Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ jobs:
key: static

- run: npm ci

- run: npx tsx bin/post-codeowners-comment/index.ts
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- run: npm run check

- uses: reviewdog/action-eslint@v1
Expand Down
3 changes: 3 additions & 0 deletions bin/post-codeowners-comment/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const GITHUB_ACTIONS_BOT_ID = 41898282;
export const COMMENT_PREFIX =
"This pull request requires reviews from **CODEOWNERS** as it changes files that match the following patterns:";
95 changes: 95 additions & 0 deletions bin/post-codeowners-comment/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import * as core from "@actions/core";
import * as github from "@actions/github";
import type { PullRequestEvent } from "@octokit/webhooks-types";

import { loadOwners, matchFile } from "codeowners-utils";
import { GITHUB_ACTIONS_BOT_ID, COMMENT_PREFIX } from "./constants.ts";

async function run(): Promise<void> {
try {
if (!process.env.GITHUB_TOKEN) {
core.setFailed(`Could not find GITHUB_TOKEN in env`);
process.exit();
}

const octokit = github.getOctokit(process.env.GITHUB_TOKEN);
const payload = github.context.payload as PullRequestEvent;

const { owner, repo } = github.context.repo;
const pullRequestNumber = payload.number;

const files = await octokit.paginate(octokit.rest.pulls.listFiles, {
owner,
repo,
pull_number: pullRequestNumber,
});

const codeowners = await loadOwners(process.cwd());

if (!codeowners) {
throw new Error("Unable to load CODEOWNERS file.");
}

const matchedPatterns = [
...new Set(
files.flatMap((file) => matchFile(file.filename, codeowners) ?? []),
),
];

const { data: comments } = await octokit.rest.issues.listComments({
owner,
repo,
issue_number: pullRequestNumber,
per_page: 100,
});

const existingComment = comments.find(
(comment) =>
comment.user?.id === GITHUB_ACTIONS_BOT_ID &&
comment.body?.includes(COMMENT_PREFIX),
);

if (existingComment) {
core.info(`Found existing comment with ID ${existingComment.id}`);
} else {
core.info(`No existing comment found`);
}

const comment = [
COMMENT_PREFIX,
"| Pattern | Owners |",
"| ------- | ------ |",
...matchedPatterns.map(
(pattern) =>
`| \`${pattern.pattern}\` | ${pattern.owners.map((owner) => `\`${owner}\``).join(", ")} |`,
),
].join("\n");

if (existingComment) {
core.info(
`Updating ${existingComment.id} with ${JSON.stringify(comment)}`,
);
await octokit.rest.issues.updateComment({
owner,
repo,
comment_id: existingComment.id,
body: comment,
});
} else {
core.info(`Creating new comment with ${JSON.stringify(comment)}`);
await octokit.rest.issues.createComment({
owner,
repo,
issue_number: pullRequestNumber,
body: comment,
});
}
} catch (error) {
if (error instanceof Error) {
core.setFailed(error.message);
}
process.exit();
}
}

run();
Loading