Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions .github/scripts/publish/verify_check_runs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// This script runs in the context of `actions/github-script` from GitHub Action workflow.
// It checks the conclusion for check suites of a commit (SHA) from a specifc Github App.
// It fails the workflow if any of the check suites are not 'success', 'neutral' or 'skipped'.

// API:
// - https://docs.github.com/en/rest/checks/suites?apiVersion=2022-11-28#list-check-suites-for-a-git-reference
// - https://docs.github.com/en/rest/checks/runs?apiVersion=2022-11-28#list-check-runs-in-a-check-suite
module.exports = async ({github, context, core}) => {
const checkSuites = await github.paginate(github.rest.checks.listSuitesForRef, {
owner: context.repo.owner,
repo: context.repo.repo,
ref: context.sha,
app_id: parseInt(process.env.APP_ID),
per_page: 100
});

console.log(`Found ${checkSuites.length} check suites`);

const failedSuites = checkSuites.filter(suite =>
suite.status === 'completed' &&
suite.conclusion !== 'success' &&
suite.conclusion !== 'neutral' &&
suite.conclusion !== 'skipped'
);

if (failedSuites.length > 0) {
console.log(`Found ${failedSuites.length} failed check suites`);

const failedChecksPromises = failedSuites.map(async suite => {
const checkRuns = await github.paginate(github.rest.checks.listForSuite, {
owner: context.repo.owner,
repo: context.repo.repo,
check_suite_id: suite.id,
per_page: 100
});

return checkRuns.filter(check =>
check.status === 'completed' &&
check.conclusion !== 'success' &&
check.conclusion !== 'neutral' &&
check.conclusion !== 'skipped'
);
});

const failedChecksArrays = await Promise.all(failedChecksPromises);
const failedChecks = failedChecksArrays.flat();

console.log(`Found a total of ${failedChecks.length} failed check runs`);

failedChecks.forEach(failedCheck => {
const { name, conclusion, html_url } = failedCheck;
const message = JSON.stringify({ name, conclusion, url: html_url }, null, 2);

core.error(message);
});

// Set job failure
core.setFailed(`Found ${failedSuites.length} failed check suites`);
}
}
41 changes: 41 additions & 0 deletions .github/scripts/publish/verify_commit_status.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// This script runs in the context of `actions/github-script` from GitHub Action workflow.
// It checks the commit status of a commit (SHA).
// It fails the workflow if the combined status is not 'success'.

// API:
// - https://docs.github.com/en/rest/commits/statuses?apiVersion=2022-11-28#get-the-combined-status-for-a-specific-reference
module.exports = async ({github, context, core}) => {
const { data: combinedStatus } = await github.rest.repos.getCombinedStatusForRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: context.sha
});

if (combinedStatus.state !== 'success') {
const allStatuses = await github.paginate(github.rest.repos.listCommitStatusesForRef, {
owner: context.repo.owner,
repo: context.repo.repo,
ref: context.sha,
per_page: 100
});

console.log(`Found ${allStatuses.length} commit statuses`);

const failedStatuses = allStatuses.filter(s => s.state !== 'success');

if (failedStatuses.length > 0) {
console.log(`Found ${failedStatuses.length} failed commit statuses`);
failedStatuses.forEach(failedStatus => {
const message = JSON.stringify({
context: failedStatus.context,
state: failedStatus.state,
url: failedStatus.target_url
}, null, 2);

core.error(message);
});
}

core.setFailed(`Commit status is ${combinedStatus.state} with ${failedStatuses.length} failed checks`);
}
}
36 changes: 8 additions & 28 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,46 +105,26 @@ jobs:
console.log(`Found open milestone ${process.env.GEM_VERSION} (ID: ${versionMilestone.number})`);

# Check if the commit has passed all Github checks
# API: https://docs.github.com/en/rest/checks/runs?apiVersion=2022-11-28#list-check-runs-for-a-git-reference
- name: Verify check runs
continue-on-error: ${{ inputs.force }}
env:
APP_ID: 15368 # Github Actions app ID
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
retries: 3
script: |
const checkRuns = await github.paginate(github.rest.checks.listForRef, {
owner: context.repo.owner,
repo: context.repo.repo,
ref: context.sha,
per_page: 100
});

const failedChecks = checkRuns.filter(check =>
check.status === 'completed' &&
check.conclusion !== 'success' &&
check.conclusion !== 'skipped'
);

if (failedChecks.length > 0) {
const failedNames = failedChecks.map(c => c.name).join(', ');
core.setFailed(`Check runs failed: ${failedNames}`);
}
const script = require('./.github/scripts/publish/verify_check_runs.js')
await script({github, context, core})

# Check if the commit has passed external CI checks
# API: https://docs.github.com/en/rest/commits/statuses?apiVersion=2022-11-28#get-the-combined-status-for-a-specific-reference
- name: Verify commit status
continue-on-error: ${{ inputs.force }}
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
retries: 3
script: |
const { data: status } = await github.rest.repos.getCombinedStatusForRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: context.sha
});

if (status.state !== 'success') {
core.setFailed(`Commit status is ${status.state}`);
}
const script = require('./.github/scripts/publish/verify_commit_status.js')
await script({github, context, core})

# Check if the commit has all the checks passed
- name: Verify deferred commit data
Expand Down
Loading