Skip to content

Commit ec953bd

Browse files
Copilotmikepenz
andcommitted
Add pr_id parameter support for workflow_run contexts
Co-authored-by: mikepenz <[email protected]>
1 parent a80d5fb commit ec953bd

File tree

6 files changed

+169
-17
lines changed

6 files changed

+169
-17
lines changed

__tests__/annotator.test.ts

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import {jest} from '@jest/globals'
2+
import {attachComment, buildCommentIdentifier} from '../src/annotator.js'
3+
import * as core from '@actions/core'
4+
5+
/**
6+
* Copyright 2024 Mike Penz
7+
*/
8+
jest.setTimeout(30000)
9+
10+
// Mock the context object
11+
jest.mock('@actions/github/lib/utils.js', () => ({
12+
context: {
13+
issue: {number: undefined},
14+
repo: {owner: 'test-owner', repo: 'test-repo'}
15+
}
16+
}))
17+
18+
describe('attachComment', () => {
19+
let mockOctokit: any
20+
let mockWarning: jest.SpiedFunction<typeof core.warning>
21+
let mockContext: any
22+
23+
beforeEach(() => {
24+
// Import context after mocking
25+
const {context} = require('@actions/github/lib/utils.js')
26+
mockContext = context
27+
28+
// Mock core.warning
29+
mockWarning = jest.spyOn(core, 'warning').mockImplementation(() => {})
30+
31+
// Mock octokit
32+
mockOctokit = {
33+
paginate: jest.fn(),
34+
rest: {
35+
issues: {
36+
listComments: jest.fn(),
37+
createComment: jest.fn(),
38+
updateComment: jest.fn()
39+
}
40+
}
41+
}
42+
})
43+
44+
afterEach(() => {
45+
jest.restoreAllMocks()
46+
})
47+
48+
it('should use pr_id when provided and context.issue.number is not available', async () => {
49+
// Setup: no context issue number
50+
mockContext.issue.number = undefined
51+
52+
mockOctokit.paginate.mockResolvedValue([])
53+
54+
const checkName = ['Test Check']
55+
const table = [['Test', 'Result'], ['Example Test', 'Passed']]
56+
const prId = '123'
57+
58+
await attachComment(mockOctokit, checkName, false, table, [], [], [], prId)
59+
60+
// Verify comment was created with correct issue number
61+
expect(mockOctokit.rest.issues.createComment).toHaveBeenCalledWith({
62+
owner: 'test-owner',
63+
repo: 'test-repo',
64+
issue_number: 123,
65+
body: expect.stringContaining('Example Test')
66+
})
67+
68+
expect(mockWarning).not.toHaveBeenCalled()
69+
})
70+
71+
it('should fall back to context.issue.number when pr_id is not provided', async () => {
72+
// Setup: context issue number available
73+
mockContext.issue.number = 456
74+
75+
mockOctokit.paginate.mockResolvedValue([])
76+
77+
const checkName = ['Test Check']
78+
const table = [['Test', 'Result'], ['Example Test', 'Passed']]
79+
80+
await attachComment(mockOctokit, checkName, false, table, [], [], [])
81+
82+
// Verify comment was created with context issue number
83+
expect(mockOctokit.rest.issues.createComment).toHaveBeenCalledWith({
84+
owner: 'test-owner',
85+
repo: 'test-repo',
86+
issue_number: 456,
87+
body: expect.stringContaining('Example Test')
88+
})
89+
90+
expect(mockWarning).not.toHaveBeenCalled()
91+
})
92+
93+
it('should warn and return early when no issue number is available', async () => {
94+
// Setup: no context issue number and no pr_id
95+
mockContext.issue.number = undefined
96+
97+
const checkName = ['Test Check']
98+
const table = [['Test', 'Result'], ['Example Test', 'Passed']]
99+
100+
await attachComment(mockOctokit, checkName, false, table, [], [], [])
101+
102+
// Verify warning was called and no comment was created
103+
expect(mockWarning).toHaveBeenCalledWith(
104+
expect.stringContaining('Action requires a valid issue number (PR reference) or pr_id input')
105+
)
106+
expect(mockOctokit.rest.issues.createComment).not.toHaveBeenCalled()
107+
})
108+
109+
it('should update existing comment when updateComment is true', async () => {
110+
// Setup: context issue number available
111+
mockContext.issue.number = 456
112+
113+
const existingComment = {
114+
id: 999,
115+
body: 'Existing comment <!-- Summary comment for ["Test Check"] by mikepenz/action-junit-report -->'
116+
}
117+
mockOctokit.paginate.mockResolvedValue([existingComment])
118+
119+
const checkName = ['Test Check']
120+
const table = [['Test', 'Result'], ['Example Test', 'Updated']]
121+
122+
await attachComment(mockOctokit, checkName, true, table, [], [], [])
123+
124+
// Verify comment was updated
125+
expect(mockOctokit.rest.issues.updateComment).toHaveBeenCalledWith({
126+
owner: 'test-owner',
127+
repo: 'test-repo',
128+
comment_id: 999,
129+
body: expect.stringContaining('Example Test')
130+
})
131+
expect(mockOctokit.rest.issues.createComment).not.toHaveBeenCalled()
132+
})
133+
})
134+
135+
describe('buildCommentIdentifier', () => {
136+
it('should build correct identifier', () => {
137+
const checkName = ['Test Check']
138+
const identifier = buildCommentIdentifier(checkName)
139+
expect(identifier).toBe('<!-- Summary comment for ["Test Check"] by mikepenz/action-junit-report -->')
140+
})
141+
})

