Skip to content

Commit 3d087ec

Browse files
authored
Merge branch 'main' into AI-touchups
2 parents f1cb6bb + f9b6bcd commit 3d087ec

File tree

4 files changed

+65
-61
lines changed

4 files changed

+65
-61
lines changed

docs/automation-actions.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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,8 +397,9 @@ 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

403404
#### `send-http-request` :fontawesome-brands-github:
404405

docs/execution-model.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,9 @@ Triggers can be defined globally at the file level or specifically for each auto
2626

2727
#### `triggers` section
2828

29-
Use explicit triggers to enhance the control and customization of automations in gitStream, when you need to define precisely when and how automations should be triggered based on various events and actions within pull requests.
29+
The `triggers` section in gitStream gives you precise control over when automations execute. It allows you to define conditions based on pull request events using `include` and `exclude` lists to specify branch and repository patterns. These lists determine which branches or repositories trigger or bypass automation but do not affect the events initiating automations.
3030

31-
The `triggers` is section specifies when automations are executed, supporting `include` and `exclude` lists for branch and repository patterns at the file level.
32-
33-
The `on` keyword can also be used within individual automations to define specific events that trigger those automations. Add the `on` keyword under the `triggers` key in the file and/or to a specific automation to define explicit triggers.
31+
Additionally, the `on` keyword defines specific events that trigger automations. It can be added at the file level (under the `triggers` section) or within individual automations for greater customization. Multiple triggers can be stacked, meaning gitStream will execute the automation for each matching triggering event, allowing flexibility in defining automation behavior
3432

3533
| Key | Type | Description |
3634
| ----------------------------------------------------- | ----------------- | -------------------------------------------------------------- |
@@ -56,6 +54,7 @@ The table below lists supported explicit triggers, categorized into those enable
5654
| :fontawesome-brands-github: Transition from draft to ready for review | `pr_ready_for_review` | `off` |
5755
| :fontawesome-brands-github: transition from any state to closed | `pr_closed` | `off` |
5856
| :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 |
5958

6059
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.
6160
If an automation block does not have explicit triggers configured, it will be triggered according to the default (implicit) triggers.
@@ -72,7 +71,7 @@ If an automation block does not have explicit triggers configured, it will be tr
7271

7372
**Exclude/Include prioritization**
7473

75-
- 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.
7675

7776
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`
7877
```yaml+jinja
@@ -89,7 +88,7 @@ If an automation block does not have explicit triggers configured, it will be tr
8988
9089
#### Dependabot and Renovate
9190
92-
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.
9392
9493
!!! warning "Required gitStream Plugins"
9594
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)