mirror of
https://github.com/github/codeql-action.git
synced 2026-11-10 14:56:01 +00:00
Wrap --marker argument in HTML comment tags automatically
This commit is contained in:
4
.github/actions/post-comment/action.yml
vendored
4
.github/actions/post-comment/action.yml
vendored
@@ -3,8 +3,8 @@ description: "Create or update a sticky PR comment identified by a caller-provid
|
||||
inputs:
|
||||
marker:
|
||||
description: >
|
||||
Non-empty marker identifying the comment. Use a unique,
|
||||
stable HTML comment for each distinct comment.
|
||||
Non-empty plain-text identifier for the comment. Use a unique, stable value
|
||||
for each distinct comment; it is automatically wrapped in a hidden HTML comment.
|
||||
required: true
|
||||
body:
|
||||
description: "Full comment markdown."
|
||||
|
||||
4
.github/workflows/pr-checks.yml
vendored
4
.github/workflows/pr-checks.yml
vendored
@@ -295,7 +295,7 @@ jobs:
|
||||
!startsWith(github.event.pull_request.head.ref, 'update-bundle/')
|
||||
uses: ./.github/actions/post-comment
|
||||
with:
|
||||
marker: "<!-- post-comment:CHANGELOG.md -->"
|
||||
marker: "post-comment:CHANGELOG.md"
|
||||
body: |
|
||||
⚠️ `CHANGELOG.md` has been modified in this PR. Please do not modify `CHANGELOG.md` directly.
|
||||
Instead, create a change-note file in `unreleased-change-notes/`. The `CHANGELOG.md`
|
||||
@@ -312,7 +312,7 @@ jobs:
|
||||
!startsWith(github.event.pull_request.head.ref, 'update-bundle/')
|
||||
uses: ./.github/actions/post-comment
|
||||
with:
|
||||
marker: "<!-- post-comment:CHANGELOG.md -->"
|
||||
marker: "post-comment:CHANGELOG.md"
|
||||
body: |
|
||||
⚠️ `CHANGELOG.md` has been modified in this PR. Please do not modify `CHANGELOG.md` directly.
|
||||
Instead, create a change-note file in `unreleased-change-notes/`. The `CHANGELOG.md`
|
||||
|
||||
@@ -20,7 +20,7 @@ const validFlags = [
|
||||
"--body",
|
||||
"hello",
|
||||
"--marker",
|
||||
"<!-- marker -->",
|
||||
"marker",
|
||||
"--issue-id",
|
||||
"42",
|
||||
"--repository",
|
||||
@@ -48,7 +48,7 @@ describe("parseOptions", async () => {
|
||||
const options = parseOptions(validFlags);
|
||||
assert.deepEqual(options, {
|
||||
body: "hello",
|
||||
marker: "<!-- marker -->",
|
||||
marker: "marker",
|
||||
issueId: 42,
|
||||
repository: { owner: "github", repo: "codeql-action" },
|
||||
});
|
||||
@@ -136,7 +136,7 @@ describe("findExistingComment", async () => {
|
||||
client,
|
||||
{ owner: "owner", repo: "repo" },
|
||||
1,
|
||||
"<!-- marker -->",
|
||||
"marker",
|
||||
);
|
||||
assert.equal(id, 2);
|
||||
});
|
||||
@@ -147,7 +147,7 @@ describe("findExistingComment", async () => {
|
||||
client,
|
||||
{ owner: "owner", repo: "repo" },
|
||||
1,
|
||||
"<!-- marker -->",
|
||||
"marker",
|
||||
);
|
||||
assert.equal(id, undefined);
|
||||
});
|
||||
@@ -156,7 +156,7 @@ describe("findExistingComment", async () => {
|
||||
/** A baseline set of `Options`, for use in `setComment` tests. */
|
||||
const baseOptions: Options = {
|
||||
body: "hello",
|
||||
marker: "<!-- marker -->",
|
||||
marker: "marker",
|
||||
issueId: 42,
|
||||
repository: { owner: "owner", repo: "repo" },
|
||||
};
|
||||
@@ -166,16 +166,16 @@ function assertCommentContent(
|
||||
marker: string,
|
||||
body: string,
|
||||
): void {
|
||||
assert.ok(comment.body?.startsWith(marker));
|
||||
assert.ok(comment.body?.startsWith(`<!-- ${marker} -->`));
|
||||
assert.ok(comment.body?.endsWith(body));
|
||||
}
|
||||
|
||||
describe("setComment", async () => {
|
||||
await it("uses the supplied marker without affecting other comments", async () => {
|
||||
const marker = "<!-- custom-warning -->";
|
||||
const marker = "custom-warning";
|
||||
const { client, comments } = fakeClient([
|
||||
{ id: 1, body: `${baseOptions.marker}\nunrelated warning` },
|
||||
{ id: 2, body: `${marker}\nold warning` },
|
||||
{ id: 1, body: "<!-- marker -->\nunrelated warning" },
|
||||
{ id: 2, body: "<!-- custom-warning -->\nold warning" },
|
||||
]);
|
||||
const options = parseOptions(withFlag("--marker", marker));
|
||||
|
||||
@@ -185,7 +185,7 @@ describe("setComment", async () => {
|
||||
assert.equal(comments.length, 2);
|
||||
assert.deepEqual(comments[0], {
|
||||
id: 1,
|
||||
body: `${baseOptions.marker}\nunrelated warning`,
|
||||
body: "<!-- marker -->\nunrelated warning",
|
||||
});
|
||||
assert.equal(comments[1].id, 2);
|
||||
assertCommentContent(comments[1], marker, options.body);
|
||||
@@ -196,7 +196,7 @@ describe("setComment", async () => {
|
||||
// No comment has the marker before posting.
|
||||
assert.equal(comments.length, 0);
|
||||
assert.ok(
|
||||
!comments.some(({ body }) => body?.startsWith(baseOptions.marker)),
|
||||
!comments.some(({ body }) => body?.startsWith("<!-- marker -->")),
|
||||
);
|
||||
|
||||
await setComment(client, baseOptions);
|
||||
@@ -214,7 +214,7 @@ describe("setComment", async () => {
|
||||
const { client, comments } = fakeClient(originalComments);
|
||||
// Existing comments do not match the marker.
|
||||
assert.ok(
|
||||
!comments.some(({ body }) => body?.startsWith(baseOptions.marker)),
|
||||
!comments.some(({ body }) => body?.startsWith("<!-- marker -->")),
|
||||
);
|
||||
|
||||
await setComment(client, baseOptions);
|
||||
@@ -226,7 +226,7 @@ describe("setComment", async () => {
|
||||
originalComments,
|
||||
);
|
||||
const markedComments = comments.filter(({ body }) =>
|
||||
body?.startsWith(baseOptions.marker),
|
||||
body?.startsWith("<!-- marker -->"),
|
||||
);
|
||||
// Exactly one comment contains the expected marker and body.
|
||||
assert.equal(markedComments.length, 1);
|
||||
@@ -241,7 +241,7 @@ describe("setComment", async () => {
|
||||
|
||||
await it("updates the existing comment when one is found", async () => {
|
||||
const { client, comments } = fakeClient([
|
||||
{ id: 7, body: `${baseOptions.marker}\nold` },
|
||||
{ id: 7, body: "<!-- marker -->\nold" },
|
||||
]);
|
||||
|
||||
await setComment(client, baseOptions);
|
||||
@@ -254,7 +254,7 @@ describe("setComment", async () => {
|
||||
|
||||
await it("replaces a warning with the resolved state using the same marker", async () => {
|
||||
const { client, comments } = fakeClient([
|
||||
{ id: 9, body: `${baseOptions.marker}\nold` },
|
||||
{ id: 9, body: "<!-- marker -->\nold" },
|
||||
]);
|
||||
const body =
|
||||
"`CHANGELOG.md` is not modified in this PR. No changelog action is needed.";
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
/*
|
||||
Creates or updates a pull request comment identified by a marker. The marker
|
||||
is supplied via `--marker` (or the `.github/actions/post-comment` action's `marker` input)
|
||||
and must be non-empty. The marker is prepended to `--body` and used to find
|
||||
the comment on later runs.
|
||||
and must be non-empty. Supply a plain-text identifier; the CLI wraps it in a
|
||||
hidden HTML comment, prepends it to `--body`, and uses it to find the comment on later runs.
|
||||
|
||||
Example:
|
||||
```sh
|
||||
GH_TOKEN=<token> npx tsx ./pr-checks/post-comment.ts \
|
||||
--body "The changelog needs updating." \
|
||||
--marker "<!-- my-bot -->" \
|
||||
--marker "my-bot" \
|
||||
--issue-id 123 \
|
||||
--repository github/codeql-action
|
||||
```
|
||||
@@ -27,7 +27,7 @@ import { type ApiClient, getApiClient, resolveToken } from "./api-client";
|
||||
export interface Options {
|
||||
/** The full comment body. */
|
||||
body: string;
|
||||
/** The hidden HTML-comment marker used to find a pre-existing comment. */
|
||||
/** Plain-text identifier wrapped in a hidden HTML comment. */
|
||||
marker: string;
|
||||
/** The issue/pull request number to post/update the comment on. */
|
||||
issueId: number;
|
||||
@@ -35,6 +35,10 @@ export interface Options {
|
||||
repository: RepositoryNwo;
|
||||
}
|
||||
|
||||
function hiddenMarker(marker: string): string {
|
||||
return `<!-- ${marker} -->`;
|
||||
}
|
||||
|
||||
/** Parses CLI arguments supplied by the composite action into `Options`. */
|
||||
export function parseOptions(argv?: string[]): Options {
|
||||
const { values } = parseArgs({
|
||||
@@ -72,17 +76,18 @@ export async function findExistingComment(
|
||||
issueNumber: number,
|
||||
marker: string,
|
||||
): Promise<number | undefined> {
|
||||
const formattedMarker = hiddenMarker(marker);
|
||||
const comments = await client.paginate(client.rest.issues.listComments, {
|
||||
...repository,
|
||||
issue_number: issueNumber,
|
||||
per_page: 100,
|
||||
});
|
||||
const markedComments = comments.filter((comment) =>
|
||||
comment.body?.startsWith(marker),
|
||||
comment.body?.startsWith(formattedMarker),
|
||||
);
|
||||
if (markedComments.length > 1) {
|
||||
console.warn(
|
||||
`Found ${markedComments.length} comments with marker "${marker}". ` +
|
||||
`Found ${markedComments.length} comments with marker "${formattedMarker}". ` +
|
||||
"Updating the first one and leaving the others unchanged." +
|
||||
"Use a unique marker for each distinct managed comment to avoid this situation.",
|
||||
);
|
||||
@@ -98,7 +103,7 @@ export async function setComment(
|
||||
options: Options,
|
||||
): Promise<void> {
|
||||
const { issueId, marker, repository } = options;
|
||||
const body = `${marker}\n${options.body}`;
|
||||
const body = `${hiddenMarker(marker)}\n${options.body}`;
|
||||
|
||||
const existingCommentId = await findExistingComment(
|
||||
client,
|
||||
|
||||
Reference in New Issue
Block a user