Skip to content

Commit cd7b78b

Browse files
committed
Add support for updating the same results comment
1 parent 2c0a6a3 commit cd7b78b

File tree

14 files changed

+4536
-343
lines changed

14 files changed

+4536
-343
lines changed

README.md

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,15 @@
99

1010
Validate issue form submissions
1111

12-
> [!IMPORTANT]
13-
>
14-
> As of version `v2.0.0`, this action has been converted to ESM. Because of
15-
> this, custom validation scripts must be provided in ESM syntax. If you are
16-
> using CommonJS, you will need to convert your scripts to ESM. See
17-
> [`team.js`](./.github/validator/team.js) for an example.
12+
## Important Updates
13+
14+
- As of version `v3`, this action now requires `issues: write` permissions to
15+
read and write issue comments. This is because the action now updates the
16+
**same** comment instead of adding new ones.
17+
- As of version `v2`, this action has been converted to ESM. Because of this,
18+
custom validation scripts must be provided in ESM syntax. If you are using
19+
CommonJS, you will need to convert your scripts to ESM. See
20+
[`team.js`](./.github/validator/team.js) for an example.
1821

1922
## About
2023

@@ -66,6 +69,12 @@ jobs:
6669
name: Validate Issue
6770
runs-on: ubuntu-latest
6871

72+
# These permissions are required to read custom validator scripts and
73+
# write/update issue comments.
74+
permissions:
75+
contents: read
76+
issues: write
77+
6978
steps:
7079
# This is required to access the repository's files. Specifically, the
7180
# issue forms template and the additional validation configuration.
@@ -117,6 +126,12 @@ jobs:
117126
name: Validate Issue with Custom Logic
118127
runs-on: ubuntu-latest
119128

129+
# These permissions are required to read custom validator scripts and
130+
# write/update issue comments.
131+
permissions:
132+
contents: read
133+
issues: write
134+
120135
steps:
121136
# This is required to access the repository's files. Specifically, the
122137
# issue forms template and the additional validation configuration.

__fixtures__/octokit.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ export const rest = {
2222
get: jest.fn(),
2323
listComments: jest.fn(),
2424
removeLabel: jest.fn(),
25-
update: jest.fn()
25+
update: jest.fn(),
26+
updateComment: jest.fn()
2627
},
2728
orgs: {
2829
checkMembershipForUser: jest.fn()

__tests__/comments.test.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { jest } from '@jest/globals'
2+
import * as github from '../__fixtures__/github.js'
3+
import * as octokit from '../__fixtures__/octokit.js'
4+
5+
jest.unstable_mockModule('@actions/github', () => github)
6+
jest.unstable_mockModule('@octokit/rest', async () => {
7+
class Octokit {
8+
constructor() {
9+
return octokit
10+
}
11+
}
12+
13+
return {
14+
Octokit
15+
}
16+
})
17+
jest.unstable_mockModule('../src/constants.js', () => ({
18+
COMMENT_IDENTIFIER: '<!-- action-required -->'
19+
}))
20+
21+
const { getCommentId } = await import('../src/comments.js')
22+
const { Octokit } = await import('@octokit/rest')
23+
24+
const mocktokit = jest.mocked(new Octokit())
25+
26+
describe('getCommentId()', () => {
27+
afterEach(() => {
28+
jest.resetAllMocks()
29+
})
30+
31+
it('Returns a comment ID', async () => {
32+
mocktokit.paginate.mockResolvedValue([
33+
{
34+
id: 1,
35+
body: 'This is a comment. <!-- action-required -->'
36+
},
37+
{
38+
id: 2,
39+
body: 'This is another comment.'
40+
}
41+
])
42+
43+
const result = await getCommentId('token', 'owner', 'repo', 1)
44+
45+
expect(mocktokit.paginate).toHaveBeenCalled()
46+
expect(result).toBe(1)
47+
})
48+
})

__tests__/main.test.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import * as octokit from '../__fixtures__/octokit.js'
77
const compileTemplateSpy = jest.fn()
88
const validateSpy = jest.fn()
99
const parseTemplateSpy = jest.fn()
10+
const getCommentIdSpy = jest.fn()
1011

1112
jest.unstable_mockModule('@actions/core', () => core)
1213
jest.unstable_mockModule('@octokit/rest', async () => {
@@ -29,6 +30,9 @@ jest.unstable_mockModule('../src/validate.js', () => ({
2930
jest.unstable_mockModule('../src/utils/parse.js', () => ({
3031
parseTemplate: parseTemplateSpy
3132
}))
33+
jest.unstable_mockModule('../src/comments.js', () => ({
34+
getCommentId: getCommentIdSpy
35+
}))
3236

3337
const main = await import('../src/main.js')
3438
const { Octokit } = await import('@octokit/rest')
@@ -76,6 +80,7 @@ describe('main.ts', () => {
7680

7781
parseTemplateSpy.mockReturnValue(JSON.parse(parsedTemplate))
7882
validateSpy.mockReturnValue([])
83+
getCommentIdSpy.mockReturnValue(undefined)
7984
})
8085

8186
afterEach(() => {
@@ -292,4 +297,47 @@ describe('main.ts', () => {
292297
expect(compileTemplateSpy).not.toHaveBeenCalledWith()
293298
expect(mocktokit.rest.issues.createComment).toHaveBeenCalled()
294299
})
300+
301+
it('Updates an existing comment when add-comment is true', async () => {
302+
getCommentIdSpy.mockReturnValue(1)
303+
304+
jest
305+
.spyOn(fs, 'existsSync')
306+
.mockImplementation((path: PathLike): boolean => {
307+
switch (path) {
308+
case `${process.cwd()}/.github/ISSUE_TEMPLATE/example-request.yml`:
309+
return true
310+
case `${process.cwd()}/.github/validator/success.mustache`:
311+
return true
312+
default:
313+
return false
314+
}
315+
})
316+
317+
jest
318+
.spyOn(fs, 'readFileSync')
319+
.mockImplementation((path: PathOrFileDescriptor): string => {
320+
switch (path) {
321+
case `${process.cwd()}/.github/ISSUE_TEMPLATE/example-request.yml`:
322+
return template
323+
case `${process.cwd()}/.github/validator/success.mustache`:
324+
return successMustache
325+
default:
326+
return ''
327+
}
328+
})
329+
330+
// Mock the validation errors.
331+
jest.mocked(validateSpy).mockReturnValue([])
332+
333+
await main.run()
334+
335+
expect(compileTemplateSpy).toHaveBeenCalledWith(
336+
`${process.cwd()}/.github/validator/success.mustache`,
337+
{
338+
issue: JSON.parse(parsedIssue)
339+
}
340+
)
341+
expect(mocktokit.rest.issues.updateComment).toHaveBeenCalled()
342+
})
295343
})

dist/comments.d.ts

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/constants.d.ts

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)