workflows/pr: refactor base/head branch decision making
Some jobs purposefully only run on certain base or head branches. By centralizing the logic, parts of it can easily be re-used later. Also, this gives them an explicit name and thus makes them easier to understand.
This commit is contained in:
parent
caf4ced100
commit
7763be5a80
7
.github/workflows/build.yml
vendored
7
.github/workflows/build.yml
vendored
@ -3,6 +3,9 @@ name: Build
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
baseBranch:
|
||||
required: true
|
||||
type: string
|
||||
mergedSha:
|
||||
required: true
|
||||
type: string
|
||||
@ -63,7 +66,7 @@ jobs:
|
||||
- name: Build NixOS manual
|
||||
if: |
|
||||
contains(matrix.builds, 'manual-nixos') && !cancelled() &&
|
||||
(github.base_ref == 'master' || startsWith(github.base_ref, 'release-'))
|
||||
contains(fromJSON(inputs.baseBranch).type, 'primary')
|
||||
run: nix-build untrusted/ci -A manual-nixos --argstr system ${{ matrix.system }} --out-link nixos-manual
|
||||
|
||||
- name: Build Nixpkgs manual
|
||||
@ -81,7 +84,7 @@ jobs:
|
||||
- name: Upload NixOS manual
|
||||
if: |
|
||||
contains(matrix.builds, 'manual-nixos') && !cancelled() &&
|
||||
(github.base_ref == 'master' || startsWith(github.base_ref, 'release-'))
|
||||
contains(fromJSON(inputs.baseBranch).type, 'primary')
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: nixos-manual-${{ matrix.system }}
|
||||
|
11
.github/workflows/check.yml
vendored
11
.github/workflows/check.yml
vendored
@ -2,6 +2,10 @@ name: Check
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
baseBranch:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions: {}
|
||||
|
||||
@ -12,9 +16,7 @@ defaults:
|
||||
jobs:
|
||||
no-channel-base:
|
||||
name: no channel base
|
||||
if: |
|
||||
startsWith(github.base_ref, 'nixos-') ||
|
||||
startsWith(github.base_ref, 'nixpkgs-')
|
||||
if: contains(fromJSON(inputs.baseBranch).type, 'channel')
|
||||
runs-on: ubuntu-24.04-arm
|
||||
steps:
|
||||
- run: |
|
||||
@ -29,8 +31,7 @@ jobs:
|
||||
cherry-pick:
|
||||
if: |
|
||||
github.event_name == 'pull_request' ||
|
||||
startsWith(github.base_ref, 'release-') ||
|
||||
(startsWith(github.base_ref, 'staging-') && github.base_ref != 'staging-next')
|
||||
fromJSON(inputs.baseBranch).stable
|
||||
permissions:
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-24.04-arm
|
||||
|
25
.github/workflows/labels.yml
vendored
25
.github/workflows/labels.yml
vendored
@ -9,6 +9,10 @@ on:
|
||||
schedule:
|
||||
- cron: '07,17,27,37,47,57 * * * *'
|
||||
workflow_call:
|
||||
inputs:
|
||||
headBranch:
|
||||
required: true
|
||||
type: string
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
updatedWithin:
|
||||
@ -252,12 +256,7 @@ jobs:
|
||||
name: Labels from touched files
|
||||
if: |
|
||||
github.event_name == 'pull_request_target' &&
|
||||
(github.event.pull_request.head.repo.owner.login != 'NixOS' || !(
|
||||
github.head_ref == 'haskell-updates' ||
|
||||
github.head_ref == 'python-updates' ||
|
||||
github.head_ref == 'staging-next' ||
|
||||
startsWith(github.head_ref, 'staging-next-')
|
||||
))
|
||||
!contains(fromJSON(inputs.headBranch).type, 'development')
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
configuration-path: .github/labeler.yml # default
|
||||
@ -267,12 +266,7 @@ jobs:
|
||||
name: Labels from touched files (no sync)
|
||||
if: |
|
||||
github.event_name == 'pull_request_target' &&
|
||||
(github.event.pull_request.head.repo.owner.login != 'NixOS' || !(
|
||||
github.head_ref == 'haskell-updates' ||
|
||||
github.head_ref == 'python-updates' ||
|
||||
github.head_ref == 'staging-next' ||
|
||||
startsWith(github.head_ref, 'staging-next-')
|
||||
))
|
||||
!contains(fromJSON(inputs.headBranch).type, 'development')
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
configuration-path: .github/labeler-no-sync.yml
|
||||
@ -285,12 +279,7 @@ jobs:
|
||||
# the backport labels.
|
||||
if: |
|
||||
github.event_name == 'pull_request_target' &&
|
||||
(github.event.pull_request.head.repo.owner.login == 'NixOS' && (
|
||||
github.head_ref == 'haskell-updates' ||
|
||||
github.head_ref == 'python-updates' ||
|
||||
github.head_ref == 'staging-next' ||
|
||||
startsWith(github.head_ref, 'staging-next-')
|
||||
))
|
||||
contains(fromJSON(inputs.headBranch).type, 'development')
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
configuration-path: .github/labeler-development-branches.yml
|
||||
|
31
.github/workflows/pr.yml
vendored
31
.github/workflows/pr.yml
vendored
@ -21,6 +21,8 @@ jobs:
|
||||
prepare:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
outputs:
|
||||
baseBranch: ${{ steps.branches.outputs.base }}
|
||||
headBranch: ${{ steps.branches.outputs.head }}
|
||||
mergedSha: ${{ steps.get-merge-commit.outputs.mergedSha }}
|
||||
targetSha: ${{ steps.get-merge-commit.outputs.targetSha }}
|
||||
systems: ${{ steps.systems.outputs.systems }}
|
||||
@ -29,6 +31,7 @@ jobs:
|
||||
with:
|
||||
sparse-checkout: |
|
||||
.github/actions
|
||||
ci/supportedBranches.js
|
||||
ci/supportedSystems.json
|
||||
- name: Check if the PR can be merged and get the test merge commit
|
||||
uses: ./.github/actions/get-merge-commit
|
||||
@ -39,12 +42,35 @@ jobs:
|
||||
run: |
|
||||
echo "systems=$(jq -c <ci/supportedSystems.json)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Determine branch type
|
||||
id: branches
|
||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||||
with:
|
||||
script: |
|
||||
const { classify } = require('./ci/supportedBranches.js')
|
||||
const { base, head } = context.payload.pull_request
|
||||
|
||||
const baseClassification = classify(base.ref)
|
||||
core.setOutput('base', baseClassification)
|
||||
core.info('base classification:', baseClassification)
|
||||
|
||||
const headClassification =
|
||||
(base.repo.full_name == head.repo.full_name) ?
|
||||
classify(head.ref) :
|
||||
// PRs from forks are always considered WIP.
|
||||
{ type: ['wip'] }
|
||||
core.setOutput('head', headClassification)
|
||||
core.info('head classification:', headClassification)
|
||||
|
||||
check:
|
||||
name: Check
|
||||
needs: [prepare]
|
||||
uses: ./.github/workflows/check.yml
|
||||
permissions:
|
||||
# cherry-picks
|
||||
pull-requests: write
|
||||
with:
|
||||
baseBranch: ${{ needs.prepare.outputs.baseBranch }}
|
||||
|
||||
lint:
|
||||
name: Lint
|
||||
@ -70,11 +96,13 @@ jobs:
|
||||
|
||||
labels:
|
||||
name: Labels
|
||||
needs: [eval]
|
||||
needs: [prepare, eval]
|
||||
uses: ./.github/workflows/labels.yml
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
with:
|
||||
headBranch: ${{ needs.prepare.outputs.headBranch }}
|
||||
|
||||
reviewers:
|
||||
name: Reviewers
|
||||
@ -91,6 +119,7 @@ jobs:
|
||||
secrets:
|
||||
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
with:
|
||||
baseBranch: ${{ needs.prepare.outputs.baseBranch }}
|
||||
mergedSha: ${{ needs.prepare.outputs.mergedSha }}
|
||||
|
||||
# This job's only purpose is to serve as a target for the "Required Status Checks" branch ruleset.
|
||||
|
4
ci/.editorconfig
Normal file
4
ci/.editorconfig
Normal file
@ -0,0 +1,4 @@
|
||||
# TODO: Move to top-level via staging PR
|
||||
[*.js]
|
||||
indent_style = space
|
||||
indent_size = 2
|
29
ci/README.md
29
ci/README.md
@ -20,3 +20,32 @@ Arguments:
|
||||
|
||||
- `BASE_BRANCH`: The base branch to use, e.g. master or release-24.05
|
||||
- `REPOSITORY`: The repository from which to fetch the base branch. Defaults to <https://github.com/NixOS/nixpkgs.git>.
|
||||
|
||||
# Branch classification
|
||||
|
||||
For the purposes of CI, branches in the NixOS/nixpkgs repository are classified as follows:
|
||||
|
||||
- **Channel** branches
|
||||
- `nixos-` or `nixpkgs-` prefix
|
||||
- Are only updated from `master` or `release-` branches, when hydra passes.
|
||||
- Otherwise not worked on, Pull Requests are not allowed.
|
||||
- Long-lived, no deletion, no force push.
|
||||
- **Primary development** branches
|
||||
- `release-` prefix and `master`
|
||||
- Pull Requests required.
|
||||
- Long-lived, no deletion, no force push.
|
||||
- **Secondary development** branches
|
||||
- `staging-` prefix, `haskell-updates` and `python-updates`
|
||||
- Pull Requests normally required, except when merging development branches into each other.
|
||||
- Long-lived, no deletion, no force push.
|
||||
- **Work-In-Progress** branches
|
||||
- `backport-`, `revert-` and `wip-` prefixes.
|
||||
- Deprecated: All other branches, not matched by channel/development.
|
||||
- Pull Requests are optional.
|
||||
- Short-lived, force push allowed, deleted after merge.
|
||||
|
||||
Some branches also have a version component, which is either `unstable` or `YY.MM`.
|
||||
|
||||
`ci/supportedBranches.js` is a script imported by CI to classify the base and head branches of a Pull Request.
|
||||
This classification will then be used to skip certain jobs.
|
||||
This script can also be run locally to print basic test cases.
|
||||
|
62
ci/supportedBranches.js
Executable file
62
ci/supportedBranches.js
Executable file
@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
/*
|
||||
#!nix-shell -i node -p nodejs
|
||||
*/
|
||||
|
||||
const typeConfig = {
|
||||
master: ['development', 'primary'],
|
||||
release: ['development', 'primary'],
|
||||
staging: ['development', 'secondary'],
|
||||
'staging-next': ['development', 'secondary'],
|
||||
'haskell-updates': ['development', 'secondary'],
|
||||
'python-updates': ['development', 'secondary'],
|
||||
nixos: ['channel'],
|
||||
nixpkgs: ['channel'],
|
||||
}
|
||||
|
||||
function split(branch) {
|
||||
return { ...branch.match(/(?<prefix>.+?)(-(?<version>\d{2}\.\d{2}|unstable)(?:-(?<suffix>.*))?)?$/).groups }
|
||||
}
|
||||
|
||||
function classify(branch) {
|
||||
const { prefix, version } = split(branch)
|
||||
return {
|
||||
stable: (version ?? 'unstable') !== 'unstable',
|
||||
type: typeConfig[prefix] ?? [ 'wip' ]
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { classify }
|
||||
|
||||
// If called directly via CLI, runs the following tests:
|
||||
if (!module.parent) {
|
||||
console.log('split(branch)')
|
||||
function testSplit(branch) {
|
||||
console.log(branch, split(branch))
|
||||
}
|
||||
testSplit('master')
|
||||
testSplit('release-25.05')
|
||||
testSplit('staging-next')
|
||||
testSplit('staging-25.05')
|
||||
testSplit('staging-next-25.05')
|
||||
testSplit('nixpkgs-25.05-darwin')
|
||||
testSplit('nixpkgs-unstable')
|
||||
testSplit('haskell-updates')
|
||||
testSplit('backport-123-to-release-25.05')
|
||||
|
||||
console.log('')
|
||||
|
||||
console.log('classify(branch)')
|
||||
function testClassify(branch) {
|
||||
console.log(branch, classify(branch))
|
||||
}
|
||||
testClassify('master')
|
||||
testClassify('release-25.05')
|
||||
testClassify('staging-next')
|
||||
testClassify('staging-25.05')
|
||||
testClassify('staging-next-25.05')
|
||||
testClassify('nixpkgs-25.05-darwin')
|
||||
testClassify('nixpkgs-unstable')
|
||||
testClassify('haskell-updates')
|
||||
testClassify('backport-123-to-release-25.05')
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user