Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 32 additions & 9 deletions action/dist/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion action/dist/index.js.map

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion action/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"type": "module",
"main": "src/index.ts",
"scripts": {
"build": "npx rollup --config rollup.config.ts --configPlugin @rollup/plugin-typescript"
"build": "npx rollup --config rollup.config.ts --configPlugin @rollup/plugin-typescript",
"test": "node --test \"src/**/*.test.ts\""
},
"devDependencies": {
"@octokit/tsconfig": "^4.0.0",
Expand Down
35 changes: 35 additions & 0 deletions action/src/comment.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import assert from "node:assert/strict";
import { describe, it } from "node:test";

import { decideCommentAction } from "./comment.ts";

const successTable =
'<table><tbody><tr><td><a href="https://example.test/runs/1">✅success</a></td></tr></tbody></table>';
const warningTable =
'<table><tbody><tr><td><a href="https://example.test/runs/1">⚠️warning</a></td></tr></tbody></table>';

describe("decideCommentAction", () => {
it("creates a comment when the bot has not commented yet", () => {
assert.deepEqual(decideCommentAction(successTable, undefined), { kind: "create" });
});

it("replaces the previous comment when the new table has a warning", () => {
const previous = { id: 7, body: successTable };
assert.deepEqual(decideCommentAction(warningTable, previous), { kind: "replace", previous });
});

it("replaces the previous comment when the previous table had a warning", () => {
const previous = { id: 7, body: warningTable };
assert.deepEqual(decideCommentAction(successTable, previous), { kind: "replace", previous });
});

it("updates the previous comment in place when neither table has a warning", () => {
const previous = { id: 7, body: successTable };
assert.deepEqual(decideCommentAction(successTable, previous), { kind: "update", previous });
});

it("treats a previous comment without a body as having no warning", () => {
const previous: { id: number; body?: string } = { id: 7 };
assert.deepEqual(decideCommentAction(successTable, previous), { kind: "update", previous });
});
});
24 changes: 24 additions & 0 deletions action/src/comment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export interface CommentLike {
readonly body?: string | undefined;
}

export type CommentAction<T extends CommentLike> =
| { kind: "create" }
| { kind: "replace"; previous: T }
| { kind: "update"; previous: T };

// Only a warning justifies notifying reviewers with a fresh comment (and
// marking the old one outdated). Otherwise the previous comment is edited in
// place so its links point at the latest run without a new notification.
export function decideCommentAction<T extends CommentLike>(
newBody: string,
previous: T | undefined,
): CommentAction<T> {
if (previous === undefined) return { kind: "create" };
if (hasWarning(newBody) || hasWarning(previous.body ?? "")) return { kind: "replace", previous };
return { kind: "update", previous };
}

function hasWarning(body: string): boolean {
return body.includes("warning");
}
29 changes: 20 additions & 9 deletions action/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Octokit } from "@octokit/rest";
import { graphql } from "@octokit/graphql";

import { decideCommentAction } from "./comment.ts";

if (!process.env.GITHUB_REF?.startsWith("refs/pull/")) {
console.log("not a pull request, exiting.");
process.exit(0);
Expand Down Expand Up @@ -213,7 +215,7 @@ const body = generateTable(rows);
console.log("body is", body);

if (body) {
console.log("outdates previous comments");
console.log("checking previous comments");
const { data: comments } = await octokit.issues.listComments({
owner,
repo,
Expand All @@ -234,23 +236,32 @@ if (body) {
.filter((comment) => comment.user?.login === "cppwarningnotifier[bot]")
.toSorted((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime());

if (sortedComments.length > 0) {
const latestComment = sortedComments[sortedComments.length - 1];
const action = decideCommentAction(body, sortedComments.at(-1));

if (body.includes("warning") || latestComment.body?.includes("warning")) {
switch (action.kind) {
case "create":
await postComment();
break;
case "replace":
await gql(
`mutation MinimizeComment($id: ID!) {
minimizeComment(input: { subjectId: $id, classifier: OUTDATED }) {
clientMutationId
}
}`,
{ id: latestComment.node_id },
{ id: action.previous.node_id },
);

await postComment();
}
} else {
await postComment();
break;
case "update":
console.log("updating links in the previous comment");
await octokit.issues.updateComment({
owner,
repo,
comment_id: action.previous.id,
body,
});
break;
}
}

Expand Down
3 changes: 2 additions & 1 deletion action/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"extends": "@octokit/tsconfig",
"compilerOptions": {
"outDir": "dist"
"outDir": "dist",
"rewriteRelativeImportExtensions": true
}
}
Loading