Skip to content

Commit b072bcc

Browse files
authored
Add simple PR comment sub-action (#636)
* Add simple PR comment sub-action * Update rolldown config * Add changeset * Update readme * Use TLA * Add prefix * fix merge * Update
1 parent 8795eee commit b072bcc

7 files changed

Lines changed: 161 additions & 1 deletion

File tree

.changeset/curly-cameras-matter.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@changesets/action": minor
3+
---
4+
5+
Add a new `@changesets/action/pr-comment` sub-action to comment on PRs

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ This action for [Changesets](https://github.com/changesets/changesets) creates a
55
There are also sub-actions hosted in this repository. Check out their respective READMEs for more details:
66

77
- [pr-status](./pr-status/README.md): Generate changeset status in PRs.
8+
- [pr-comment](./pr-comment/README.md): Comment on PRs.
89

910
## Usage
1011

pr-comment/README.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# @changesets/action/pr-comment
2+
3+
A simple GitHub Action to comment on PRs aimed to complement [`@changesets/action/pr-status`](../pr-status/README.md).
4+
5+
This action is intentionally simple without advanced features. Check out other actions if so, such as [mshick/add-pr-comment](https://github.com/marketplace/actions/add-pr-comment) and [peter-evans/create-or-update-comment](https://github.com/marketplace/actions/create-or-update-comment).
6+
7+
See the [action metadata](action.yml) for details on the inputs and outputs.
8+
9+
## Example setup
10+
11+
```yaml
12+
name: PR Comment
13+
14+
on:
15+
pull_request:
16+
17+
jobs:
18+
pr-comment:
19+
runs-on: ubuntu-slim
20+
permissions:
21+
pull-requests: write # to create and update comments on PRs
22+
steps:
23+
- uses: changesets/action/pr-comment@v1
24+
with:
25+
body: Hello world!
26+
```
27+
28+
When called repeatedly, the action will update the comment it created by default. If you use this action to create different types of comments, pass an `update-id` value to differentiate them.
29+
30+
```yaml
31+
jobs:
32+
pr-comment:
33+
# ...
34+
steps:
35+
- uses: changesets/action/pr-comment@v1
36+
with:
37+
body: Hello world!
38+
update-id: my-tag
39+
```
40+
41+
If you want to always create new comments, pass an empty value to `update-id`.
42+
43+
```yaml
44+
jobs:
45+
pr-comment:
46+
# ...
47+
steps:
48+
- uses: changesets/action/pr-comment@v1
49+
with:
50+
body: Hello world!
51+
update-id: ""
52+
```

pr-comment/action.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: Changesets - PR Comment
2+
description: A simple GitHub Action to comment on PRs
3+
runs:
4+
using: node24
5+
main: ../dist/pr-comment.js
6+
inputs:
7+
github-token:
8+
description: "The GitHub token to use for authentication. Defaults to the GitHub-provided token."
9+
required: false
10+
default: ${{ github.token }}
11+
body:
12+
description: "The comment body to post on the PR."
13+
required: true
14+
update-id:
15+
description: >
16+
By default, the action will create and update a comment with this id. Pass a different id to
17+
create and update a new comment, or pass an empty string to disable updating comments.
18+
required: false
19+
default: "changesets-action-pr-comment"
20+
outputs:
21+
comment-id:
22+
description: "The comment id of the comment that was created or updated."
23+
branding:
24+
icon: message-circle
25+
color: blue

pr-status/README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ jobs:
5656
uses: changesets/action/pr-comment@v1
5757
with:
5858
body: ${{ needs.pr-status.outputs.comment-body }}
59-
update-id: changesets-pr-status
6059
```
6160
6261
The workflow uses [`@changesets/action/pr-comment`](../pr-comment/README.md), which is a simple GitHub Action to comment on PRs.

rolldown.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export default defineConfig({
44
input: {
55
index: "src/index.ts",
66
["pr-status"]: "src/pr-status/index.ts",
7+
["pr-comment"]: "src/pr-comment/index.ts",
78
},
89
output: {
910
dir: "dist",

src/pr-comment/index.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import * as core from "@actions/core";
2+
import * as github from "@actions/github";
3+
4+
type Octokit = ReturnType<typeof github.getOctokit>;
5+
type CreateCommentParams = NonNullable<
6+
Parameters<Octokit["rest"]["issues"]["createComment"]>[0]
7+
>;
8+
type UpdateCommentParams = NonNullable<
9+
Parameters<Octokit["rest"]["issues"]["updateComment"]>[0]
10+
>;
11+
12+
try {
13+
await main();
14+
} catch (err) {
15+
core.setFailed((err as Error).message);
16+
}
17+
18+
async function main() {
19+
const context = github.context.payload.pull_request;
20+
if (!context) {
21+
throw new Error(
22+
"This action should only be run on `pull_request_target` or `pull_request` events",
23+
);
24+
}
25+
26+
const githubToken = core.getInput("github-token", { required: true });
27+
const body = core.getInput("body", { required: true });
28+
const updateId = core.getInput("update-id");
29+
30+
const commentMarker = updateId ? getCommentMarker(updateId) : null;
31+
const commentBody = commentMarker ? `${commentMarker}\n\n${body}` : body;
32+
const commentParam: CreateCommentParams | UpdateCommentParams = {
33+
repo: context.base.repo.name,
34+
owner: context.base.repo.owner.login,
35+
issue_number: context.number,
36+
body: commentBody,
37+
};
38+
39+
const octokit = github.getOctokit(githubToken);
40+
41+
let existingCommentId: number | undefined;
42+
if (commentMarker) {
43+
core.info("Checking for existing comment...");
44+
existingCommentId = await octokit.rest.issues
45+
.listComments({
46+
repo: context.base.repo.name,
47+
owner: context.base.repo.owner.login,
48+
issue_number: context.number,
49+
})
50+
.then((res) => {
51+
const comment = res.data.find((c) => c.body?.includes(commentMarker));
52+
return comment?.id;
53+
});
54+
}
55+
56+
if (existingCommentId) {
57+
core.info(`Updating existing comment (id: ${existingCommentId})...`);
58+
await octokit.rest.issues.updateComment({
59+
...commentParam,
60+
comment_id: existingCommentId,
61+
});
62+
core.setOutput("comment-id", existingCommentId);
63+
} else {
64+
core.info("Creating new comment...");
65+
const result = await octokit.rest.issues.createComment(commentParam);
66+
core.setOutput("comment-id", result.data.id);
67+
}
68+
69+
core.info("Done!");
70+
}
71+
72+
function getCommentMarker(updateId: string) {
73+
const prefix = "changesets-action-pr-comment";
74+
return prefix === updateId
75+
? `<!-- ${prefix} -->`
76+
: `<!-- ${prefix}:${updateId} -->`;
77+
}

0 commit comments

Comments
 (0)