Move comment branching into workflow steps

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Mario Campos
2026-10-28 15:53:36 -05:00
parent 90d1bc983c
commit ae23865548
4 changed files with 49 additions and 55 deletions

View File

@@ -5,16 +5,10 @@ inputs:
description: "Non-empty marker identifying the comment. Use a unique, stable HTML comment for each distinct comment."
required: true
body:
description: "Full comment markdown."
required: true
action-condition:
description: "The business condition ('true' or 'false') that selects which action to perform."
required: true
action-if-true:
description: "Action to perform when action-condition is 'true'. One of: none, insert, upsert, delete."
required: true
action-if-false:
description: "Action to perform when action-condition is 'false'. One of: none, insert, upsert, delete."
description: "Full comment markdown. Not needed when deleting a comment."
required: false
action:
description: "Action to perform. One of: none, insert, upsert, delete."
required: true
issue-id:
description: "The issue or pull request number to post/update/delete the comment on. Defaults to the current pull request if not provided."
@@ -32,15 +26,11 @@ runs:
MARKER: ${{ inputs.marker }}
GH_TOKEN: ${{ inputs.token }}
ISSUE_ID: ${{ inputs.issue-id || github.event.pull_request.number }}
ACTION_CONDITION: ${{ inputs.action-condition }}
ACTION_IF_TRUE: ${{ inputs.action-if-true }}
ACTION_IF_FALSE: ${{ inputs.action-if-false }}
ACTION: ${{ inputs.action }}
run: |
npx tsx ./pr-checks/post-comment.ts \
--body "$BODY" \
--marker "$MARKER" \
--action-condition "$ACTION_CONDITION" \
--action-if-true "$ACTION_IF_TRUE" \
--action-if-false "$ACTION_IF_FALSE" \
--action "$ACTION" \
--issue-id "$ISSUE_ID" \
--repository "$GITHUB_REPOSITORY"

View File

@@ -292,6 +292,7 @@ jobs:
# Release, backport, mergeback, and bundle-update PRs deliberately modify CHANGELOG.md,
# so skip comment management entirely for these automation flows.
if: >-
needs.other-checks.outputs.changelog-changed == 'true' &&
!startsWith(github.event.pull_request.head.ref, 'update-v') &&
!startsWith(github.event.pull_request.head.ref, 'backport-v') &&
!startsWith(github.event.pull_request.head.ref, 'mergeback/') &&
@@ -304,7 +305,19 @@ jobs:
Instead, create a change-note file in `unreleased-change-notes/`. The `CHANGELOG.md`
file will be automatically generated from those change-notes.
See [`unreleased-change-notes/README.md`](https://github.com/github/codeql-action/blob/main/unreleased-change-notes/README.md) for more information.
action-condition: ${{ needs.other-checks.outputs.changelog-changed }}
action-if-true: upsert
action-if-false: delete
action: upsert
token: ${{ secrets.GITHUB_TOKEN }}
- name: Delete the warning about modifying CHANGELOG.md
id: delete-changelog-warning
if: >-
needs.other-checks.outputs.changelog-changed != 'true' &&
!startsWith(github.event.pull_request.head.ref, 'update-v') &&
!startsWith(github.event.pull_request.head.ref, 'backport-v') &&
!startsWith(github.event.pull_request.head.ref, 'mergeback/') &&
!startsWith(github.event.pull_request.head.ref, 'update-bundle/')
uses: ./.github/actions/post-comment
with:
marker: "<!-- post-comment:CHANGELOG.md -->"
action: delete
token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -22,12 +22,8 @@ const validFlags = [
"hello",
"--marker",
"<!-- marker -->",
"--action-condition",
"true",
"--action-if-true",
"--action",
"insert",
"--action-if-false",
"delete",
"--issue-id",
"42",
"--repository",
@@ -56,17 +52,20 @@ describe("parseOptions", async () => {
assert.deepEqual(options, {
body: "hello",
marker: "<!-- marker -->",
actionCondition: true,
actionIfTrue: "insert",
actionIfFalse: "delete",
action: "insert",
issueId: 42,
repository: { owner: "github", repo: "codeql-action" },
});
});
await it("parses action-condition=false", () => {
const options = parseOptions(withFlag("--action-condition", "false"));
assert.equal(options.actionCondition, false);
await it("parses a delete action without a body", () => {
const options = parseOptions([
...withoutFlag("--body"),
"--action",
"delete",
]);
assert.equal(options.action, "delete");
assert.equal(options.body, "");
});
await it("rejects a missing --marker", () => {
@@ -181,9 +180,7 @@ describe("findExistingComment", async () => {
const baseOptions: Options = {
body: "hello",
marker: "<!-- marker -->",
actionCondition: true,
actionIfTrue: "insert",
actionIfFalse: "delete",
action: "insert",
issueId: 42,
repository: { owner: "owner", repo: "repo" },
};
@@ -281,9 +278,14 @@ describe("performAction", async () => {
const { client, calls } = fakeClient([
{ id: 9, body: "<!-- marker -->\nold" },
]);
await performAction(client, "delete", baseOptions);
const options = parseOptions([
...withoutFlag("--body"),
"--action",
"delete",
]);
await performAction(client, options.action, options);
assert.deepEqual(calls.deleteComment, [
{ owner: "owner", repo: "repo", comment_id: 9 },
{ owner: "github", repo: "codeql-action", comment_id: 9 },
]);
});
});

View File

@@ -31,12 +31,8 @@ export interface Options {
body: string;
/** The hidden HTML-comment marker used to find a pre-existing comment. */
marker: string;
/** The condition that selects which action to perform. */
actionCondition: boolean;
/** The action to perform when `actionCondition` is `true`. */
actionIfTrue: Action;
/** The action to perform when `actionCondition` is `false`. */
actionIfFalse: Action;
/** The action to perform. */
action: Action;
/** The issue/pull request number to post/update/delete the comment on. */
issueId: number;
/** The repository to operate on. */
@@ -48,11 +44,9 @@ export function parseOptions(argv?: string[]): Options {
const { values } = parseArgs({
args: argv,
options: {
body: { type: "string" },
body: { type: "string", default: "" },
marker: { type: "string" },
"action-condition": { type: "string" },
"action-if-true": { type: "string" },
"action-if-false": { type: "string" },
action: { type: "string" },
"issue-id": { type: "string" },
repository: { type: "string" },
},
@@ -63,11 +57,9 @@ export function parseOptions(argv?: string[]): Options {
const [owner, repo] = values.repository!.split("/");
return {
body: values.body!,
body: values.body,
marker: values.marker!,
actionCondition: values["action-condition"] === "true",
actionIfTrue: values["action-if-true"] as Action,
actionIfFalse: values["action-if-false"] as Action,
action: values.action as Action,
issueId: Number(values["issue-id"]),
repository: { owner, repo },
};
@@ -102,7 +94,7 @@ export async function findExistingComment(
}
/**
* Performs the resolved `action` against a (possibly pre-existing) marked comment, using
* Performs the supplied `action` against a (possibly pre-existing) marked comment, using
* `client` to talk to the GitHub API. This is the core dispatch logic of this script, extracted
* from `main` so it can be unit-tested with an injected (fake) `client`.
*/
@@ -169,15 +161,12 @@ export async function performAction(
async function main(): Promise<number> {
const options = parseOptions();
const action = options.actionCondition
? options.actionIfTrue
: options.actionIfFalse;
console.info(`Resolved action: ${action}`);
console.info(`Action: ${options.action}`);
const token = resolveToken(process.env);
const client = getApiClient(token);
await performAction(client, action, options);
await performAction(client, options.action, options);
return 0;
}