workflows/check: always run commits job

This is the very first step to extending the commits job to do more than
just cherry-picks in the future: It could check reverts or merge
commits, but also the commit message format and more.

Of course, cherry-picks are still just checked on the stable branches as
before. For now, this allows us to run the part that dismisses automated
reviews automatically. This helps us when we do branch related checks in
the prepare step, which would also create such a review. To avoid
cluttering multiple reviews across a PR, we'll want all of these reviews
to be handled by the same code, thus this change.
This commit is contained in:
Wolfgang Walther
2025-08-21 15:08:23 +02:00
parent 534d41ee9c
commit b6bbf7b250
3 changed files with 26 additions and 17 deletions

View File

@@ -42,10 +42,7 @@ jobs:
EOF EOF
exit 1 exit 1
cherry-pick: commits:
if: |
github.event_name == 'pull_request' ||
(fromJSON(inputs.baseBranch).stable && !contains(fromJSON(inputs.headBranch).type, 'development'))
permissions: permissions:
pull-requests: write pull-requests: write
runs-on: ubuntu-24.04-arm runs-on: ubuntu-24.04-arm
@@ -65,16 +62,20 @@ jobs:
GH_TOKEN: ${{ github.token }} GH_TOKEN: ${{ github.token }}
run: gh api /rate_limit | jq run: gh api /rate_limit | jq
- name: Check cherry-picks - name: Check commits
id: check id: check
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
env:
TARGETS_STABLE: ${{ fromJSON(inputs.baseBranch).stable && !contains(fromJSON(inputs.headBranch).type, 'development') }}
with: with:
script: | script: |
const targetsStable = JSON.parse(process.env.TARGETS_STABLE)
require('./trusted/ci/github-script/commits.js')({ require('./trusted/ci/github-script/commits.js')({
github, github,
context, context,
core, core,
dry: context.eventName == 'pull_request', dry: context.eventName == 'pull_request',
cherryPicks: context.eventName == 'pull_request' || targetsStable,
}) })
- name: Log current API rate limits - name: Log current API rate limits

View File

@@ -1,4 +1,4 @@
module.exports = async ({ github, context, core, dry }) => { module.exports = async ({ github, context, core, dry, cherryPicks }) => {
const { execFileSync } = require('node:child_process') const { execFileSync } = require('node:child_process')
const { classify } = require('../supportedBranches.js') const { classify } = require('../supportedBranches.js')
const withRateLimit = require('./withRateLimit.js') const withRateLimit = require('./withRateLimit.js')
@@ -16,7 +16,7 @@ module.exports = async ({ github, context, core, dry }) => {
run_id: context.runId, run_id: context.runId,
per_page: 100, per_page: 100,
}) })
).find(({ name }) => name.endsWith('Check / cherry-pick')).html_url + ).find(({ name }) => name.endsWith('Check / commits')).html_url +
'?pr=' + '?pr=' +
pull_number pull_number
@@ -137,10 +137,14 @@ module.exports = async ({ github, context, core, dry }) => {
} }
} }
const commits = await github.paginate(github.rest.pulls.listCommits, { // For now we short-circuit the list of commits when cherryPicks should not be checked.
...context.repo, // This will not run any checks, but still trigger the "dismiss reviews" part below.
pull_number, const commits = !cherryPicks
}) ? []
: await github.paginate(github.rest.pulls.listCommits, {
...context.repo,
pull_number,
})
const extracted = await Promise.all(commits.map(extract)) const extracted = await Promise.all(commits.map(extract))
@@ -185,6 +189,8 @@ module.exports = async ({ github, context, core, dry }) => {
// Only create step summary below in case of warnings or errors. // Only create step summary below in case of warnings or errors.
// Also clean up older reviews, when all checks are good now. // Also clean up older reviews, when all checks are good now.
// An empty results array will always trigger this condition, which is helpful
// to clean up reviews created by the prepare step when on the wrong branch.
if (results.every(({ severity }) => severity === 'info')) { if (results.every(({ severity }) => severity === 'info')) {
if (!dry) { if (!dry) {
await Promise.all( await Promise.all(
@@ -201,7 +207,7 @@ module.exports = async ({ github, context, core, dry }) => {
...context.repo, ...context.repo,
pull_number, pull_number,
review_id: review.id, review_id: review.id,
message: 'All cherry-picks are good now, thank you!', message: 'All good now, thank you!',
}) })
} }
await github.graphql( await github.graphql(

View File

@@ -7,7 +7,7 @@ import { program } from 'commander'
import * as core from '@actions/core' import * as core from '@actions/core'
import { getOctokit } from '@actions/github' import { getOctokit } from '@actions/github'
async function run(action, owner, repo, pull_number, dry = true) { async function run(action, owner, repo, pull_number, options = {}) {
const token = execSync('gh auth token', { encoding: 'utf-8' }).trim() const token = execSync('gh auth token', { encoding: 'utf-8' }).trim()
const github = getOctokit(token) const github = getOctokit(token)
@@ -35,7 +35,8 @@ async function run(action, owner, repo, pull_number, dry = true) {
}, },
}, },
core, core,
dry, dry: true,
...options,
}) })
} }
@@ -56,9 +57,10 @@ program
.argument('<owner>', 'Owner of the GitHub repository to check (Example: NixOS)') .argument('<owner>', 'Owner of the GitHub repository to check (Example: NixOS)')
.argument('<repo>', 'Name of the GitHub repository to check (Example: nixpkgs)') .argument('<repo>', 'Name of the GitHub repository to check (Example: nixpkgs)')
.argument('<pr>', 'Number of the Pull Request to check') .argument('<pr>', 'Number of the Pull Request to check')
.action(async (owner, repo, pr) => { .option('--no-cherry-picks', 'Do not expect cherry-picks.')
.action(async (owner, repo, pr, options) => {
const commits = (await import('./commits.js')).default const commits = (await import('./commits.js')).default
run(commits, owner, repo, pr) run(commits, owner, repo, pr, options)
}) })
program program
@@ -74,7 +76,7 @@ program
try { try {
process.env.GITHUB_WORKSPACE = tmp process.env.GITHUB_WORKSPACE = tmp
process.chdir(tmp) process.chdir(tmp)
run(labels, owner, repo, pr, options.dry) run(labels, owner, repo, pr, options)
} finally { } finally {
rmSync(tmp, { recursive: true }) rmSync(tmp, { recursive: true })
} }