Compare commits

..

No commits in common. "main" and "v2.1.0" have entirely different histories.
main ... v2.1.0

25 changed files with 11266 additions and 33033 deletions

View File

@ -1,3 +0,0 @@
dist/
lib/
node_modules/

View File

@ -1,18 +1,17 @@
{ {
"env": { "node": true, "jest": true }, "env": {
"parser": "@typescript-eslint/parser", "commonjs": true,
"parserOptions": { "ecmaVersion": 9, "sourceType": "module" }, "es6": true,
"extends": [ "node": true
"eslint:recommended", },
"plugin:@typescript-eslint/eslint-recommended", "extends": "eslint:recommended",
"plugin:@typescript-eslint/recommended", "globals": {
"plugin:import/errors", "Atomics": "readonly",
"plugin:import/warnings", "SharedArrayBuffer": "readonly"
"plugin:import/typescript", },
"plugin:prettier/recommended" "parserOptions": {
], "ecmaVersion": 2018
"plugins": ["@typescript-eslint"], },
"rules": { "rules": {
"@typescript-eslint/camelcase": "off" }
}
} }

View File

@ -1 +1 @@
This is still the second line. **Edit:** Some additional info

View File

@ -1,2 +1,5 @@
This is a multi-line test comment read from a file. This is a multi-line test comment read from a file.
This is the second line. - With GitHub **Markdown** :sparkles:
- Created by [create-or-update-comment][1]
[1]: https://github.com/peter-evans/create-or-update-comment

View File

@ -4,7 +4,6 @@ updates:
directory: "/" directory: "/"
schedule: schedule:
interval: "weekly" interval: "weekly"
day: "wednesday"
labels: labels:
- "dependencies" - "dependencies"
@ -12,9 +11,5 @@ updates:
directory: "/" directory: "/"
schedule: schedule:
interval: "weekly" interval: "weekly"
day: "wednesday" allow:
ignore: - dependency-name: "@actions/*"
- dependency-name: "*"
update-types: ["version-update:semver-major"]
labels:
- "dependencies"

View File

@ -1,13 +0,0 @@
name: Auto-merge Dependabot
on: pull_request
jobs:
automerge:
runs-on: ubuntu-latest
if: github.actor == 'dependabot[bot]'
steps:
- uses: peter-evans/enable-pull-request-automerge@v3
with:
token: ${{ secrets.ACTIONS_BOT_TOKEN }}
pull-request-number: ${{ github.event.pull_request.number }}
merge-method: squash

View File

