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
This commit is contained in:
Bjorn Lu
2026-05-30 19:39:39 +00:00
committed by GitHub
parent 8795eee5ee
commit b072bccc4c
7 changed files with 161 additions and 1 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"@changesets/action": minor
---
Add a new `@changesets/action/pr-comment` sub-action to comment on PRs
+1
View File
@@ -5,6 +5,7 @@ This action for [Changesets](https://github.com/changesets/changesets) creates a
There are also sub-actions hosted in this repository. Check out their respective READMEs for more details: There are also sub-actions hosted in this repository. Check out their respective READMEs for more details:
- [pr-status](./pr-status/README.md): Generate changeset status in PRs. - [pr-status](./pr-status/README.md): Generate changeset status in PRs.
- [pr-comment](./pr-comment/README.md): Comment on PRs.
## Usage ## Usage
+52
View File
@@ -0,0 +1,52 @@
# @changesets/action/pr-comment
A simple GitHub Action to comment on PRs aimed to complement [`@changesets/action/pr-status`](../pr-status/README.md).
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).
See the [action metadata](action.yml) for details on the inputs and outputs.
## Example setup
```yaml
name: PR Comment
on:
pull_request:
jobs:
pr-comment:
runs-on: ubuntu-slim
permissions:
pull-requests: write # to create and update comments on PRs
steps:
- uses: changesets/action/pr-comment@v1
with:
body: Hello world!
```
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.
```yaml
jobs:
pr-comment:
# ...
steps:
- uses: changesets/action/pr-comment@v1
with:
body: Hello world!
update-id: my-tag
```
If you want to always create new comments, pass an empty value to `update-id`.
```yaml
jobs:
pr-comment:
# ...
steps:
- uses: changesets/action/pr-comment@v1
with:
body: Hello world!
update-id: ""
```
+25
View File
@@ -0,0 +1,25 @@
name: Changesets - PR Comment
description: A simple GitHub Action to comment on PRs
runs:
using: node24
main: ../dist/pr-comment.js
inputs:
github-token:
description: "The GitHub token to use for authentication. Defaults to the GitHub-provided token."
required: false
default: ${{ github.token }}
body:
description: "The comment body to post on the PR."
required: true
update-id:
description: >
By default, the action will create and update a comment with this id. Pass a different id to
create and update a new comment, or pass an empty string to disable updating comments.
required: false
default: "changesets-action-pr-comment"
outputs:
comment-id:
description: "The comment id of the comment that was created or updated."
branding:
icon: message-circle
color: blue
-1
View File
@@ -56,7 +56,6 @@ jobs:
uses: changesets/action/pr-comment@v1 uses: changesets/action/pr-comment@v1
with: with:
body: ${{ needs.pr-status.outputs.comment-body }} body: ${{ needs.pr-status.outputs.comment-body }}
update-id: changesets-pr-status
``` ```
The workflow uses [`@changesets/action/pr-comment`](../pr-comment/README.md), which is a simple GitHub Action to comment on PRs. The workflow uses [`@changesets/action/pr-comment`](../pr-comment/README.md), which is a simple GitHub Action to comment on PRs.
+1
View File
@@ -4,6 +4,7 @@ export default defineConfig({
input: { input: {
index: "src/index.ts", index: "src/index.ts",
["pr-status"]: "src/pr-status/index.ts", ["pr-status"]: "src/pr-status/index.ts",
["pr-comment"]: "src/pr-comment/index.ts",
}, },
output: { output: {
dir: "dist", dir: "dist",
+77
View File
@@ -0,0 +1,77 @@
import * as core from "@actions/core";
import * as github from "@actions/github";
type Octokit = ReturnType<typeof github.getOctokit>;
type CreateCommentParams = NonNullable<
Parameters<Octokit["rest"]["issues"]["createComment"]>[0]
>;
type UpdateCommentParams = NonNullable<
Parameters<Octokit["rest"]["issues"]["updateComment"]>[0]
>;
try {
await main();
} catch (err) {
core.setFailed((err as Error).message);
}
async function main() {
const context = github.context.payload.pull_request;
if (!context) {
throw new Error(
"This action should only be run on `pull_request_target` or `pull_request` events",
);
}
const githubToken = core.getInput("github-token", { required: true });
const body = core.getInput("body", { required: true });
const updateId = core.getInput("update-id");
const commentMarker = updateId ? getCommentMarker(updateId) : null;
const commentBody = commentMarker ? `${commentMarker}\n\n${body}` : body;
const commentParam: CreateCommentParams | UpdateCommentParams = {
repo: context.base.repo.name,
owner: context.base.repo.owner.login,
issue_number: context.number,
body: commentBody,
};
const octokit = github.getOctokit(githubToken);
let existingCommentId: number | undefined;
if (commentMarker) {
core.info("Checking for existing comment...");
existingCommentId = await octokit.rest.issues
.listComments({
repo: context.base.repo.name,
owner: context.base.repo.owner.login,
issue_number: context.number,
})
.then((res) => {
const comment = res.data.find((c) => c.body?.includes(commentMarker));
return comment?.id;
});
}
if (existingCommentId) {
core.info(`Updating existing comment (id: ${existingCommentId})...`);
await octokit.rest.issues.updateComment({
...commentParam,
comment_id: existingCommentId,
});
core.setOutput("comment-id", existingCommentId);
} else {
core.info("Creating new comment...");
const result = await octokit.rest.issues.createComment(commentParam);
core.setOutput("comment-id", result.data.id);
}
core.info("Done!");
}
function getCommentMarker(updateId: string) {
const prefix = "changesets-action-pr-comment";
return prefix === updateId
? `<!-- ${prefix} -->`
: `<!-- ${prefix}:${updateId} -->`;
}