action.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ inputs:
160160
description: 'Disable commenting if no tests are detected'
161161
required: false
162162
default: 'false'
163+
pr_id:
164+
description: 'PR number to comment on (useful for workflow_run contexts)'
165+
required: false
163166
outputs:
164167
total:
165168
description: 'The total count of all checks'

dist/index.js

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

dist/index.js.map

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

src/annotator.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -180,10 +180,14 @@ export async function attachComment(
180180
table: SummaryTableRow[],
181181
detailsTable: SummaryTableRow[],
182182
flakySummary: SummaryTableRow[],
183-
checkInfos: CheckInfo[] = []
183+
checkInfos: CheckInfo[] = [],
184+
prId?: string
184185
): Promise<void> {
185-
if (!context.issue.number) {
186-
core.warning(`⚠️ Action requires a valid issue number (PR reference) to be able to attach a comment..`)
186+
// Use provided prId or fall back to context issue number
187+
const issueNumber = prId ? parseInt(prId, 10) : context.issue.number
188+
189+
if (!issueNumber) {
190+
core.warning(`⚠️ Action requires a valid issue number (PR reference) or pr_id input to be able to attach a comment..`)
187191
return
188192
}
189193

@@ -215,7 +219,7 @@ export async function attachComment(
215219

216220
comment += `\n\n${identifier}`
217221

218-
const priorComment = updateComment ? await findPriorComment(octokit, identifier) : undefined
222+
const priorComment = updateComment ? await findPriorComment(octokit, identifier, issueNumber) : undefined
219223
if (priorComment) {
220224
await octokit.rest.issues.updateComment({
221225
owner: context.repo.owner,
@@ -227,17 +231,17 @@ export async function attachComment(
227231
await octokit.rest.issues.createComment({
228232
owner: context.repo.owner,
229233
repo: context.repo.repo,
230-
issue_number: context.issue.number,
234+
issue_number: issueNumber,
231235
body: comment
232236
})
233237
}
234238
}
235239

236-
async function findPriorComment(octokit: InstanceType<typeof GitHub>, identifier: string): Promise<number | undefined> {
240+
async function findPriorComment(octokit: InstanceType<typeof GitHub>, identifier: string, issueNumber: number): Promise<number | undefined> {
237241
const comments = await octokit.paginate(octokit.rest.issues.listComments, {
238242
owner: context.repo.owner,
239243
repo: context.repo.repo,
240-
issue_number: context.issue.number
244+
issue_number: issueNumber
241245
})
242246

243247
const foundComment = comments.find(comment => comment.body?.endsWith(identifier))

src/main.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export async function run(): Promise<void> {
4141
const updateComment = core.getInput('updateComment') === 'true'
4242
const jobName = core.getInput('job_name')
4343
const skipCommentWithoutTests = core.getInput('skip_comment_without_tests') === 'true'
44+
const prId = core.getInput('pr_id')
4445

4546
const reportPaths = core.getMultilineInput('report_paths')
4647
const summary = core.getMultilineInput('summary')
@@ -208,7 +209,7 @@ export async function run(): Promise<void> {
208209

209210
if (comment && (!skipCommentWithoutTests || mergedResult.totalCount > 0)) {
210211
const octokit: InstanceType<typeof GitHub> = github.getOctokit(token)
211-
await attachComment(octokit, checkName, updateComment, table, detailTable, flakyTable, checkInfos)
212+
await attachComment(octokit, checkName, updateComment, table, detailTable, flakyTable, checkInfos, prId)
212213
}
213214

214215
core.setOutput('summary', buildTable(table))

0 commit comments

Comments
 (0)