@ -22,21 +22,18 @@ jobs:
outputs: outputs:
issue-number: ${{ steps.vars.outputs.issue-number }} issue-number: ${{ steps.vars.outputs.issue-number }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- uses: actions/setup-node@v4 - uses: actions/setup-node@v3
with: with:
node-version: 20.x node-version: 16.x
cache: npm
- run: npm ci - run: npm ci
- run: npm run build
- run: npm run format-check
- run: npm run lint
- run: npm run test - run: npm run test
- uses: actions/upload-artifact@v4 - run: npm run package
- uses: actions/upload-artifact@v3
with: with:
name: dist name: dist
path: dist path: dist
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v3
with: with:
name: action.yml name: action.yml
path: action.yml path: action.yml
@ -56,14 +53,14 @@ jobs:
matrix: matrix:
target: [built, committed] target: [built, committed]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- if: matrix.target == 'built' || github.event_name == 'pull_request' - if: matrix.target == 'built' || github.event_name == 'pull_request'
uses: actions/download-artifact@v4 uses: actions/download-artifact@v3
with: with:
name: dist name: dist
path: dist path: dist
- if: matrix.target == 'built' || github.event_name == 'pull_request' - if: matrix.target == 'built' || github.event_name == 'pull_request'
uses: actions/download-artifact@v4 uses: actions/download-artifact@v3
with: with:
name: action.yml name: action.yml
path: . path: .
@ -88,49 +85,41 @@ jobs:
body: | body: |
**Edit:** Some additional info **Edit:** Some additional info
reactions: eyes reactions: eyes
reactions-edit-mode: replace
- name: Test add reactions - name: Test add reactions
uses: ./ uses: ./
with: with:
comment-id: ${{ steps.couc.outputs.comment-id }} comment-id: ${{ steps.couc.outputs.comment-id }}
reactions: | reactions: heart, hooray, laugh
heart
hooray
laugh
- name: Test create comment from file - name: Test create comment from file
uses: ./ uses: ./
id: couc2 id: couc2
with: with:
issue-number: ${{ needs.build.outputs.issue-number }} issue-number: ${{ needs.build.outputs.issue-number }}
body-path: .github/comment-body.md body-file: .github/comment-body.md
reactions: | reactions: '+1'
+1
- name: Test update comment from file - name: Test update comment from file
uses: ./ uses: ./
with: with:
comment-id: ${{ steps.couc2.outputs.comment-id }} comment-id: ${{ steps.couc2.outputs.comment-id }}
body-path: .github/comment-body-addition.md body-file: .github/comment-body-addition.md
append-separator: space reactions: eyes
reactions: eyes, rocket
reactions-edit-mode: replace
package: package:
if: github.event_name == 'push' && github.ref == 'refs/heads/main' if: github.event_name == 'push' && github.ref == 'refs/heads/main'
needs: [test] needs: [test]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v3
with: with:
name: dist name: dist
path: dist path: dist
- name: Create Pull Request - name: Create Pull Request
uses: peter-evans/create-pull-request@v7 uses: peter-evans/create-pull-request@v4
with: with:
token: ${{ secrets.ACTIONS_BOT_TOKEN }}
commit-message: Update distribution commit-message: Update distribution
title: Update distribution title: Update distribution
body: | body: |

View File

@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Slash Command Dispatch - name: Slash Command Dispatch
uses: peter-evans/slash-command-dispatch@v4 uses: peter-evans/slash-command-dispatch@v3
with: with:
token: ${{ secrets.ACTIONS_BOT_TOKEN }} token: ${{ secrets.ACTIONS_BOT_TOKEN }}
config: > config: >

View File

@ -18,7 +18,7 @@ jobs:
echo "branch=$branch" >> $GITHUB_OUTPUT echo "branch=$branch" >> $GITHUB_OUTPUT
# Checkout the branch to test # Checkout the branch to test
- uses: actions/checkout@v4 - uses: actions/checkout@v3
with: with:
repository: ${{ steps.vars.outputs.repository }} repository: ${{ steps.vars.outputs.repository }}
ref: ${{ steps.vars.outputs.branch }} ref: ${{ steps.vars.outputs.branch }}
@ -45,7 +45,6 @@ jobs:
body: | body: |
**Edit:** Some additional info **Edit:** Some additional info
reactions: eyes reactions: eyes
reactions-edit-mode: replace
# Test add reactions # Test add reactions
- name: Add reactions - name: Add reactions
@ -54,17 +53,24 @@ jobs:
comment-id: ${{ steps.couc.outputs.comment-id }} comment-id: ${{ steps.couc.outputs.comment-id }}
reactions: heart, hooray, laugh reactions: heart, hooray, laugh
- name: Add reaction
uses: peter-evans/create-or-update-comment@v2
with:
repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
comment-id: ${{ github.event.client_payload.github.payload.comment.id }}
reactions: hooray
# Test create with body from file # Test create with body from file
- name: Create comment - name: Create comment
uses: ./ uses: ./
with: with:
issue-number: 1 issue-number: 1
body-path: .github/comment-body.md body-file: .github/comment-body.md
# Test create from template # Test create from template
- name: Render template - name: Render template
id: template id: template
uses: chuhlomin/render-template@v1.10 uses: chuhlomin/render-template@v1.6
with: with:
template: .github/comment-template.md template: .github/comment-template.md
vars: | vars: |
@ -76,10 +82,3 @@ jobs:
with: with:
issue-number: 1 issue-number: 1
body: ${{ steps.template.outputs.result }} body: ${{ steps.template.outputs.result }}
- name: Add reaction
uses: peter-evans/create-or-update-comment@v4
with:
repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
comment-id: ${{ github.event.client_payload.github.payload.comment.id }}
reactions: hooray

View File

@ -1,66 +0,0 @@
name: Test v3
on: workflow_dispatch
jobs:
testCreateOrUpdateComment:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Test create
- name: Create comment
uses: peter-evans/create-or-update-comment@v4
id: couc
with:
token: ${{ secrets.ACTIONS_BOT_TOKEN }}
issue-number: 1
body: |
This is a multi-line test comment
- With GitHub **Markdown** :sparkles:
- Created by [create-or-update-comment][1]
[1]: https://github.com/peter-evans/create-or-update-comment
reactions: '+1'
# Test update
- name: Update comment
uses: peter-evans/create-or-update-comment@v4
with:
token: ${{ secrets.ACTIONS_BOT_TOKEN }}
comment-id: ${{ steps.couc.outputs.comment-id }}
body: |
**Edit:** Some additional info
reactions: eyes
reactions-edit-mode: replace
# Test add reactions
- name: Add reactions
uses: peter-evans/create-or-update-comment@v4
with:
token: ${{ secrets.ACTIONS_BOT_TOKEN }}
comment-id: ${{ steps.couc.outputs.comment-id }}
reactions: heart, hooray, laugh
# Test create with body from file
- name: Create comment
uses: peter-evans/create-or-update-comment@v4
with:
token: ${{ secrets.ACTIONS_BOT_TOKEN }}
issue-number: 1
body-file: .github/comment-body.md
# Test create from template
- name: Render template
id: template
uses: chuhlomin/render-template@v1.10
with:
template: .github/comment-template.md
vars: |
foo: this
bar: that
- name: Create comment
uses: peter-evans/create-or-update-comment@v4
with:
token: ${{ secrets.ACTIONS_BOT_TOKEN }}
issue-number: 1
body: ${{ steps.template.outputs.result }}

View File

@ -1,32 +0,0 @@
name: Update Major Version
run-name: Update ${{ github.event.inputs.main_version }} to ${{ github.event.inputs.target }}
on:
workflow_dispatch:
inputs:
target:
description: The target tag or reference
required: true
main_version:
type: choice
description: The major version tag to update
options:
- v3
- v4
jobs:
tag:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.ACTIONS_BOT_TOKEN }}
fetch-depth: 0
- name: Git config
run: |
git config user.name actions-bot
git config user.email actions-bot@users.noreply.github.com
- name: Tag new target
run: git tag -f ${{ github.event.inputs.main_version }} ${{ github.event.inputs.target }}
- name: Push new tag
run: git push origin ${{ github.event.inputs.main_version }} --force

3
.gitignore vendored
View File

@ -1,2 +1 @@
lib/ node_modules
node_modules/

View File

@ -1,3 +0,0 @@
dist/
lib/
node_modules/

View File

@ -1,11 +0,0 @@
{
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": false,
"singleQuote": true,
"trailingComma": "none",
"bracketSpacing": false,
"arrowParens": "avoid",
"parser": "typescript"
}

View File

@ -4,13 +4,15 @@
A GitHub action to create or update an issue or pull request comment. A GitHub action to create or update an issue or pull request comment.
This action was created to help facilitate a GitHub Actions "ChatOps" solution in conjunction with [slash-command-dispatch](https://github.com/peter-evans/slash-command-dispatch) action.
## Usage ## Usage
### Add a comment to an issue or pull request ### Add a comment to an issue or pull request
```yml ```yml
- name: Create comment - name: Create comment
uses: peter-evans/create-or-update-comment@v4 uses: peter-evans/create-or-update-comment@v2
with: with:
issue-number: 1 issue-number: 1
body: | body: |
@ -26,7 +28,7 @@ A GitHub action to create or update an issue or pull request comment.
```yml ```yml
- name: Update comment - name: Update comment
uses: peter-evans/create-or-update-comment@v4 uses: peter-evans/create-or-update-comment@v2
with: with:
comment-id: 557858210 comment-id: 557858210
body: | body: |
@ -38,33 +40,28 @@ A GitHub action to create or update an issue or pull request comment.
```yml ```yml
- name: Add reactions - name: Add reactions
uses: peter-evans/create-or-update-comment@v4 uses: peter-evans/create-or-update-comment@v2
with: with:
comment-id: 557858210 comment-id: 557858210
reactions: | reactions: heart, hooray, laugh
heart
hooray
laugh
``` ```
### Action inputs ### Action inputs
| Name | Description | Default | | Name | Description | Default |
| --- | --- | --- | | --- | --- | --- |
| `token` | `GITHUB_TOKEN` (`issues: write`, `pull-requests: write`) or a `repo` scoped [PAT](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token). | `GITHUB_TOKEN` | | `token` | `GITHUB_TOKEN` (`issues: write`, `pull-requests: write`) or a `repo` scoped [PAT](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token). | `GITHUB_TOKEN` |
| `repository` | The full name of the repository in which to create or update a comment. | Current repository | | `repository` | The full name of the repository in which to create or update a comment. | Current repository |
| `issue-number` | The number of the issue or pull request in which to create a comment. | | | `issue-number` | The number of the issue or pull request in which to create a comment. | |
| `comment-id` | The id of the comment to update. | | | `comment-id` | The id of the comment to update. | |
| `body` | The comment body. Cannot be used in conjunction with `body-path`. | | | `body` | The comment body. Cannot be used in conjunction with `body-file`. | |
| `body-path` | The path to a file containing the comment body. Cannot be used in conjunction with `body`. | | | `body-file` | The path to a file containing the comment body. Cannot be used in conjunction with `body`. | |
| `edit-mode` | The mode when updating a comment, `replace` or `append`. | `append` | | `edit-mode` | The mode when updating a comment, `replace` or `append`. | `append` |
| `append-separator` | The separator to use when appending to an existing comment. (`newline`, `space`, `none`) | `newline` | | `reactions` | A comma separated list of reactions to add to the comment. (`+1`, `-1`, `laugh`, `confused`, `heart`, `hooray`, `rocket`, `eyes`) | |
| `reactions` | A comma or newline separated list of reactions to add to the comment. (`+1`, `-1`, `laugh`, `confused`, `heart`, `hooray`, `rocket`, `eyes`) | |
| `reactions-edit-mode` | The mode when updating comment reactions, `replace` or `append`. | `append` |
Note: In *public* repositories this action does not work in `pull_request` workflows when triggered by forks. Note: In *public* repositories this action does not work in `pull_request` workflows when triggered by forks.
Any attempt will be met with the error, `Resource not accessible by integration`. Any attempt will be met with the error, `Resource not accessible by integration`.
This is due to token restrictions put in place by GitHub Actions. Private repositories can be configured to [enable workflows](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository#enabling-workflows-for-forks-of-private-repositories) from forks to run without restriction. See [here](https://github.com/peter-evans/create-pull-request/blob/main/docs/concepts-guidelines.md#restrictions-on-repository-forks) for further explanation. Alternatively, use the [`pull_request_target`](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target) event to comment on pull requests. This is due to token restrictions put in place by GitHub Actions. Private repositories can be configured to [enable workflows](https://docs.github.com/en/github/administering-a-repository/disabling-or-limiting-github-actions-for-a-repository#enabling-workflows-for-private-repository-forks) from forks to run without restriction. See [here](https://github.com/peter-evans/create-pull-request/blob/main/docs/concepts-guidelines.md#restrictions-on-repository-forks) for further explanation. Alternatively, use the [`pull_request_target`](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#pull_request_target) event to comment on pull requests.
#### Outputs #### Outputs
@ -73,7 +70,7 @@ Note that in order to read the step output the action step must have an id.
```yml ```yml
- name: Create comment - name: Create comment
uses: peter-evans/create-or-update-comment@v4 uses: peter-evans/create-or-update-comment@v2
id: couc id: couc
with: with:
issue-number: 1 issue-number: 1
@ -98,7 +95,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Add reaction - name: Add reaction
uses: peter-evans/create-or-update-comment@v4 uses: peter-evans/create-or-update-comment@v2
with: with:
comment-id: ${{ github.event.comment.id }} comment-id: ${{ github.event.comment.id }}
reactions: eyes reactions: eyes
@ -113,7 +110,7 @@ If the find-comment action output `comment-id` returns an empty string, a new co
If it returns a value, the comment already exists and the content is replaced. If it returns a value, the comment already exists and the content is replaced.
```yml ```yml
- name: Find Comment - name: Find Comment
uses: peter-evans/find-comment@v3 uses: peter-evans/find-comment@v2
id: fc id: fc
with: with:
issue-number: ${{ github.event.pull_request.number }} issue-number: ${{ github.event.pull_request.number }}
@ -121,7 +118,7 @@ If it returns a value, the comment already exists and the content is replaced.
body-includes: Build output body-includes: Build output
- name: Create or update comment - name: Create or update comment
uses: peter-evans/create-or-update-comment@v4 uses: peter-evans/create-or-update-comment@v2
with: with:
comment-id: ${{ steps.fc.outputs.comment-id }} comment-id: ${{ steps.fc.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }} issue-number: ${{ github.event.pull_request.number }}
@ -134,7 +131,7 @@ If it returns a value, the comment already exists and the content is replaced.
If required, the create and update steps can be separated for greater control. If required, the create and update steps can be separated for greater control.
```yml ```yml
- name: Find Comment - name: Find Comment
uses: peter-evans/find-comment@v3 uses: peter-evans/find-comment@v2
id: fc id: fc
with: with:
issue-number: ${{ github.event.pull_request.number }} issue-number: ${{ github.event.pull_request.number }}
@ -143,7 +140,7 @@ If required, the create and update steps can be separated for greater control.
- name: Create comment - name: Create comment
if: steps.fc.outputs.comment-id == '' if: steps.fc.outputs.comment-id == ''
uses: peter-evans/create-or-update-comment@v4 uses: peter-evans/create-or-update-comment@v2
with: with:
issue-number: ${{ github.event.pull_request.number }} issue-number: ${{ github.event.pull_request.number }}
body: | body: |
@ -152,7 +149,7 @@ If required, the create and update steps can be separated for greater control.
- name: Update comment - name: Update comment
if: steps.fc.outputs.comment-id != '' if: steps.fc.outputs.comment-id != ''
uses: peter-evans/create-or-update-comment@v4 uses: peter-evans/create-or-update-comment@v2
with: with:
comment-id: ${{ steps.fc.outputs.comment-id }} comment-id: ${{ steps.fc.outputs.comment-id }}
body: | body: |
@ -164,10 +161,10 @@ If required, the create and update steps can be separated for greater control.
```yml ```yml
- name: Create comment - name: Create comment
uses: peter-evans/create-or-update-comment@v4 uses: peter-evans/create-or-update-comment@v2
with: with:
issue-number: 1 issue-number: 1
body-path: 'comment-body.md' body-file: 'comment-body.md'
``` ```
### Using a markdown template ### Using a markdown template
@ -190,7 +187,7 @@ The template is rendered using the [render-template](https://github.com/chuhlomi
bar: that bar: that
- name: Create comment - name: Create comment
uses: peter-evans/create-or-update-comment@v4 uses: peter-evans/create-or-update-comment@v2
with: with:
issue-number: 1 issue-number: 1
body: ${{ steps.template.outputs.result }} body: ${{ steps.template.outputs.result }}
@ -198,7 +195,7 @@ The template is rendered using the [render-template](https://github.com/chuhlomi
### Accessing issues and comments in other repositories ### Accessing issues and comments in other repositories
You can create and update comments in another repository by using a [PAT](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) instead of `GITHUB_TOKEN`. You can create and update comments in another repository by using a [PAT](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) instead of `GITHUB_TOKEN`.
The user associated with the PAT must have write access to the repository. The user associated with the PAT must have write access to the repository.
## License ## License

View File

@ -6,33 +6,25 @@ inputs:
default: ${{ github.token }} default: ${{ github.token }}
repository: repository:
description: 'The full name of the repository in which to create or update a comment.' description: 'The full name of the repository in which to create or update a comment.'
default: ${{ github.repository }}
issue-number: issue-number:
description: 'The number of the issue or pull request in which to create a comment.' description: 'The number of the issue or pull request in which to create a comment.'
comment-id: comment-id:
description: 'The id of the comment to update.' description: 'The id of the comment to update.'
body: body:
description: 'The comment body. Cannot be used in conjunction with `body-path`.' description: 'The comment body. Cannot be used in conjunction with `body-file`.'
body-path:
description: 'The path to a file containing the comment body. Cannot be used in conjunction with `body`.'
body-file: body-file:
description: 'Deprecated in favour of `body-path`.' description: 'The path to a file containing the comment body. Cannot be used in conjunction with `body`.'
edit-mode: edit-mode:
description: 'The mode when updating a comment, "replace" or "append".' description: 'The mode when updating a comment, "replace" or "append".'
default: 'append' reaction-type:
append-separator: description: 'Deprecated in favour of `reactions`'
description: 'The separator to use when appending to an existing comment. (`newline`, `space`, `none`)'
default: 'newline'
reactions: reactions:
description: 'A comma or newline separated list of reactions to add to the comment.' description: 'A comma separated list of reactions to add to the comment.'
reactions-edit-mode:
description: 'The mode when updating comment reactions, "replace" or "append".'
default: 'append'
outputs: outputs:
comment-id: comment-id:
description: 'The id of the created comment' description: 'The id of the created comment'
runs: runs:
using: 'node20' using: 'node16'
main: 'dist/index.js' main: 'dist/index.js'
branding: branding:
icon: 'message-square' icon: 'message-square'

34708
dist/index.js vendored

File diff suppressed because one or more lines are too long

192
index.js Normal file
View File

@ -0,0 +1,192 @@
const { inspect } = require("util");
const { readFileSync, existsSync } = require("fs");
const core = require("@actions/core");
const github = require("@actions/github");
const REACTION_TYPES = [
"+1",
"-1",
"laugh",
"confused",
"heart",
"hooray",
"rocket",
"eyes",
];
async function addReactions(octokit, repo, comment_id, reactions) {
let ReactionsSet = [
...new Set(
reactions
.replace(/\s/g, "")
.split(",")
.filter((item) => {
if (!REACTION_TYPES.includes(item)) {
core.info(`Skipping invalid reaction '${item}'.`);
return false;
}
return true;
})
),
];
if (!ReactionsSet) {
core.setFailed(
`No valid reactions are contained in '${reactions}'.`
);
return false;
}
let results = await Promise.allSettled(
ReactionsSet.map(async (item) => {
await octokit.rest.reactions.createForIssueComment({
owner: repo[0],
repo: repo[1],
comment_id: comment_id,
content: item,
});
core.info(`Setting '${item}' reaction on comment.`);
})
);
for (let i = 0, l = results.length; i < l; i++) {
if (results[i].status === "fulfilled") {
core.info(
`Added reaction '${ReactionsSet[i]}' to comment id '${comment_id}'.`
);
} else if (results[i].status === "rejected") {
core.info(
`Adding reaction '${ReactionsSet[i]}' to comment id '${comment_id}' failed with ${results[i].reason}.`
);
}
}
ReactionsSet = undefined;
results = undefined;
}
function getBody(inputs) {
if (inputs.body) {
return inputs.body;
} else if (inputs.bodyFile) {
return readFileSync(inputs.bodyFile, 'utf-8');
} else {
return '';
}
}
async function run() {
try {
const inputs = {
token: core.getInput("token"),
repository: core.getInput("repository"),
issueNumber: core.getInput("issue-number"),
commentId: core.getInput("comment-id"),
body: core.getInput("body"),
bodyFile: core.getInput("body-file"),
editMode: core.getInput("edit-mode"),
reactions: core.getInput("reactions")
? core.getInput("reactions")
: core.getInput("reaction-type"),
};
core.debug(`Inputs: ${inspect(inputs)}`);
const repository = inputs.repository
? inputs.repository
: process.env.GITHUB_REPOSITORY;
const repo = repository.split("/");
core.debug(`repository: ${repository}`);
const editMode = inputs.editMode ? inputs.editMode : "append";
core.debug(`editMode: ${editMode}`);
if (!["append", "replace"].includes(editMode)) {
core.setFailed(`Invalid edit-mode '${editMode}'.`);
return;
}
if (inputs.bodyFile && inputs.body) {
core.setFailed("Only one of 'body' or 'body-file' can be set.");
return;
}
if (inputs.bodyFile) {
if (!existsSync(inputs.bodyFile)) {
core.setFailed(`File '${inputs.bodyFile}' does not exist.`);
return;
}
}
const body = getBody(inputs);
const octokit = github.getOctokit(inputs.token);
if (inputs.commentId) {
// Edit a comment
if (!body && !inputs.reactions) {
core.setFailed("Missing comment 'body', 'body-file', or 'reactions'.");
return;
}
if (body) {
var commentBody = "";
if (editMode == "append") {
// Get the comment body
const { data: comment } = await octokit.rest.issues.getComment({
owner: repo[0],
repo: repo[1],
comment_id: inputs.commentId,
});
commentBody = comment.body + "\n";
}
commentBody = commentBody + body;
core.debug(`Comment body: ${commentBody}`);
await octokit.rest.issues.updateComment({
owner: repo[0],
repo: repo[1],
comment_id: inputs.commentId,
body: commentBody,
});
core.info(`Updated comment id '${inputs.commentId}'.`);
core.setOutput("comment-id", inputs.commentId);
}
// Set comment reactions
if (inputs.reactions) {
await addReactions(octokit, repo, inputs.commentId, inputs.reactions);
}
} else if (inputs.issueNumber) {
// Create a comment
if (!body) {
core.setFailed("Missing comment 'body' or 'body-file'.");
return;
}
const { data: comment } = await octokit.rest.issues.createComment({
owner: repo[0],
repo: repo[1],
issue_number: inputs.issueNumber,
body,
});
core.info(
`Created comment id '${comment.id}' on issue '${inputs.issueNumber}'.`
);
core.setOutput("comment-id", comment.id);
// Set comment reactions
if (inputs.reactions) {
await addReactions(octokit, repo, comment.id, inputs.reactions);
}
} else {
core.setFailed("Missing either 'issue-number' or 'comment-id'.");
return;
}
} catch (error) {
core.debug(inspect(error));
core.setFailed(error.message);
if (error.message == 'Resource not accessible by integration') {
core.error(`See this action's readme for details about this error`);
}
}
}
run();

View File

@ -1,11 +0,0 @@
module.exports = {
clearMocks: true,
moduleFileExtensions: ['js', 'ts'],
testEnvironment: 'node',
testMatch: ['**/*.test.ts'],
testRunner: 'jest-circus/runner',
transform: {
'^.+\\.ts$': 'ts-jest'
},
verbose: true
}

8632
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,25 +1,18 @@
{ {
"name": "create-or-update-comment", "name": "create-or-update-comment",
"version": "4.0.0", "version": "2.0.0",
"description": "Create or update an issue or pull request comment", "description": "Create or update an issue or pull request comment",
"main": "lib/main.js", "main": "index.js",
"scripts": { "scripts": {
"build": "tsc && ncc build", "lint": "eslint index.js",
"format": "prettier --write '**/*.ts'", "package": "ncc build index.js -o dist",
"format-check": "prettier --check '**/*.ts'", "test": "eslint index.js && jest --passWithNoTests"
"lint": "eslint src/**/*.ts",
"test": "jest --passWithNoTests"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/peter-evans/create-or-update-comment.git" "url": "git+https://github.com/peter-evans/create-or-update-comment.git"
}, },
"keywords": [ "keywords": [],
"actions",
"create",
"update",
"comment"
],
"author": "Peter Evans", "author": "Peter Evans",
"license": "MIT", "license": "MIT",
"bugs": { "bugs": {
@ -27,24 +20,12 @@
}, },
"homepage": "https://github.com/peter-evans/create-or-update-comment#readme", "homepage": "https://github.com/peter-evans/create-or-update-comment#readme",
"dependencies": { "dependencies": {
"@actions/core": "^1.11.1", "@actions/core": "^1.10.0",
"@actions/github": "^6.0.0" "@actions/github": "^5.1.1"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^27.0.3", "@vercel/ncc": "^0.32.0",
"@types/node": "^18.19.86", "eslint": "^8.3.0",
"@typescript-eslint/eslint-plugin": "^5.62.0", "jest": "^27.4.3"
"@typescript-eslint/parser": "^5.62.0",
"@vercel/ncc": "^0.38.3",
"eslint": "^8.57.1",
"eslint-plugin-github": "^4.10.2",
"eslint-plugin-jest": "^27.9.0",
"eslint-plugin-prettier": "^5.2.6",
"jest": "^27.5.1",
"jest-circus": "^27.5.1",
"js-yaml": "^4.1.0",
"prettier": "^3.5.3",
"ts-jest": "^27.1.5",
"typescript": "^4.9.5"
} }
} }

View File

@ -1,282 +0,0 @@
import * as core from '@actions/core'
import * as github from '@actions/github'
import * as utils from './utils'
import {inspect} from 'util'
export interface Inputs {
token: string
repository: string
issueNumber: number
commentId: number
body: string
bodyPath: string
editMode: string
appendSeparator: string
reactions: string[]
reactionsEditMode: string
}
const REACTION_TYPES = [
'+1',
'-1',
'laugh',
'confused',
'heart',
'hooray',
'rocket',
'eyes'
]
function getReactionsSet(reactions: string[]): string[] {
const reactionsSet = [
...new Set(
reactions.filter(item => {
if (!REACTION_TYPES.includes(item)) {
core.warning(`Skipping invalid reaction '${item}'.`)
return false
}
return true
})
)
]
if (!reactionsSet) {
throw new Error(`No valid reactions are contained in '${reactions}'.`)
}
return reactionsSet
}
async function addReactions(
octokit,
owner: string,
repo: string,
commentId: number,
reactions: string[]
) {
const results = await Promise.allSettled(
reactions.map(async reaction => {
await octokit.rest.reactions.createForIssueComment({
owner: owner,
repo: repo,
comment_id: commentId,
content: reaction
})
core.info(`Setting '${reaction}' reaction on comment.`)
})
)
for (let i = 0, l = results.length; i < l; i++) {
if (results[i].status === 'fulfilled') {
core.info(
`Added reaction '${reactions[i]}' to comment id '${commentId}'.`
)
} else if (results[i].status === 'rejected') {
core.warning(
`Adding reaction '${reactions[i]}' to comment id '${commentId}' failed.`
)
}
}
}
async function removeReactions(
octokit,
owner: string,
repo: string,
commentId: number,
reactions: Reaction[]
) {
const results = await Promise.allSettled(
reactions.map(async reaction => {
await octokit.rest.reactions.deleteForIssueComment({
owner: owner,
repo: repo,
comment_id: commentId,
reaction_id: reaction.id
})
core.info(`Removing '${reaction.content}' reaction from comment.`)
})
)
for (let i = 0, l = results.length; i < l; i++) {
if (results[i].status === 'fulfilled') {
core.info(
`Removed reaction '${reactions[i].content}' from comment id '${commentId}'.`
)
} else if (results[i].status === 'rejected') {
core.warning(
`Removing reaction '${reactions[i].content}' from comment id '${commentId}' failed.`
)
}
}
}
function appendSeparatorTo(body: string, separator: string): string {
switch (separator) {
case 'newline':
return body + '\n'
case 'space':
return body + ' '
default: // none
return body
}
}
function truncateBody(body: string) {
// 65536 characters is the maximum allowed for issue comments.
const truncateWarning = '...*[Comment body truncated]*'
if (body.length > 65536) {
core.warning(`Comment body is too long. Truncating to 65536 characters.`)
return body.substring(0, 65536 - truncateWarning.length) + truncateWarning
}
return body
}
async function createComment(
octokit,
owner: string,
repo: string,
issueNumber: number,
body: string
): Promise<number> {
body = truncateBody(body)
const {data: comment} = await octokit.rest.issues.createComment({
owner: owner,
repo: repo,
issue_number: issueNumber,
body
})
core.info(`Created comment id '${comment.id}' on issue '${issueNumber}'.`)
return comment.id
}
async function updateComment(
octokit,
owner: string,
repo: string,
commentId: number,
body: string,
editMode: string,
appendSeparator: string
): Promise<number> {
if (body) {
let commentBody = ''
if (editMode == 'append') {
// Get the comment body
const {data: comment} = await octokit.rest.issues.getComment({
owner: owner,
repo: repo,
comment_id: commentId
})
commentBody = appendSeparatorTo(
comment.body ? comment.body : '',
appendSeparator
)
}
commentBody = truncateBody(commentBody + body)
core.debug(`Comment body: ${commentBody}`)
await octokit.rest.issues.updateComment({
owner: owner,
repo: repo,
comment_id: commentId,
body: commentBody
})
core.info(`Updated comment id '${commentId}'.`)
}
return commentId
}
async function getAuthenticatedUser(octokit): Promise<string> {
try {
const {data: user} = await octokit.rest.users.getAuthenticated()
return user.login
} catch (error) {
if (
utils
.getErrorMessage(error)
.includes('Resource not accessible by integration')
) {
// In this case we can assume the token is the default GITHUB_TOKEN and
// therefore the user is 'github-actions[bot]'.
return 'github-actions[bot]'
} else {
throw error
}
}
}
type Reaction = {
id: number
content: string
}
async function getCommentReactionsForUser(
octokit,
owner: string,
repo: string,
commentId: number,
user: string
): Promise<Reaction[]> {
const userReactions: Reaction[] = []
for await (const {data: reactions} of octokit.paginate.iterator(
octokit.rest.reactions.listForIssueComment,
{
owner,
repo,
comment_id: commentId,
per_page: 100
}
)) {
const filteredReactions: Reaction[] = reactions
.filter(reaction => reaction.user.login === user)
.map(reaction => {
return {id: reaction.id, content: reaction.content}
})
userReactions.push(...filteredReactions)
}
return userReactions
}
export async function createOrUpdateComment(
inputs: Inputs,
body: string
): Promise<void> {
const [owner, repo] = inputs.repository.split('/')
const octokit = github.getOctokit(inputs.token)
const commentId = inputs.commentId
? await updateComment(
octokit,
owner,
repo,
inputs.commentId,
body,
inputs.editMode,
inputs.appendSeparator
)
: await createComment(octokit, owner, repo, inputs.issueNumber, body)
core.setOutput('comment-id', commentId)
if (inputs.reactions) {
const reactionsSet = getReactionsSet(inputs.reactions)
// Remove reactions if reactionsEditMode is 'replace'
if (inputs.commentId && inputs.reactionsEditMode === 'replace') {
const authenticatedUser = await getAuthenticatedUser(octokit)
const userReactions = await getCommentReactionsForUser(
octokit,
owner,
repo,
commentId,
authenticatedUser
)
core.debug(inspect(userReactions))
const reactionsToRemove = userReactions.filter(
reaction => !reactionsSet.includes(reaction.content)
)
await removeReactions(octokit, owner, repo, commentId, reactionsToRemove)
}
await addReactions(octokit, owner, repo, commentId, reactionsSet)
}
}

View File

@ -1,82 +0,0 @@
import * as core from '@actions/core'
import {Inputs, createOrUpdateComment} from './create-or-update-comment'
import {existsSync, readFileSync} from 'fs'
import {inspect} from 'util'
import * as utils from './utils'
function getBody(inputs: Inputs) {
if (inputs.body) {
return inputs.body
} else if (inputs.bodyPath) {
return readFileSync(inputs.bodyPath, 'utf-8')
} else {
return ''
}
}
async function run(): Promise<void> {
try {
const inputs: Inputs = {
token: core.getInput('token'),
repository: core.getInput('repository'),
issueNumber: Number(core.getInput('issue-number')),
commentId: Number(core.getInput('comment-id')),
body: core.getInput('body'),
bodyPath: core.getInput('body-path') || core.getInput('body-file'),
editMode: core.getInput('edit-mode'),
appendSeparator: core.getInput('append-separator'),
reactions: utils.getInputAsArray('reactions'),
reactionsEditMode: core.getInput('reactions-edit-mode')
}
core.debug(`Inputs: ${inspect(inputs)}`)
if (!['append', 'replace'].includes(inputs.editMode)) {
throw new Error(`Invalid edit-mode '${inputs.editMode}'.`)
}
if (!['append', 'replace'].includes(inputs.reactionsEditMode)) {
throw new Error(
`Invalid reactions edit-mode '${inputs.reactionsEditMode}'.`
)
}
if (!['newline', 'space', 'none'].includes(inputs.appendSeparator)) {
throw new Error(`Invalid append-separator '${inputs.appendSeparator}'.`)
}
if (inputs.bodyPath && inputs.body) {
throw new Error("Only one of 'body' or 'body-path' can be set.")
}
if (inputs.bodyPath) {
if (!existsSync(inputs.bodyPath)) {
throw new Error(`File '${inputs.bodyPath}' does not exist.`)
}
}
const body = getBody(inputs)
if (inputs.commentId) {
if (!body && !inputs.reactions) {
throw new Error("Missing comment 'body', 'body-path', or 'reactions'.")
}
} else if (inputs.issueNumber) {
if (!body) {
throw new Error("Missing comment 'body' or 'body-path'.")
}
} else {
throw new Error("Missing either 'issue-number' or 'comment-id'.")
}
createOrUpdateComment(inputs, body)
} catch (error) {
core.debug(inspect(error))
const errMsg = utils.getErrorMessage(error)
core.setFailed(errMsg)
if (errMsg == 'Resource not accessible by integration') {
core.error(`See this action's readme for details about this error`)
}
}
}
run()

View File

@ -1,20 +0,0 @@
import * as core from '@actions/core'
export function getInputAsArray(
name: string,
options?: core.InputOptions
): string[] {
return getStringAsArray(core.getInput(name, options))
}
export function getStringAsArray(str: string): string[] {
return str
.split(/[\n,]+/)
.map(s => s.trim())
.filter(x => x !== '')
}
export function getErrorMessage(error: unknown) {
if (error instanceof Error) return error.message
return String(error)
}

View File

@ -1,16 +0,0 @@
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"lib": [
"es6"
],
"outDir": "./lib",
"rootDir": "./src",
"declaration": true,
"strict": true,
"noImplicitAny": false,
"esModuleInterop": true
},
"exclude": ["__test__", "lib", "node_modules"]
}