Add sticky comment feature and ID based reference. (#61)

* sticky comment feature
* remove unused param
This commit is contained in:
Michael Shick 2022-11-07 09:43:48 -08:00 committed by GitHub
parent f9a5a1c8cb
commit 3aa992a9b5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 212 additions and 180 deletions

View file

@ -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 }}

View file

@ -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

View file

@ -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)
}) })
}) })

View file

@ -6,13 +6,14 @@ inputs:
required: false required: false
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
View file

@ -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

File diff suppressed because one or more lines are too long

View file

@ -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) {

View file

@ -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) {