mirror of
https://github.com/mshick/add-pr-comment.git
synced 2026-01-01 06:29:49 +11:00
Add sticky comment feature and ID based reference. (#61)
* sticky comment feature * remove unused param
This commit is contained in:
parent
f9a5a1c8cb
commit
3aa992a9b5
8 changed files with 212 additions and 180 deletions
2
.github/workflows/integration.yml
vendored
2
.github/workflows/integration.yml
vendored
|
|
@ -57,7 +57,7 @@ jobs:
|
||||||
- uses: ./
|
- uses: ./
|
||||||
with:
|
with:
|
||||||
message: |
|
message: |
|
||||||
**Hello**
|
**Hello ${{ github.run_number }}**
|
||||||
🌏
|
🌏
|
||||||
!
|
!
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
|
||||||
35
README.md
35
README.md
|
|
@ -4,12 +4,14 @@
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Fast, runs in the GitHub Actions node.js runtime; no Docker pull needed.
|
- Fast, runs in the GitHub Actions node.js runtime.
|
||||||
- Modify issues for PRs merged to master.
|
- Modify issues for PRs merged to main.
|
||||||
|
- By default will post "sticky" comments. If on a subsequent run the message text changes the original comment will be updated.
|
||||||
|
- Multiple sticky comments allowed by setting unique `message-id`s.
|
||||||
- Multiple posts of the same comment optionally allowable.
|
- Multiple posts of the same comment optionally allowable.
|
||||||
- Supports emoji 😂😂😂!
|
- Supports emoji 😂😂😂!
|
||||||
- Supports a proxy for fork-based PRs. [See below](#proxy-for-fork-based-prs).
|
- Supports a proxy for fork-based PRs. [See below](#proxy-for-fork-based-prs).
|
||||||
- Supports creating a message from a file path
|
- Supports creating a message from a file path.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
|
@ -32,17 +34,17 @@ jobs:
|
||||||
🌏
|
🌏
|
||||||
!
|
!
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
repo-token-user-login: 'github-actions[bot]' # The user.login for temporary GitHub tokens
|
|
||||||
allow-repeats: false # This is the default
|
allow-repeats: false # This is the default
|
||||||
|
message-id: 'add-pr-comment' # This is the default
|
||||||
```
|
```
|
||||||
|
|
||||||
You can even use it on PR Issues that are related to PRs that were merged into master, for example:
|
You can even use it on PR Issues that are related to PRs that were merged into main, for example:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
|
|
@ -55,21 +57,20 @@ jobs:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
message: |
|
message: |
|
||||||
**Hello MASTER**
|
**Hello MAIN**
|
||||||
allow-repeats: true
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration options
|
## Configuration options
|
||||||
|
|
||||||
| Variable or Argument | Location | Description | Required | Default |
|
| Variable or Argument | Location | Description | Required | Default |
|
||||||
| --------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------- | -------- | ------- |
|
| -------------------- | -------- | ---------------------------------------------------------------------------------------------------- | -------- | ------- |
|
||||||
| message | with | The message you'd like displayed, supports Markdown and all valid Unicode characters | maybe | |
|
| message | with | The message you'd like displayed, supports Markdown and all valid Unicode characters. | maybe | |
|
||||||
| message-path | with | A path to a message you'd like displayed. Will be read and displayed just like a normal message | maybe | |
|
| message-path | with | Path to a message you'd like displayed. Will be read and displayed just like a normal message. | maybe | |
|
||||||
| repo-token | with | A valid GitHub token, either the temporary token GitHub provides or a personal access token | maybe | |
|
| repo-token | with | Valid GitHub token, either the temporary token GitHub provides or a personal access token. | maybe | |
|
||||||
| repo-token-user-login | with | Define this to save on comment processing time when checking for repeats. GitHub's default token uses `github-actions[bot]` | no | |
|
| message-id | with | Message id to use when searching existing comments. If found, updates the existing (sticky comment). | no | |
|
||||||
| allow-repeats | with | A boolean flag to allow identical messages to be posted each time this action is run | no | false |
|
| allow-repeats | with | Boolean flag to allow identical messages to be posted each time this action is run. | no | false |
|
||||||
| proxy-url | with | A string for your proxy service URL if you'd like this to work with fork-based PRs | no | |
|
| proxy-url | with | String for your proxy service URL if you'd like this to work with fork-based PRs. | no | |
|
||||||
| GITHUB_TOKEN | env | A valid GitHub token, can alternatively be defined in the env | maybe | |
|
| GITHUB_TOKEN | env | Valid GitHub token, can alternatively be defined in the env. | maybe | |
|
||||||
|
|
||||||
## Proxy for Fork-based PRs
|
## Proxy for Fork-based PRs
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import * as github from '@actions/github'
|
||||||
import { WebhookPayload } from '@actions/github/lib/interfaces'
|
import { WebhookPayload } from '@actions/github/lib/interfaces'
|
||||||
import { rest } from 'msw'
|
import { rest } from 'msw'
|
||||||
import { setupServer } from 'msw/node'
|
import { setupServer } from 'msw/node'
|
||||||
import * as fs from 'node:fs'
|
|
||||||
import * as path from 'node:path'
|
import * as path from 'node:path'
|
||||||
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'
|
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||||
import run from '../src/main'
|
import run from '../src/main'
|
||||||
|
|
@ -11,21 +10,14 @@ import apiResponse from './sample-pulls-api-response.json'
|
||||||
|
|
||||||
const repoFullName = 'foo/bar'
|
const repoFullName = 'foo/bar'
|
||||||
const repoToken = '12345'
|
const repoToken = '12345'
|
||||||
const userLogin = 'github-actions[bot]'
|
|
||||||
const commitSha = 'abc123'
|
const commitSha = 'abc123'
|
||||||
const simpleMessage = 'hello world'
|
const simpleMessage = 'hello world'
|
||||||
const multilineMessage = fs
|
|
||||||
.readFileSync(path.resolve(__dirname, './message-windows.txt'))
|
|
||||||
.toString()
|
|
||||||
const multilineMessageWindows = fs
|
|
||||||
.readFileSync(path.resolve(__dirname, './message-windows.txt'))
|
|
||||||
.toString()
|
|
||||||
|
|
||||||
type Inputs = {
|
type Inputs = {
|
||||||
message: string | undefined
|
message: string | undefined
|
||||||
'message-path': string | undefined
|
'message-path': string | undefined
|
||||||
'repo-token': string
|
'repo-token': string
|
||||||
'repo-token-user-login': string
|
'message-id': string
|
||||||
'allow-repeats': string
|
'allow-repeats': string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -33,14 +25,14 @@ const inputs: Inputs = {
|
||||||
message: '',
|
message: '',
|
||||||
'message-path': undefined,
|
'message-path': undefined,
|
||||||
'repo-token': '',
|
'repo-token': '',
|
||||||
'repo-token-user-login': '',
|
'message-id': 'add-pr-comment',
|
||||||
'allow-repeats': 'false',
|
'allow-repeats': 'false',
|
||||||
}
|
}
|
||||||
|
|
||||||
let issueNumber = 1
|
let issueNumber = 1
|
||||||
let getCommitPullsResponse
|
let getCommitPullsResponse
|
||||||
let getIssueCommentsResponse
|
let getIssueCommentsResponse
|
||||||
const postIssueCommentsResponse = {
|
let postIssueCommentsResponse = {
|
||||||
id: 42,
|
id: 42,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -53,6 +45,12 @@ export const handlers = [
|
||||||
return res(ctx.status(200), ctx.json(postIssueCommentsResponse))
|
return res(ctx.status(200), ctx.json(postIssueCommentsResponse))
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
rest.patch(
|
||||||
|
`https://api.github.com/repos/${repoFullName}/issues/comments/:commentId`,
|
||||||
|
(req, res, ctx) => {
|
||||||
|
return res(ctx.status(200), ctx.json(postIssueCommentsResponse))
|
||||||
|
},
|
||||||
|
),
|
||||||
rest.get(
|
rest.get(
|
||||||
`https://api.github.com/repos/${repoFullName}/issues/:issueNumber/comments`,
|
`https://api.github.com/repos/${repoFullName}/issues/:issueNumber/comments`,
|
||||||
(req, res, ctx) => {
|
(req, res, ctx) => {
|
||||||
|
|
@ -182,19 +180,16 @@ describe('add-pr-comment action', () => {
|
||||||
expect(core.setOutput).toHaveBeenCalledWith('comment-created', 'false')
|
expect(core.setOutput).toHaveBeenCalledWith('comment-created', 'false')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('identifies repeat messages and does not create a comment [user login provided]', async () => {
|
it('creates a message when the message id does not exist', async () => {
|
||||||
inputs.message = simpleMessage
|
inputs.message = simpleMessage
|
||||||
inputs['message-path'] = undefined
|
inputs['message-path'] = undefined
|
||||||
inputs['repo-token'] = repoToken
|
inputs['repo-token'] = repoToken
|
||||||
inputs['repo-token-user-login'] = userLogin
|
|
||||||
inputs['allow-repeats'] = 'false'
|
inputs['allow-repeats'] = 'false'
|
||||||
|
inputs['message-id'] = 'custom-id'
|
||||||
|
|
||||||
const replyBody = [
|
const replyBody = [
|
||||||
{
|
{
|
||||||
body: simpleMessage,
|
body: `<!-- some-other-id -->\n\n${simpleMessage}`,
|
||||||
user: {
|
|
||||||
login: userLogin,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -202,27 +197,32 @@ describe('add-pr-comment action', () => {
|
||||||
|
|
||||||
await run()
|
await run()
|
||||||
|
|
||||||
expect(core.setOutput).toHaveBeenCalledWith('comment-created', 'false')
|
expect(core.setOutput).toHaveBeenCalledWith('comment-created', 'true')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('matches multiline messages with windows line feeds against api responses with unix linefeeds [no user login provided]', async () => {
|
it('identifies an existing message by id and updates it', async () => {
|
||||||
inputs.message = multilineMessageWindows
|
inputs.message = simpleMessage
|
||||||
inputs['message-path'] = undefined
|
inputs['message-path'] = undefined
|
||||||
inputs['repo-token'] = repoToken
|
inputs['repo-token'] = repoToken
|
||||||
inputs['allow-repeats'] = 'false'
|
inputs['allow-repeats'] = 'false'
|
||||||
|
|
||||||
|
const commentId = 123
|
||||||
|
|
||||||
const replyBody = [
|
const replyBody = [
|
||||||
{
|
{
|
||||||
body: multilineMessage,
|
id: commentId,
|
||||||
user: {
|
body: `<!-- ${inputs['message-id']} -->\n\n${simpleMessage}`,
|
||||||
login: userLogin,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
getIssueCommentsResponse = replyBody
|
getIssueCommentsResponse = replyBody
|
||||||
|
postIssueCommentsResponse = {
|
||||||
|
id: commentId,
|
||||||
|
}
|
||||||
|
|
||||||
await run()
|
await run()
|
||||||
expect(core.setOutput).toHaveBeenCalledWith('comment-created', 'false')
|
|
||||||
|
expect(core.setOutput).toHaveBeenCalledWith('comment-updated', 'true')
|
||||||
|
expect(core.setOutput).toHaveBeenCalledWith('comment-id', commentId)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
11
action.yml
11
action.yml
|
|
@ -7,12 +7,13 @@ inputs:
|
||||||
message-path:
|
message-path:
|
||||||
description: "A path to a file to print as a message instead of a string."
|
description: "A path to a file to print as a message instead of a string."
|
||||||
required: false
|
required: false
|
||||||
|
message-id:
|
||||||
|
description: "An optional id to use for this message."
|
||||||
|
required: false
|
||||||
|
default: "add-pr-comment"
|
||||||
repo-token:
|
repo-token:
|
||||||
description: "A GitHub token for API access."
|
description: "A GitHub token for API access."
|
||||||
required: false
|
required: false
|
||||||
repo-token-user-login:
|
|
||||||
description: "A user login associated with your token, for temporary repo tokens this is `github-actions[bot]`."
|
|
||||||
required: false
|
|
||||||
allow-repeats:
|
allow-repeats:
|
||||||
description: "Allow messages to be repeated."
|
description: "Allow messages to be repeated."
|
||||||
required: false
|
required: false
|
||||||
|
|
@ -23,8 +24,10 @@ inputs:
|
||||||
outputs:
|
outputs:
|
||||||
comment-created:
|
comment-created:
|
||||||
description: "Whether a comment was created."
|
description: "Whether a comment was created."
|
||||||
|
comment-updated:
|
||||||
|
description: "Whether a comment was updated."
|
||||||
comment-id:
|
comment-id:
|
||||||
description: "If a comment was created, the id of it."
|
description: "If a comment was created or updated, it's id."
|
||||||
branding:
|
branding:
|
||||||
icon: message-circle
|
icon: message-circle
|
||||||
color: purple
|
color: purple
|
||||||
|
|
|
||||||
90
dist/index.js
vendored
90
dist/index.js
vendored
|
|
@ -39,37 +39,35 @@ const http_client_1 = __nccwpck_require__(6255);
|
||||||
const promises_1 = __importDefault(__nccwpck_require__(3977));
|
const promises_1 = __importDefault(__nccwpck_require__(3977));
|
||||||
const getIssueNumberFromCommitPullsList = (commitPullsList) => (commitPullsList.length ? commitPullsList[0].number : null);
|
const getIssueNumberFromCommitPullsList = (commitPullsList) => (commitPullsList.length ? commitPullsList[0].number : null);
|
||||||
const createCommentProxy = async (params) => {
|
const createCommentProxy = async (params) => {
|
||||||
const { repoToken, owner, repo, issueNumber, body, proxyUrl } = params;
|
const { repoToken, owner, repo, issueNumber, body, commentId, proxyUrl } = params;
|
||||||
const http = new http_client_1.HttpClient('http-client-add-pr-comment');
|
const http = new http_client_1.HttpClient('http-client-add-pr-comment');
|
||||||
const response = await http.postJson(`${proxyUrl}/repos/${owner}/${repo}/issues/${issueNumber}/comments`, { body }, {
|
const response = await http.postJson(`${proxyUrl}/repos/${owner}/${repo}/issues/${issueNumber}/comments`, { comment_id: commentId, body }, {
|
||||||
['temporary-github-token']: repoToken,
|
['temporary-github-token']: repoToken,
|
||||||
});
|
});
|
||||||
return response.result;
|
return response.result;
|
||||||
};
|
};
|
||||||
const isMessagePresent = (message, comments, login) => {
|
const getExistingCommentId = (comments, messageId) => {
|
||||||
const cleanRe = new RegExp('\\R|\\s', 'g');
|
const found = comments.find(({ body }) => {
|
||||||
const messageClean = message.replace(cleanRe, '');
|
var _a;
|
||||||
return comments.some(({ user, body }) => {
|
return ((_a = body === null || body === void 0 ? void 0 : body.search(messageId)) !== null && _a !== void 0 ? _a : -1) > -1;
|
||||||
// If a username is provided we can save on a bit of processing
|
|
||||||
if (login && (user === null || user === void 0 ? void 0 : user.login) !== login) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return (body === null || body === void 0 ? void 0 : body.replace(cleanRe, '')) === messageClean;
|
|
||||||
});
|
});
|
||||||
|
return found === null || found === void 0 ? void 0 : found.id;
|
||||||
};
|
};
|
||||||
const getInputs = () => {
|
const getInputs = () => {
|
||||||
|
const messageId = core.getInput('message-id');
|
||||||
return {
|
return {
|
||||||
allowRepeats: Boolean(core.getInput('allow-repeats') === 'true'),
|
allowRepeats: Boolean(core.getInput('allow-repeats') === 'true'),
|
||||||
message: core.getInput('message'),
|
message: core.getInput('message'),
|
||||||
|
messageId: messageId === '' ? 'add-pr-comment' : messageId,
|
||||||
messagePath: core.getInput('message-path'),
|
messagePath: core.getInput('message-path'),
|
||||||
proxyUrl: core.getInput('proxy-url').replace(/\/$/, ''),
|
proxyUrl: core.getInput('proxy-url').replace(/\/$/, ''),
|
||||||
repoToken: core.getInput('repo-token') || process.env['GITHUB_TOKEN'],
|
repoToken: core.getInput('repo-token') || process.env['GITHUB_TOKEN'],
|
||||||
repoTokenUserLogin: core.getInput('repo-token-user-login'),
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
const run = async () => {
|
const run = async () => {
|
||||||
try {
|
try {
|
||||||
const { allowRepeats, message, messagePath, repoToken, repoTokenUserLogin, proxyUrl } = getInputs();
|
const { allowRepeats, message, messageId, messagePath, repoToken, proxyUrl } = getInputs();
|
||||||
|
const messageIdComment = `<!-- ${messageId} -->`;
|
||||||
if (!repoToken) {
|
if (!repoToken) {
|
||||||
throw new Error('no github token provided, set one with the repo-token input or GITHUB_TOKEN env variable');
|
throw new Error('no github token provided, set one with the repo-token input or GITHUB_TOKEN env variable');
|
||||||
}
|
}
|
||||||
|
|
@ -118,7 +116,7 @@ const run = async () => {
|
||||||
core.setOutput('comment-created', 'false');
|
core.setOutput('comment-created', 'false');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let shouldCreateComment = true;
|
let existingCommentId;
|
||||||
if (!allowRepeats) {
|
if (!allowRepeats) {
|
||||||
core.debug('repeat comments are disallowed, checking for existing');
|
core.debug('repeat comments are disallowed, checking for existing');
|
||||||
const { data: comments } = await octokit.rest.issues.listComments({
|
const { data: comments } = await octokit.rest.issues.listComments({
|
||||||
|
|
@ -126,39 +124,51 @@ const run = async () => {
|
||||||
repo,
|
repo,
|
||||||
issue_number: issueNumber,
|
issue_number: issueNumber,
|
||||||
});
|
});
|
||||||
if (isMessagePresent(message, comments, repoTokenUserLogin)) {
|
existingCommentId = getExistingCommentId(comments, messageIdComment);
|
||||||
core.info('the issue already contains an identical message');
|
if (existingCommentId) {
|
||||||
shouldCreateComment = false;
|
core.debug(`existing comment found with id: ${existingCommentId}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let createdCommentData;
|
let comment;
|
||||||
if (shouldCreateComment) {
|
const body = `${messageIdComment}\n\n${messageText}`;
|
||||||
if (proxyUrl) {
|
if (proxyUrl) {
|
||||||
createdCommentData = await createCommentProxy({
|
comment = await createCommentProxy({
|
||||||
owner,
|
commentId: existingCommentId,
|
||||||
repo,
|
owner,
|
||||||
issueNumber,
|
repo,
|
||||||
body: message,
|
issueNumber,
|
||||||
repoToken,
|
body,
|
||||||
proxyUrl,
|
repoToken,
|
||||||
});
|
proxyUrl,
|
||||||
}
|
});
|
||||||
else {
|
core.setOutput(existingCommentId ? 'comment-updated' : 'comment-created', 'true');
|
||||||
const createdComment = await octokit.rest.issues.createComment({
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
issue_number: issueNumber,
|
|
||||||
body: message,
|
|
||||||
});
|
|
||||||
createdCommentData = createdComment.data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (createdCommentData) {
|
else if (existingCommentId) {
|
||||||
|
const updatedComment = await octokit.rest.issues.updateComment({
|
||||||
|
comment_id: existingCommentId,
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
body,
|
||||||
|
});
|
||||||
|
comment = updatedComment.data;
|
||||||
|
core.setOutput('comment-updated', 'true');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const createdComment = await octokit.rest.issues.createComment({
|
||||||
|
issue_number: issueNumber,
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
body,
|
||||||
|
});
|
||||||
|
comment = createdComment.data;
|
||||||
core.setOutput('comment-created', 'true');
|
core.setOutput('comment-created', 'true');
|
||||||
core.setOutput('comment-id', createdCommentData.id);
|
}
|
||||||
|
if (comment) {
|
||||||
|
core.setOutput('comment-id', comment.id);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
core.setOutput('comment-created', 'false');
|
core.setOutput('comment-created', 'false');
|
||||||
|
core.setOutput('comment-updated', 'false');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
|
|
|
||||||
2
dist/index.js.map
vendored
2
dist/index.js.map
vendored
File diff suppressed because one or more lines are too long
90
lib/main.js
90
lib/main.js
|
|
@ -32,37 +32,35 @@ const http_client_1 = require("@actions/http-client");
|
||||||
const promises_1 = __importDefault(require("node:fs/promises"));
|
const promises_1 = __importDefault(require("node:fs/promises"));
|
||||||
const getIssueNumberFromCommitPullsList = (commitPullsList) => (commitPullsList.length ? commitPullsList[0].number : null);
|
const getIssueNumberFromCommitPullsList = (commitPullsList) => (commitPullsList.length ? commitPullsList[0].number : null);
|
||||||
const createCommentProxy = async (params) => {
|
const createCommentProxy = async (params) => {
|
||||||
const { repoToken, owner, repo, issueNumber, body, proxyUrl } = params;
|
const { repoToken, owner, repo, issueNumber, body, commentId, proxyUrl } = params;
|
||||||
const http = new http_client_1.HttpClient('http-client-add-pr-comment');
|
const http = new http_client_1.HttpClient('http-client-add-pr-comment');
|
||||||
const response = await http.postJson(`${proxyUrl}/repos/${owner}/${repo}/issues/${issueNumber}/comments`, { body }, {
|
const response = await http.postJson(`${proxyUrl}/repos/${owner}/${repo}/issues/${issueNumber}/comments`, { comment_id: commentId, body }, {
|
||||||
['temporary-github-token']: repoToken,
|
['temporary-github-token']: repoToken,
|
||||||
});
|
});
|
||||||
return response.result;
|
return response.result;
|
||||||
};
|
};
|
||||||
const isMessagePresent = (message, comments, login) => {
|
const getExistingCommentId = (comments, messageId) => {
|
||||||
const cleanRe = new RegExp('\\R|\\s', 'g');
|
const found = comments.find(({ body }) => {
|
||||||
const messageClean = message.replace(cleanRe, '');
|
var _a;
|
||||||
return comments.some(({ user, body }) => {
|
return ((_a = body === null || body === void 0 ? void 0 : body.search(messageId)) !== null && _a !== void 0 ? _a : -1) > -1;
|
||||||
// If a username is provided we can save on a bit of processing
|
|
||||||
if (login && (user === null || user === void 0 ? void 0 : user.login) !== login) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return (body === null || body === void 0 ? void 0 : body.replace(cleanRe, '')) === messageClean;
|
|
||||||
});
|
});
|
||||||
|
return found === null || found === void 0 ? void 0 : found.id;
|
||||||
};
|
};
|
||||||
const getInputs = () => {
|
const getInputs = () => {
|
||||||
|
const messageId = core.getInput('message-id');
|
||||||
return {
|
return {
|
||||||
allowRepeats: Boolean(core.getInput('allow-repeats') === 'true'),
|
allowRepeats: Boolean(core.getInput('allow-repeats') === 'true'),
|
||||||
message: core.getInput('message'),
|
message: core.getInput('message'),
|
||||||
|
messageId: messageId === '' ? 'add-pr-comment' : messageId,
|
||||||
messagePath: core.getInput('message-path'),
|
messagePath: core.getInput('message-path'),
|
||||||
proxyUrl: core.getInput('proxy-url').replace(/\/$/, ''),
|
proxyUrl: core.getInput('proxy-url').replace(/\/$/, ''),
|
||||||
repoToken: core.getInput('repo-token') || process.env['GITHUB_TOKEN'],
|
repoToken: core.getInput('repo-token') || process.env['GITHUB_TOKEN'],
|
||||||
repoTokenUserLogin: core.getInput('repo-token-user-login'),
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
const run = async () => {
|
const run = async () => {
|
||||||
try {
|
try {
|
||||||
const { allowRepeats, message, messagePath, repoToken, repoTokenUserLogin, proxyUrl } = getInputs();
|
const { allowRepeats, message, messageId, messagePath, repoToken, proxyUrl } = getInputs();
|
||||||
|
const messageIdComment = `<!-- ${messageId} -->`;
|
||||||
if (!repoToken) {
|
if (!repoToken) {
|
||||||
throw new Error('no github token provided, set one with the repo-token input or GITHUB_TOKEN env variable');
|
throw new Error('no github token provided, set one with the repo-token input or GITHUB_TOKEN env variable');
|
||||||
}
|
}
|
||||||
|
|
@ -111,7 +109,7 @@ const run = async () => {
|
||||||
core.setOutput('comment-created', 'false');
|
core.setOutput('comment-created', 'false');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let shouldCreateComment = true;
|
let existingCommentId;
|
||||||
if (!allowRepeats) {
|
if (!allowRepeats) {
|
||||||
core.debug('repeat comments are disallowed, checking for existing');
|
core.debug('repeat comments are disallowed, checking for existing');
|
||||||
const { data: comments } = await octokit.rest.issues.listComments({
|
const { data: comments } = await octokit.rest.issues.listComments({
|
||||||
|
|
@ -119,39 +117,51 @@ const run = async () => {
|
||||||
repo,
|
repo,
|
||||||
issue_number: issueNumber,
|
issue_number: issueNumber,
|
||||||
});
|
});
|
||||||
if (isMessagePresent(message, comments, repoTokenUserLogin)) {
|
existingCommentId = getExistingCommentId(comments, messageIdComment);
|
||||||
core.info('the issue already contains an identical message');
|
if (existingCommentId) {
|
||||||
shouldCreateComment = false;
|
core.debug(`existing comment found with id: ${existingCommentId}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let createdCommentData;
|
let comment;
|
||||||
if (shouldCreateComment) {
|
const body = `${messageIdComment}\n\n${messageText}`;
|
||||||
if (proxyUrl) {
|
if (proxyUrl) {
|
||||||
createdCommentData = await createCommentProxy({
|
comment = await createCommentProxy({
|
||||||
owner,
|
commentId: existingCommentId,
|
||||||
repo,
|
owner,
|
||||||
issueNumber,
|
repo,
|
||||||
body: message,
|
issueNumber,
|
||||||
repoToken,
|
body,
|
||||||
proxyUrl,
|
repoToken,
|
||||||
});
|
proxyUrl,
|
||||||
}
|
});
|
||||||
else {
|
core.setOutput(existingCommentId ? 'comment-updated' : 'comment-created', 'true');
|
||||||
const createdComment = await octokit.rest.issues.createComment({
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
issue_number: issueNumber,
|
|
||||||
body: message,
|
|
||||||
});
|
|
||||||
createdCommentData = createdComment.data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (createdCommentData) {
|
else if (existingCommentId) {
|
||||||
|
const updatedComment = await octokit.rest.issues.updateComment({
|
||||||
|
comment_id: existingCommentId,
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
body,
|
||||||
|
});
|
||||||
|
comment = updatedComment.data;
|
||||||
|
core.setOutput('comment-updated', 'true');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const createdComment = await octokit.rest.issues.createComment({
|
||||||
|
issue_number: issueNumber,
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
body,
|
||||||
|
});
|
||||||
|
comment = createdComment.data;
|
||||||
core.setOutput('comment-created', 'true');
|
core.setOutput('comment-created', 'true');
|
||||||
core.setOutput('comment-id', createdCommentData.id);
|
}
|
||||||
|
if (comment) {
|
||||||
|
core.setOutput('comment-id', comment.id);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
core.setOutput('comment-created', 'false');
|
core.setOutput('comment-created', 'false');
|
||||||
|
core.setOutput('comment-updated', 'false');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
|
|
|
||||||
108
src/main.ts
108
src/main.ts
|
|
@ -17,6 +17,7 @@ const getIssueNumberFromCommitPullsList = (
|
||||||
|
|
||||||
interface CreateCommentProxyParams {
|
interface CreateCommentProxyParams {
|
||||||
repoToken: string
|
repoToken: string
|
||||||
|
commentId?: number
|
||||||
body: string
|
body: string
|
||||||
owner: string
|
owner: string
|
||||||
repo: string
|
repo: string
|
||||||
|
|
@ -27,13 +28,13 @@ interface CreateCommentProxyParams {
|
||||||
const createCommentProxy = async (
|
const createCommentProxy = async (
|
||||||
params: CreateCommentProxyParams,
|
params: CreateCommentProxyParams,
|
||||||
): Promise<CreateIssueCommentResponseData | null> => {
|
): Promise<CreateIssueCommentResponseData | null> => {
|
||||||
const { repoToken, owner, repo, issueNumber, body, proxyUrl } = params
|
const { repoToken, owner, repo, issueNumber, body, commentId, proxyUrl } = params
|
||||||
|
|
||||||
const http = new HttpClient('http-client-add-pr-comment')
|
const http = new HttpClient('http-client-add-pr-comment')
|
||||||
|
|
||||||
const response = await http.postJson<CreateIssueCommentResponseData>(
|
const response = await http.postJson<CreateIssueCommentResponseData>(
|
||||||
`${proxyUrl}/repos/${owner}/${repo}/issues/${issueNumber}/comments`,
|
`${proxyUrl}/repos/${owner}/${repo}/issues/${issueNumber}/comments`,
|
||||||
{ body },
|
{ comment_id: commentId, body },
|
||||||
{
|
{
|
||||||
['temporary-github-token']: repoToken,
|
['temporary-github-token']: repoToken,
|
||||||
},
|
},
|
||||||
|
|
@ -42,48 +43,43 @@ const createCommentProxy = async (
|
||||||
return response.result
|
return response.result
|
||||||
}
|
}
|
||||||
|
|
||||||
const isMessagePresent = (
|
const getExistingCommentId = (
|
||||||
message: AddPrCommentInputs['message'],
|
|
||||||
comments: IssuesListCommentsResponseData,
|
comments: IssuesListCommentsResponseData,
|
||||||
login?: string,
|
messageId: string,
|
||||||
): boolean => {
|
): number | undefined => {
|
||||||
const cleanRe = new RegExp('\\R|\\s', 'g')
|
const found = comments.find(({ body }) => {
|
||||||
const messageClean = message.replace(cleanRe, '')
|
return (body?.search(messageId) ?? -1) > -1
|
||||||
|
|
||||||
return comments.some(({ user, body }) => {
|
|
||||||
// If a username is provided we can save on a bit of processing
|
|
||||||
if (login && user?.login !== login) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return body?.replace(cleanRe, '') === messageClean
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return found?.id
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AddPrCommentInputs {
|
interface AddPrCommentInputs {
|
||||||
allowRepeats: boolean
|
allowRepeats: boolean
|
||||||
message: string
|
message?: string
|
||||||
messagePath: string
|
messagePath?: string
|
||||||
proxyUrl?: string
|
proxyUrl?: string
|
||||||
repoToken?: string
|
repoToken?: string
|
||||||
repoTokenUserLogin?: string
|
messageId: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const getInputs = (): AddPrCommentInputs => {
|
const getInputs = (): AddPrCommentInputs => {
|
||||||
|
const messageId = core.getInput('message-id')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
allowRepeats: Boolean(core.getInput('allow-repeats') === 'true'),
|
allowRepeats: Boolean(core.getInput('allow-repeats') === 'true'),
|
||||||
message: core.getInput('message'),
|
message: core.getInput('message'),
|
||||||
|
messageId: messageId === '' ? 'add-pr-comment' : messageId,
|
||||||
messagePath: core.getInput('message-path'),
|
messagePath: core.getInput('message-path'),
|
||||||
proxyUrl: core.getInput('proxy-url').replace(/\/$/, ''),
|
proxyUrl: core.getInput('proxy-url').replace(/\/$/, ''),
|
||||||
repoToken: core.getInput('repo-token') || process.env['GITHUB_TOKEN'],
|
repoToken: core.getInput('repo-token') || process.env['GITHUB_TOKEN'],
|
||||||
repoTokenUserLogin: core.getInput('repo-token-user-login'),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const run = async (): Promise<void> => {
|
const run = async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
const { allowRepeats, message, messagePath, repoToken, repoTokenUserLogin, proxyUrl } =
|
const { allowRepeats, message, messageId, messagePath, repoToken, proxyUrl } = getInputs()
|
||||||
getInputs()
|
const messageIdComment = `<!-- ${messageId} -->`
|
||||||
|
|
||||||
if (!repoToken) {
|
if (!repoToken) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|
@ -151,7 +147,7 @@ const run = async (): Promise<void> => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let shouldCreateComment = true
|
let existingCommentId
|
||||||
|
|
||||||
if (!allowRepeats) {
|
if (!allowRepeats) {
|
||||||
core.debug('repeat comments are disallowed, checking for existing')
|
core.debug('repeat comments are disallowed, checking for existing')
|
||||||
|
|
@ -162,40 +158,52 @@ const run = async (): Promise<void> => {
|
||||||
issue_number: issueNumber,
|
issue_number: issueNumber,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (isMessagePresent(message, comments, repoTokenUserLogin)) {
|
existingCommentId = getExistingCommentId(comments, messageIdComment)
|
||||||
core.info('the issue already contains an identical message')
|
|
||||||
shouldCreateComment = false
|
if (existingCommentId) {
|
||||||
|
core.debug(`existing comment found with id: ${existingCommentId}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let createdCommentData: CreateIssueCommentResponseData | null | undefined
|
let comment: CreateIssueCommentResponseData | null | undefined
|
||||||
|
const body = `${messageIdComment}\n\n${messageText}`
|
||||||
|
|
||||||
if (shouldCreateComment) {
|
if (proxyUrl) {
|
||||||
if (proxyUrl) {
|
comment = await createCommentProxy({
|
||||||
createdCommentData = await createCommentProxy({
|
commentId: existingCommentId,
|
||||||
owner,
|
owner,
|
||||||
repo,
|
repo,
|
||||||
issueNumber,
|
issueNumber,
|
||||||
body: message,
|
body,
|
||||||
repoToken,
|
repoToken,
|
||||||
proxyUrl,
|
proxyUrl,
|
||||||
})
|
})
|
||||||
} else {
|
core.setOutput(existingCommentId ? 'comment-updated' : 'comment-created', 'true')
|
||||||
const createdComment = await octokit.rest.issues.createComment({
|
} else if (existingCommentId) {
|
||||||
owner,
|
const updatedComment = await octokit.rest.issues.updateComment({
|
||||||
repo,
|
comment_id: existingCommentId,
|
||||||
issue_number: issueNumber,
|
owner,
|
||||||
body: message,
|
repo,
|
||||||
})
|
body,
|
||||||
createdCommentData = createdComment.data
|
})
|
||||||
}
|
comment = updatedComment.data
|
||||||
}
|
core.setOutput('comment-updated', 'true')
|
||||||
|
} else {
|
||||||
if (createdCommentData) {
|
const createdComment = await octokit.rest.issues.createComment({
|
||||||
|
issue_number: issueNumber,
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
body,
|
||||||
|
})
|
||||||
|
comment = createdComment.data
|
||||||
core.setOutput('comment-created', 'true')
|
core.setOutput('comment-created', 'true')
|
||||||
core.setOutput('comment-id', createdCommentData.id)
|
}
|
||||||
|
|
||||||
|
if (comment) {
|
||||||
|
core.setOutput('comment-id', comment.id)
|
||||||
} else {
|
} else {
|
||||||
core.setOutput('comment-created', 'false')
|
core.setOutput('comment-created', 'false')
|
||||||
|
core.setOutput('comment-updated', 'false')
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof Error) {
|
if (err instanceof Error) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue