Skip to content

Commit 7c9e705

Browse files
authored
Merge branch 'main' into trigggers-refinement
2 parents 50d47d7 + 6cfb5be commit 7c9e705

File tree

5 files changed

+71
-61
lines changed

5 files changed

+71
-61
lines changed

docs/automation-actions.md

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ For all other actions, gitStream executes the actions in the order they are list
3232
- [`request-changes`](#request-changes) :fontawesome-brands-github: :fontawesome-brands-gitlab:
3333
- [`require-reviewers`](#require-reviewers) :fontawesome-brands-github:
3434
- [`run-github-workflow`](#run-github-workflow) :fontawesome-brands-github:
35-
- [`send-http-request`](#send-http-request) :fontawesome-solid-flask: :fontawesome-brands-github: :fontawesome-brands-gitlab:
36-
- [`send-slack-message`](#send-slack-message) :fontawesome-solid-flask: :fontawesome-brands-github:
35+
- [`send-http-request`](#send-http-request) :fontawesome-brands-github:
36+
- [`send-slack-message`](#send-slack-message) :fontawesome-brands-github:
3737
- [`set-required-approvals`](#set-required-approvals) :fontawesome-brands-github:
3838
- [`update-description`](#update-description) :fontawesome-brands-github:
3939
- [`update-title`](#update-title) :fontawesome-brands-github:
@@ -365,13 +365,13 @@ This action, once triggered, will start a workflow dispatch automation with the
365365

366366
| Args | Usage | Type | Description |
367367
| ----------------------- | -------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
368-
| `workflow` | Required | String | The ID or name of the workflow dispatch. |
369-
| `owner` | Optional | String | By default, the value of `repo.owner` context variable. The account owner of the repository. Case insensitive. |
370-
| `repo` | Optional | String | By default, the value of `repo.name` context variable. The name of the repository without the `.git` extension. Case insensitive. |
371-
| `ref` | Optional | String | By default, the value of `branch.name` context variable. The account owner of the repository. Case insensitive. |
368+
| `workflow` | Required | String | The ID or the path of the workflow dispatch. |
369+
| `owner` | Optional | String | By default, the value of `repo.owner` context variable. The account owner of the repository. Case insensitive. |
370+
| `repo` | Optional | String | By default, the value of `repo.name` context variable. The name of the repository without the `.git` extension. Case insensitive. |
371+
| `ref` | Optional | String | By default, the value of `branch.name` context variable. The branch name. Case sensitive. |
372372
| `inputs` | Optional | String | By default, an empty list. Key-Value list with the arguments to provide to the workflow |
373373
| `check_name` | Optional | String | When added, after the workflow is complete, add the check name to the checks list on GitHub |
374-
| `stop_ongoing_workflow` | Optional | Bool | By default, `false`. In case the workflow already runs on the branch, if `true`: cancel the ongoing workflow before running the newly dispatched workflow. If `false`: wait for the old workflow to finish before dispatching a new one |
374+
| `stop_ongoing_workflow` | Optional | Bool | By default, `false`. If the workflow already runs on the branch, When `true`: cancel the ongoing workflow before running the newly dispatched workflow. When `false`: wait for the old workflow to finish before dispatching a new one |
375375

376376
</div>
377377

@@ -397,10 +397,11 @@ has:
397397

398398
!!! attention
399399

400-
* This action will invoke the run of a workflow dispatch; thus, it might result in significant GitHub action minutes charge.
400+
* This action will invoke the run of a workflow dispatch; thus, it might result in a significant GitHub action minutes charge.
401401
* We encourage you to use this action with [custom triggers](./execution-model.md#explicit-triggers)
402+
* To manually test the webhook dispatch, please [run the workflow](https://docs.github.com/en/actions/managing-workflow-runs-and-deployments/managing-workflow-runs/manually-running-a-workflow#running-a-workflow){:target="_blank"} before using it with gitStream.
402403

403-
#### `send-http-request` :fontawesome-solid-flask: :fontawesome-brands-github: :fontawesome-brands-gitlab:
404+
#### `send-http-request` :fontawesome-brands-github:
404405

405406
The action, once triggered, sends an HTTP request to the specified URL
406407
<div class="filter-details" markdown=1>
@@ -430,7 +431,7 @@ automations:
430431
body: '{"text": "Hello, world!"}'
431432
```
432433

433-
#### `send-slack-message` :fontawesome-solid-flask: :fontawesome-brands-github:
434+
#### `send-slack-message` :fontawesome-brands-github:
434435

435436
The action, once triggered, sends a webhook with a message content to a Slack app.
436437
To use this action, [create a Slack app](https://api.slack.com/messaging/webhooks#getting_started) with Incoming Webhooks enabled. gitStream uses the webhook URL to send the message.

docs/downloads/automation-library/integrations/jira/jira_update_field.cm

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,7 @@ automations:
2828
has:
2929
jira_ticket_in_title: {{ pr.title | includes(regex=r/\b[A-Za-z]+-\d+\b/) }}
3030
jira_ticket_in_branch: {{ branch.name | includes(regex=r/\b[A-Za-z]+-\d+\b/) }}
31+
32+
tickets:
33+
- {{branch.name | capture(regex=r/\b[A-Za-z]+-\d+\b/)}}
34+
- {{pr.title | capture(regex=r/\b[A-Za-z]+-\d+\b/)}}

docs/execution-model.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ The table below lists supported explicit triggers, categorized into those enable
5454
| :fontawesome-brands-github: Transition from draft to ready for review | `pr_ready_for_review` | `off` |
5555
| :fontawesome-brands-github: transition from any state to closed | `pr_closed` | `off` |
5656
| :fontawesome-brands-github: transition from closed to open | `pr_reopened` | `off` |
57+
| :fontawesome-brands-github: Transition from any state to approved | `pr_approved` | If there is an automation with one of the actions: `require-reviewers`, `set-required-approvals` or `merge`, or uses `pr.approvals` context variable |
5758

5859
Explicit triggers are set independently per each automation block and can be configured at the file level, specific to each automation separately or in combination. If triggers are listed at the file level **and** specific automation, the automation will be triggered according to both triggers.
5960
If an automation block does not have explicit triggers configured, it will be triggered according to the default (implicit) triggers.
@@ -70,7 +71,7 @@ If an automation block does not have explicit triggers configured, it will be tr
7071

7172
**Exclude/Include prioritization**
7273

73-
- Exclude overrides the include option. Thus, a repo will be excluded when a it matches both the include and exclude lists.
74+
- Exclude overrides the include option. Thus, a repo will be excluded when it matches the include and exclude lists.
7475

7576
In the following example, the automations in the file will be triggered for all repositories that contain the string `feature`, except for the repository `my_feature`
7677
```yaml+jinja
@@ -87,7 +88,7 @@ If an automation block does not have explicit triggers configured, it will be tr
8788
8889
#### Dependabot and Renovate
8990
90-
For example, you can have your normal automations that help developers with their PRs and a separate automation that automates Dependabot or Renovate version bumps. Both automations serve distinctly different purposes: the first helps your developers streamline their PRs, while the other reduces developers' toil by auto-approving version bumps. You will not want to trigger gitStream for Dependabot or Renovate unnecessarily, so you can configure the triggers to exclude the branch where Dependabot or Renovate PRs are created.
91+
For example, you can have your normal automations that help developers with their PRs and a separate automation that automates Dependabot or Renovate version bumps. Both automations serve distinctly different purposes: the first helps your developers streamline their PRs, while the other reduces developers' toil by auto-approving version bumps. You will not want to unnecessarily trigger gitStream for Dependabot or Renovate, so you can configure the triggers to exclude the branch where Dependabot or Renovate PRs are created.
9192
9293
!!! warning "Required gitStream Plugins"
9394
This example requires you to install the [`extractDependabotVersionBump`](/filter-function-plugins/#extractdependabotversionbump) and [`compareSemver`](/filter-function-plugins/#comparesemver) plugins.

docs/filter-functions.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ The following functions are supported in addition to the built-in functions prov
2020

2121
| Function | Input | Args | Output |
2222
| -------------------------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------- | ---------------------- |
23-
| [`capture`](#capture)<br />Find and return the first occurrence of a regex in the input string | String | `regex` | [Objects] |
23+
| [`capture`](#capture)<br />Find and return the first occurrence of a regex in the input string | String | `regex` | String |
2424
| [`difference`](#difference)<br />Given two lists, keep only items that are in the 1st list but not in the 2nd. | [Objects] | `list` | [Objects] |
2525
| [`every`](#every)<br />Checks whether all element in the list are `true` | [Bool] | - | Bool |
2626
| [`filter`](#filter)<br />Reduce list of items into a list of same items that match the specified term | [String]<br />[Object] | `regex`, `term`, `list`, `attr` | [String]<br />[Object] |
@@ -94,7 +94,7 @@ Extract the first match of the regex in the input string. If no match is found,
9494
| -------- | ---------|-----------|------------------------------------------------ |
9595
| - | Input | String | The string to find the match in |
9696
| `regex` | Input | String | Search term to match with the input string |
97-
| - | Output | Bool | The first substring that match the provided regex |
97+
| - | Output | String | The first substring that matches the provided regex |
9898

9999
</div>
100100

plugins/filters/askAI/index.js

Lines changed: 51 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
* @returns {Object} Returns the response from the AI model.
99
* @example {{ branch | generateDescription(pr, repo, source) }}
1010
* @license MIT
11-
**/
11+
* */
1212

13-
const lockFiles = [
13+
const MAX_TOKENS = 4096;
14+
const OPEN_AI_ENDPOINT = 'https://api.openai.com/v1/chat/completions';
15+
const LOCK_FILES = [
1416
'package-lock.json',
1517
'yarn.lock',
1618
'npm-shrinkwrap.json',
@@ -36,8 +38,7 @@ const lockFiles = [
3638
'flake.lock',
3739
'pnpm-lock.yaml'
3840
];
39-
40-
const excludeExpressionsList = [
41+
const EXCLUDE_EXPRESSIONS_LIST = [
4142
'.*\\.(ini|csv|xls|xlsx|xlr|doc|docx|txt|pps|ppt|pptx|dot|dotx|log|tar|rtf|dat|ipynb|po|profile|object|obj|dxf|twb|bcsymbolmap|tfstate|pdf|rbi|pem|crt|svg|png|jpeg|jpg|ttf)$',
4243
'.*(package-lock|packages\\.lock|package)\\.json$',
4344
'.*(yarn|gemfile|podfile|cargo|composer|pipfile|gopkg)\\.lock$',
@@ -47,55 +48,58 @@ const excludeExpressionsList = [
4748
'.*public/assets/.*\\.js',
4849
'.*ci\\.yml$'
4950
];
51+
const IGNORE_FILES_REGEX_LIST = [
52+
...LOCK_FILES.map(f => f.replace('.', '\\.')),
53+
...EXCLUDE_EXPRESSIONS_LIST
54+
];
55+
const EXCLUDE_PATTERN = new RegExp(IGNORE_FILES_REGEX_LIST.join('|'));
5056

51-
const ignoreFilesRegexList = lockFiles
52-
.map(file => file.replace('.', '\\.'))
53-
.concat(excludeExpressionsList);
54-
const excludePattern = new RegExp(ignoreFilesRegexList.join('|'));
55-
56-
const filterExcludeFiles = file => {
57-
return !excludePattern.test(file) || (file.diff?.split(' ').length ?? 0) < 800;
58-
};
59-
60-
const buildArrayContext = context => {
61-
return context.filter(element => {
62-
if (typeof element !== 'object') {
63-
return true;
64-
}
65-
66-
return context.filter(filterExcludeFiles);
67-
});
57+
/**
58+
* @description Check if a file should be excluded from the context like "package-lock.json"
59+
* @param {*} fileObject
60+
* @returns returns true if the file should be excluded
61+
*/
62+
const shouldExcludeFile = fileObject => {
63+
const shouldExludeByName = EXCLUDE_PATTERN.test(fileObject.original_file);
64+
const shouldExludeBySize = (fileObject.diff?.split(' ').length ?? 0) > 1000;
65+
66+
return shouldExludeByName || shouldExludeBySize;
6867
};
6968

70-
const buildSourceContext = context => {
71-
return context.diff.files.filter(filterExcludeFiles);
69+
/**
70+
* @description Check if a file should be included in the context
71+
* @param {*} fileObject
72+
* @returns returns true if the file should be included
73+
*/
74+
const shouldIncludeFile = fileObject => {
75+
return !shouldExcludeFile(fileObject);
7276
};
7377

7478
const buildContextForGPT = context => {
7579
if (Array.isArray(context)) {
76-
return buildArrayContext(context);
80+
return context.filter(element =>
81+
typeof element !== 'object' ? true : context.filter(shouldIncludeFile)
82+
);
7783
}
7884

7985
if (context?.diff?.files) {
80-
return buildSourceContext(context);
86+
const files = context.diff.files.filter(shouldIncludeFile);
87+
return files;
8188
}
8289

8390
return context;
8491
};
8592

86-
const askAI = async (context, role = '', prompt, token, callback) => {
87-
const cacheKey = `${__filename}${role}${prompt}`;
88-
89-
if (process.env[cacheKey]) {
90-
return callback(null, process.env[cacheKey]);
91-
}
92-
93-
const maxTokens = 4096;
94-
const endpoint = 'https://api.openai.com/v1/chat/completions';
95-
93+
const askAI = async (context, role, prompt, token, callback) => {
9694
const formattedContext = buildContextForGPT(context);
9795

98-
const response = await fetch(endpoint, {
96+
if (!formattedContext?.length) {
97+
const message = `There are no context files to analyze.\nAll ${context?.diff?.files?.length} files were excluded by pattern or size.`;
98+
console.log(message);
99+
return callback(null, message);
100+
}
101+
102+
const response = await fetch(OPEN_AI_ENDPOINT, {
99103
method: 'POST',
100104
headers: {
101105
'Content-Type': 'application/json',
@@ -104,32 +108,32 @@ const askAI = async (context, role = '', prompt, token, callback) => {
104108
body: JSON.stringify({
105109
model: 'gpt-4o-2024-08-06',
106110
messages: [
107-
...(role ?
108-
[
109-
{
110-
role: 'system',
111-
content: `You are a ${role}. Answer only to the request, without any introductory or conclusion text.`
112-
}]
113-
: []),
111+
{
112+
role: 'system',
113+
content: `You are a ${role}. Answer only to the request, without any introductory or conclusion text.`
114+
},
114115
{
115116
role: 'user',
116117
content: JSON.stringify(formattedContext)
117118
},
118119
{ role: 'user', content: prompt }
119120
],
120-
max_tokens: maxTokens
121+
max_tokens: MAX_TOKENS
121122
})
122123
});
123124

124125
const data = await response.json();
125126

127+
if (data?.error?.message) {
128+
console.error(data.error.message);
129+
return callback(null, data.error.message);
130+
}
131+
126132
const suggestion =
127133
data.choices?.[0]?.message?.content ??
128134
'context was too big for api, try with smaller context object';
129135

130-
process.env[cacheKey] = suggestion;
131-
132-
return callback(null, process.env[cacheKey]);
136+
return callback(null, suggestion);
133137
};
134138

135139
module.exports = {

0 commit comments

Comments
 (0)