diff --git a/docs/automations/automation-library.md b/docs/automations/automation-library.md index 3cf953af..e2cbf052 100644 --- a/docs/automations/automation-library.md +++ b/docs/automations/automation-library.md @@ -32,6 +32,7 @@ This library of gitStream examples is meant to serve as a starting point for you * [Label missing project tracker](label-missing-project-tracker/README.md) - Flag PRs that are missing a reference to an associated project tracking resource. * [Automatic project tracking links](standard/link-issue-tracker/README.md) - Automatically post PR comments that link to the associated project tracking resource (Jira, Shortcut, Azure Boards, and more). * [Summarize PR contents by language](standard/summarize-language-changes/README.md) - Post a comment that breaks down code changes by the programming languages contained in the PR. +* [PR Checklist](pr-checklist-general/README.md) - Post a comment with a checklist giving more context about the PR to reviewers ## Improve PR Quality ### Merge Routing diff --git a/docs/automations/pr-checklist-general/README.md b/docs/automations/pr-checklist-general/README.md new file mode 100644 index 00000000..ae7733f3 --- /dev/null +++ b/docs/automations/pr-checklist-general/README.md @@ -0,0 +1,39 @@ +--- +title: Automation - PR Checklist General +description: Automatically evaluate PRs against code requirement checklists. +--- +# PR Checklist General + + +Automatically evaluate PRs against code requirement checklists. + +
+![PR Checklist General](/automations/standard/pr-checklist-general/pr-checklist-general.png) +
+
+!!! info "Configuration Description" + There are no conditions for this action - if included as presented in the demo, it's run every time. + + Automation Actions: + + * Post a comment containing a checklist with each completed item checked off. + +
+
+!!! example "PR Checklist General" + ```yaml+jinja + --8<-- "docs/downloads/automation-library/pr_checklist_general.cm" + ``` +
+ + [:octicons-download-24: Download this example as a CM file.](/downloads/automation-library/pr_checklist_general.cm){ .md-button } + +
+
+ + +## Additional Resources + +--8<-- "docs/snippets/general.md" + +--8<-- "docs/snippets/automation-footer.md" diff --git a/docs/automations/pr-checklist-general/pr-checklist-general.png b/docs/automations/pr-checklist-general/pr-checklist-general.png new file mode 100644 index 00000000..f7d63f68 Binary files /dev/null and b/docs/automations/pr-checklist-general/pr-checklist-general.png differ diff --git a/docs/downloads/automation-library/pr_checklist_general.cm b/docs/downloads/automation-library/pr_checklist_general.cm new file mode 100644 index 00000000..50ddeb43 --- /dev/null +++ b/docs/downloads/automation-library/pr_checklist_general.cm @@ -0,0 +1,13 @@ +# -*- mode: yaml -*- + +manifest: + version: 1.0 + +automations: + checklist: + if: + - true + run: + - action: add-comment@v1 + args: + comment: {{ "" | checklist(branch, files, pr, repo, env, source) }} diff --git a/docs/filter-function-plugins.md b/docs/filter-function-plugins.md index e971e029..adfccced 100644 --- a/docs/filter-function-plugins.md +++ b/docs/filter-function-plugins.md @@ -6,6 +6,8 @@ description: Implement custom gitStream filter functions with JavaScript. JavaScript plugins that enable custom filter functions for gitStream. To learn how to use these examples, read our [guide on how to use gitStream plugins](/plugins). +--8<-- "plugins/filters/checklist/README.md" + --8<-- "plugins/filters/compareMultiSemver/README.md" --8<-- "plugins/filters/compareSemver/README.md" diff --git a/plugins/filters/checklist/LICENSE b/plugins/filters/checklist/LICENSE new file mode 100644 index 00000000..3b6f147e --- /dev/null +++ b/plugins/filters/checklist/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 LinearB + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/plugins/filters/checklist/README.md b/plugins/filters/checklist/README.md new file mode 100644 index 00000000..dfb48260 --- /dev/null +++ b/plugins/filters/checklist/README.md @@ -0,0 +1,26 @@ +--8<-- "plugins/filters/checklist/reference.md" + +With this plugin, you can easily customize the checklist using the object in the JavaScript code. To add a new check to the list, just add a new object with a descriptive `title` for your own benefit, a `label` that'll get posted in the comment, and the `condition` that, if true, would cause the entry in the checklist to be checked off. + +??? note "Plugin Code: checklist" + ```javascript + --8<-- "plugins/filters/checklist/index.js" + ``` +
+ + +
+ + +??? example "gitStream CM Example: checklist" + ```yaml+jinja + --8<-- "docs/downloads/automation-library/pr_checklist_general.cm" + ``` +
+ + +
+ +[Download Source Code](https://github.com/linear-b/gitstream/tree/main/plugins/filters/checklist) + + diff --git a/plugins/filters/checklist/index.js b/plugins/filters/checklist/index.js new file mode 100644 index 00000000..3dc4d23b --- /dev/null +++ b/plugins/filters/checklist/index.js @@ -0,0 +1,76 @@ +/** + * @module checklist + * @description Automatically check PRs against a checklist of conditions. + * This is useful if you want to ensure that PRs meet certain criteria before they can be merged. + * @param {string} Input - A blank string (no input variable is required) + * @param {object} branch - The branch context variable. + * @param {object} files - The files context variable. + * @param {object} pr - The pr context variable. + * @param {object} repo - The repo context variable. + * @param {object} env - The env context variable. + * @param {object} source - The source context variable. + * @returns {string} Returns a formatted GitHub comment with a checklist of conditions that the PR meets. + * @example + * - action: add-comment@v1 + args: + comment: {{ "" | checklist(branch, files, pr, repo, env, source) }} + * @license MIT +**/ + +const checklistFilter = async (empty, branch, files, pr, repo, env, source, callback) => { // made sync temporarily + + const checks = [ + { + title: "low-risk", + label: "The PR is a low-risk change", + // our sample definition of a low-risk change is a docs-only PR from designated docs writers + condition: files.every(file => /docs\//.test(file)) && pr.author_teams.includes("tech-writers") + }, + { + title: "has-jira", + label: "The PR has a Jira reference in the title", + condition: /\b[A-Za-z]+-\d+\b/.test(pr.title) + }, + { + title: "updates-tests", + label: "The PR includes updates to tests", + condition: files.some(file => /[^a-zA-Z0-9](spec|test|tests)[^a-zA-Z0-9]/.test(file)) + }, + { + title: "includes-docs", + label: "The PR includes changes to the documentation", + condition: files.some(file => /docs\//.test(file)) + }, + { + title: "first-time", + label: "The PR author is a first-time contributor", + condition: repo.author_age < 1 && repo.age > 0 // if the PR author made their first contirbution on the current day + }, + { + title: "requires-opsec", + label: "The PR doesn't expose any secrets", + condition: source.diff.files + .map(file => file.new_content) + .every(file_content => + [ + "MY_SECRET_ENVIRONMENT_VARIABLE" + ].every(env_var => !file_content.includes(env_var)) + // nothing added to any file during this comment contains any of the secret environment variables in this array + ) + } + ]; + + const comment = await Promise.resolve(checks + .map(check => `- [${check.condition ? "x" : " "}] ${check.label}`) + .join("\n")); + + return callback( + null, + JSON.stringify(comment) + ); +}; + +module.exports = { + async: true, + filter: checklistFilter +} diff --git a/plugins/filters/checklist/reference.md b/plugins/filters/checklist/reference.md new file mode 100644 index 00000000..9c9f85a7 --- /dev/null +++ b/plugins/filters/checklist/reference.md @@ -0,0 +1,25 @@ + + +## checklist +Automatically check PRs against a checklist of conditions. +This is useful if you want to ensure that PRs meet certain criteria before they can be merged. + +**Returns**: string - Returns a formatted GitHub comment with a checklist of conditions that the PR meets. +**License**: MIT + +| Param | Type | Description | +| --- | --- | --- | +| Input | string | A blank string (no input variable is required) | +| branch | object | The branch context variable. | +| files | object | The files context variable. | +| pr | object | The pr context variable. | +| repo | object | The repo context variable. | +| env | object | The env context variable. | +| source | object | The source context variable. | + +**Example** +```js +- action: add-comment@v1 + args: + comment: {{ "" | checklist(branch, files, pr, repo, env, source) }} +```