From 418d9eb4e79b6ba0ec64538e261b3e87c946f8ba Mon Sep 17 00:00:00 2001 From: Zach Himsel Date: Thu, 8 Jun 2023 12:21:56 -0400 Subject: [PATCH] Support running multiple instances without collision (#54) * Support running multiple instances without collision This uses a combination of three Github-set env vars that, together, are guaranteed to be unique within the scope of a repo and all its workflows: - GITHUB_WORKFLOW: the name of the workflow (or file path, if no name is given) - GITHUB_JOB: the ID of the job - GITHUB_ACTION: the ID of the step (or a formatted name of the repo where the action resides, i.e. `__mheap_github-action-required-labels`) Without this, running multiple instances of this action with comments enabled would result in them clobbering each others' comments. --------- Co-authored-by: Michael Heap --- README.md | 6 ++++++ index.js | 12 +++++++++++- index.test.js | 4 +++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0939b60..1dabaa6 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,12 @@ The following tokens are available for use in custom messages: labels: "community-reviewed, team-reviewed, codeowner-reviewed" ``` +### Preventing comment collisions + +This action uses a combination of the workflow name/path, job ID, and step ID to add an invisible "match token" to the beginning of any comments it creates. That way, it can later know which comments it owns when modifying them, while supporting multiple "instances" of this action to be run at the same time within a repo. + +However, note that if any of those three identifiers change, any "in flight" comments on open PRs may be orphaned (since the final match token will have changed between runs). If you rename any of those identifiers, you will have to delete any orphaned comments manually. + ### Controlling failure You can set `exit_type` to success then inspect `outputs.status` to see if the action passed or failed. This is useful when you want to perform additional actions if a label is not present, but not fail the entire build. diff --git a/index.js b/index.js index 362569d..8326ff8 100644 --- a/index.js +++ b/index.js @@ -1,8 +1,18 @@ const core = require("@actions/core"); const github = require("@actions/github"); -const matchToken = `\n`; +let matchToken; async function action() { + // Use a guaranteed-unique (but persistent) string to match "our" comment + // https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables + const matchTokenId = [ + process.env.GITHUB_WORKFLOW, + process.env.GITHUB_JOB, + process.env.GITHUB_ACTION, + ].join("/"); + + matchToken = `\n`; + try { const token = core.getInput("token", { required: true }); const octokit = github.getOctokit(token); diff --git a/index.test.js b/index.test.js index c9342e4..91c6e2a 100644 --- a/index.test.js +++ b/index.test.js @@ -6,7 +6,8 @@ const mockedEnv = require("mocked-env"); const nock = require("nock"); nock.disableNetConnect(); -const matchToken = `\n`; +// note: these need to match the mocked env vars below +const matchToken = `\n`; describe("Required Labels", () => { let restore; @@ -14,6 +15,7 @@ describe("Required Labels", () => { beforeEach(() => { restore = mockedEnv({ GITHUB_WORKFLOW: "demo-workflow", + GITHUB_JOB: "demo-job", GITHUB_ACTION: "required-labels", GITHUB_ACTOR: "mheap", GITHUB_REPOSITORY: "mheap/missing-repo",