mirror of
https://github.com/gradle/actions.git
synced 2026-07-26 14:14:32 +02:00
Hide obsolete Job summaries (#902)
- Injects a `<!-- gradle-job-summary: ${jobCorrelator} -->` marker on
each job summary
- Lists 100 last comments: unfortunately there is no API to specifically
filter for comments, and checking the last 100 comments (the limit) is
usually enough and does not require iterating over pages
- Mutate comments having this expected marker
I tried to add some tests, but I'm not familiar enough to setup a
complete test suite with proper mocking of GitHub/Octokit with jest.
I could potentially extract the `prComment` creation to check for the
marker presence, let me know.
Note: it seems like there is currently an issue on mutating comments as
`OUTDATED` through graphql. Although it does not work as expected
(flagging as OUTDATED) the comments are still minimized, which is what
we want.
- https://github.com/orgs/community/discussions/19865
Implements #176
---------
Co-authored-by: Daz DeBoer <daz@gradle.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Daz DeBoer
Claude Opus 4.8
parent
a740661292
commit
318eed7038
@@ -548,6 +548,11 @@ jobs:
|
||||
- run: ./gradlew build --scan
|
||||
```
|
||||
|
||||
When a comment is added, any earlier Job Summary comments posted by the same job on that Pull Request are
|
||||
automatically minimized, so only the most recent result remains expanded. This also applies when
|
||||
`add-job-summary-as-pr-comment: 'on-failure'` is used: once a later run of the job succeeds, the previous
|
||||
failure comment is collapsed.
|
||||
|
||||
Note that to add a Pull Request comment, the workflow must be configured with the `pull-requests: write` permission.
|
||||
|
||||
|
||||
|
||||
@@ -206,6 +206,10 @@ export class SummaryConfig {
|
||||
return this.shouldAddJobSummary(this.getJobSummaryOption(), hasFailure)
|
||||
}
|
||||
|
||||
canAddPRComment(): boolean {
|
||||
return this.getPRCommentOption() !== JobSummaryOption.Never
|
||||
}
|
||||
|
||||
shouldAddPRComment(hasFailure: boolean): boolean {
|
||||
return this.shouldAddJobSummary(this.getPRCommentOption(), hasFailure)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as core from '@actions/core'
|
||||
import * as github from '@actions/github'
|
||||
|
||||
import {BuildResult} from './build-results'
|
||||
import {SummaryConfig, getActionId, getGithubToken} from './configuration'
|
||||
import {DependencyGraphConfig, getActionId, getGithubToken, getJobMatrix, SummaryConfig} from './configuration'
|
||||
import {Deprecation, getDeprecations, getErrors} from './deprecation-collector'
|
||||
|
||||
export async function generateJobSummary(
|
||||
@@ -33,6 +33,10 @@ export async function generateJobSummary(
|
||||
core.info('============================')
|
||||
}
|
||||
|
||||
if (config.canAddPRComment()) {
|
||||
await minimizeObsoletePRComments()
|
||||
}
|
||||
|
||||
if (config.shouldAddPRComment(hasFailure)) {
|
||||
await addPRComment(summaryTable)
|
||||
}
|
||||
@@ -48,7 +52,8 @@ async function addPRComment(jobSummary: string): Promise<void> {
|
||||
const pull_request_number = context.payload.pull_request.number
|
||||
core.info(`Adding Job Summary as comment to PR #${pull_request_number}.`)
|
||||
|
||||
const prComment = `<h3>Job Summary for Gradle</h3>
|
||||
const prComment = `${jobMarker(context)}
|
||||
<h3>Job Summary for Gradle</h3>
|
||||
<a href="${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}" target="_blank">
|
||||
<h5>${context.workflow} :: <em>${context.job}</em></h5>
|
||||
</a>
|
||||
@@ -57,6 +62,7 @@ ${jobSummary}`
|
||||
|
||||
const github_token = getGithubToken()
|
||||
const octokit = github.getOctokit(github_token)
|
||||
|
||||
try {
|
||||
await octokit.rest.issues.createComment({
|
||||
...context.repo,
|
||||
@@ -201,3 +207,77 @@ function truncateString(str: string, maxLength: number): string {
|
||||
return str
|
||||
}
|
||||
}
|
||||
|
||||
async function minimizeObsoletePRComments(): Promise<void> {
|
||||
const context = github.context
|
||||
if (context.payload.pull_request == null) {
|
||||
core.info('No pull_request trigger detected: not minimizing obsolete PR comments')
|
||||
return
|
||||
}
|
||||
|
||||
const prNumber = context.payload.pull_request.number
|
||||
core.info(`Minimizing obsolete Job Summary comments on PR #${prNumber}.`)
|
||||
|
||||
const marker = jobMarker(context)
|
||||
const octokit = github.getOctokit(getGithubToken())
|
||||
const {owner, repo} = context.repo
|
||||
|
||||
const query = `
|
||||
query($owner: String!, $repo: String!, $prNumber: Int!) {
|
||||
repository(owner: $owner, name: $repo) {
|
||||
pullRequest(number: $prNumber) {
|
||||
comments(last: 100) {
|
||||
nodes { id body isMinimized url }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
let comments: PullRequestComment[]
|
||||
try {
|
||||
const {repository} = await octokit.graphql<CommentsQueryResult>(query, {owner, repo, prNumber})
|
||||
comments = repository.pullRequest?.comments?.nodes?.filter((c): c is PullRequestComment => c !== null) ?? []
|
||||
} catch (error) {
|
||||
return core.warning(`Failed to fetch comments: ${error}`)
|
||||
}
|
||||
|
||||
const mutation = `
|
||||
mutation($id: ID!) {
|
||||
minimizeComment(input: {subjectId: $id, classifier: OUTDATED}) {
|
||||
clientMutationId
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const commentsToMinimize = comments
|
||||
.filter(c => !c.isMinimized && c.body.includes(marker))
|
||||
.map(async c =>
|
||||
octokit
|
||||
.graphql(mutation, {id: c.id})
|
||||
.then(() => core.info(`Successfully minimized (id:${c.id}, url:${c.url})`))
|
||||
.catch(e => core.warning(`Failed to minimize (id:${c.id}, url:${c.url}, error:${e?.message || e})`))
|
||||
)
|
||||
await Promise.allSettled(commentsToMinimize)
|
||||
}
|
||||
|
||||
export function jobMarker(context: typeof github.context): string {
|
||||
const jobCorrelator = DependencyGraphConfig.constructJobCorrelator(context.workflow, context.job, getJobMatrix())
|
||||
return `<!-- gradle-job-summary: ${jobCorrelator} -->`
|
||||
}
|
||||
|
||||
interface PullRequestComment {
|
||||
id: string
|
||||
body: string
|
||||
isMinimized: boolean
|
||||
url: string
|
||||
}
|
||||
|
||||
interface CommentsQueryResult {
|
||||
repository: {
|
||||
pullRequest?: {
|
||||
comments?: {
|
||||
nodes?: (PullRequestComment | null)[] | null
|
||||
} | null
|
||||
} | null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
import dedent from 'dedent'
|
||||
import {describe, expect, it} from '@jest/globals'
|
||||
import * as github from '@actions/github'
|
||||
import {afterEach, describe, expect, it} from '@jest/globals'
|
||||
|
||||
import {BuildResult} from '../../src/build-results'
|
||||
import {renderSummaryTable} from '../../src/job-summary'
|
||||
import {jobMarker, renderSummaryTable} from '../../src/job-summary'
|
||||
|
||||
const MATRIX_INPUT_ENV = 'INPUT_WORKFLOW-JOB-CONTEXT'
|
||||
|
||||
function fakeContext(workflow: string, job: string): typeof github.context {
|
||||
return {workflow, job} as unknown as typeof github.context
|
||||
}
|
||||
|
||||
const successfulHelpBuild: BuildResult = {
|
||||
rootProjectName: 'root',
|
||||
@@ -177,3 +184,27 @@ describe('renderSummaryTable', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('jobMarker', () => {
|
||||
const original = process.env[MATRIX_INPUT_ENV]
|
||||
|
||||
afterEach(() => {
|
||||
if (original === undefined) {
|
||||
delete process.env[MATRIX_INPUT_ENV]
|
||||
} else {
|
||||
process.env[MATRIX_INPUT_ENV] = original
|
||||
}
|
||||
})
|
||||
|
||||
it('builds a hidden marker from the workflow and job', () => {
|
||||
process.env[MATRIX_INPUT_ENV] = 'null'
|
||||
const marker = jobMarker(fakeContext('CI', 'build'))
|
||||
expect(marker).toBe('<!-- gradle-job-summary: ci-build -->')
|
||||
})
|
||||
|
||||
it('includes the job matrix in the marker', () => {
|
||||
process.env[MATRIX_INPUT_ENV] = JSON.stringify({os: 'ubuntu', java: '17'})
|
||||
const marker = jobMarker(fakeContext('CI', 'build'))
|
||||
expect(marker).toBe('<!-- gradle-job-summary: ci-build-ubuntu-17 -->')
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user