From 7f9b9ffd50a28ae298b3ba3dc548ee503fc7b648 Mon Sep 17 00:00:00 2001 From: patrick brisbin Date: Mon, 8 Apr 2024 14:29:07 -0400 Subject: [PATCH] Support reading from body-file Configured rules can now omit `body`, to load comment contents from a file. The file is read the same way as the configuration: via the GitHub API and from the default branch. The file path will conventionally be `.github/commenter/{name}.md`. If `body-file` is given, that is used as the complete path. If `body-file-name` is given, `.github/commenter/{body-file-name}` is used. The prefix is also configurable as `inputs.body-file-prefix`. If the file does not exist on the default branch, the API call to read it will error and we allow that error to bubble out as-is. We could catch and improve the messaging, or gracefully place details of the failure in the comment itself, but both of these have been deferred by now. We'll start simply. --- .github/commenter.yml | 5 +++++ .github/commenter/Prelude.md | 6 ++++++ README.md | 8 ++++++++ __tests__/fixtures/body_file.yml | 4 ++++ __tests__/main.test.ts | 25 +++++++++++++++++++++++-- action.yml | 4 ++++ src/commenter.ts | 18 +++++++++++++++--- 7 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 .github/commenter/Prelude.md create mode 100644 __tests__/fixtures/body_file.yml diff --git a/.github/commenter.yml b/.github/commenter.yml index 4950adb..ad52523 100644 --- a/.github/commenter.yml +++ b/.github/commenter.yml @@ -19,3 +19,8 @@ Frontend: - [ ] Do this - [ ] And this - [ ] And that + +Prelude: + where: + path: + matches: "backend/**/*" diff --git a/.github/commenter/Prelude.md b/.github/commenter/Prelude.md new file mode 100644 index 0000000..e316393 --- /dev/null +++ b/.github/commenter/Prelude.md @@ -0,0 +1,6 @@ +You've modified our Prelude! + +Please read the following links: + +- ... +- ... diff --git a/README.md b/README.md index f0d4243..dbce79e 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,14 @@ CommentOnAutomatedUpdate: integrity of the packages being updated. ``` +## Reading the Comment Body from a File + +If `body` is omitted, a file named `.github/commenter/{name}.md` is read from +the default branch for the comment contents. The `.github/commenter/` prefix can +be changed via `inputs.body-file-prefix`. The complete path, or just the name +part, can be specified via the `body-file` and `body-file-name` attributes of +the configuration, respectively. + ## Acknowledgements This action was highly inspired by (and began as a copy of) diff --git a/__tests__/fixtures/body_file.yml b/__tests__/fixtures/body_file.yml new file mode 100644 index 0000000..9705e0e --- /dev/null +++ b/__tests__/fixtures/body_file.yml @@ -0,0 +1,4 @@ +Prelude: + where: + path: + matches: "Prelude.hs" diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts index 8cc6445..8cc6ea9 100644 --- a/__tests__/main.test.ts +++ b/__tests__/main.test.ts @@ -22,6 +22,7 @@ const yamlFixtures = { "all_conditions.yml": fs.readFileSync( "__tests__/fixtures/all_conditions.yml", ), + "body_file.yml": fs.readFileSync("__tests__/fixtures/body_file.yml"), }; afterAll(() => jest.restoreAllMocks()); @@ -185,11 +186,31 @@ describe("run", () => { body: "This change requires human review\n", }); }); + + it("adds comments from file contents", async () => { + usingConfigYaml("body_file.yml"); + mockGitHubResponseGetContentOnce("Some content\n"); + mockGitHubResponseChangedFiles("Prelude.hs"); + + await run(); + + expect(createCommentMock).toHaveBeenCalledTimes(1); + expect(createCommentMock).toHaveBeenCalledWith({ + owner: "monalisa", + repo: "helloworld", + issue_number: 123, + body: "Some content\n", + }); + }); }); function usingConfigYaml(fixtureName: keyof typeof yamlFixtures): void { - reposMock.mockResolvedValue({ - data: { content: yamlFixtures[fixtureName], encoding: "utf8" }, + mockGitHubResponseGetContentOnce(yamlFixtures[fixtureName]); +} + +function mockGitHubResponseGetContentOnce(content: string): void { + reposMock.mockResolvedValueOnce({ + data: { content, encoding: "utf8" }, }); } diff --git a/action.yml b/action.yml index b7f5c47..12db980 100644 --- a/action.yml +++ b/action.yml @@ -9,6 +9,10 @@ inputs: description: "The path for the comment configurations" default: ".github/commenter.yml" required: false + body-file-prefix: + description: "The path for finding body markdown files" + default: ".github/commenter/" + required: false runs: using: "node20" diff --git a/src/commenter.ts b/src/commenter.ts index 4967b7b..e8a2856 100644 --- a/src/commenter.ts +++ b/src/commenter.ts @@ -12,6 +12,9 @@ export async function run() { try { const token = core.getInput("repo-token", { required: true }); const configPath = core.getInput("configuration-path", { required: true }); + const bodyFilePrefix = core.getInput("body-file-prefix", { + required: true, + }); const client: ClientType = github.getOctokit(token); const configs = await getConfigurations(client, configPath); @@ -19,9 +22,16 @@ export async function run() { let body: string | null = null; - for (const [_name, config] of Object.entries(configs)) { + for (const [name, config] of Object.entries(configs)) { if (matches(changes, config.where)) { - body = config.body; + if (config.body) { + body = config.body; + } else { + const bodyFileName = config["body-file-name"] ?? `${name}.md`; + const bodyFile = + config["body-file"] ?? `${bodyFilePrefix}${bodyFileName}`; + body = await fetchContent(client, bodyFile); + } break; // first match wins } } @@ -104,7 +114,9 @@ type ConfigurationWhereClause = { }; type Configuration = { - body: string; + body: string | undefined; + "body-file": string | undefined; + "body-file-name": string | undefined; where: ConfigurationWhereClause; };