workflows/{check,reviewers}: don't run on staging-like PRs (#418496)

authored by Wolfgang Walther and committed by GitHub 767223d2 c3293bfb

+150 -27
+5 -2
.github/workflows/build.yml
··· 3 on: 4 workflow_call: 5 inputs: 6 mergedSha: 7 required: true 8 type: string ··· 63 - name: Build NixOS manual 64 if: | 65 contains(matrix.builds, 'manual-nixos') && !cancelled() && 66 - (github.base_ref == 'master' || startsWith(github.base_ref, 'release-')) 67 run: nix-build untrusted/ci -A manual-nixos --argstr system ${{ matrix.system }} --out-link nixos-manual 68 69 - name: Build Nixpkgs manual ··· 81 - name: Upload NixOS manual 82 if: | 83 contains(matrix.builds, 'manual-nixos') && !cancelled() && 84 - (github.base_ref == 'master' || startsWith(github.base_ref, 'release-')) 85 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 86 with: 87 name: nixos-manual-${{ matrix.system }}
··· 3 on: 4 workflow_call: 5 inputs: 6 + baseBranch: 7 + required: true 8 + type: string 9 mergedSha: 10 required: true 11 type: string ··· 66 - name: Build NixOS manual 67 if: | 68 contains(matrix.builds, 'manual-nixos') && !cancelled() && 69 + contains(fromJSON(inputs.baseBranch).type, 'primary') 70 run: nix-build untrusted/ci -A manual-nixos --argstr system ${{ matrix.system }} --out-link nixos-manual 71 72 - name: Build Nixpkgs manual ··· 84 - name: Upload NixOS manual 85 if: | 86 contains(matrix.builds, 'manual-nixos') && !cancelled() && 87 + contains(fromJSON(inputs.baseBranch).type, 'primary') 88 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 89 with: 90 name: nixos-manual-${{ matrix.system }}
+9 -5
.github/workflows/check.yml
··· 2 3 on: 4 workflow_call: 5 6 permissions: {} 7 ··· 12 jobs: 13 no-channel-base: 14 name: no channel base 15 - if: | 16 - startsWith(github.base_ref, 'nixos-') || 17 - startsWith(github.base_ref, 'nixpkgs-') 18 runs-on: ubuntu-24.04-arm 19 steps: 20 - run: | ··· 29 cherry-pick: 30 if: | 31 github.event_name == 'pull_request' || 32 - startsWith(github.base_ref, 'release-') || 33 - (startsWith(github.base_ref, 'staging-') && github.base_ref != 'staging-next') 34 permissions: 35 pull-requests: write 36 runs-on: ubuntu-24.04-arm
··· 2 3 on: 4 workflow_call: 5 + inputs: 6 + baseBranch: 7 + required: true 8 + type: string 9 + headBranch: 10 + required: true 11 + type: string 12 13 permissions: {} 14 ··· 19 jobs: 20 no-channel-base: 21 name: no channel base 22 + if: contains(fromJSON(inputs.baseBranch).type, 'channel') 23 runs-on: ubuntu-24.04-arm 24 steps: 25 - run: | ··· 34 cherry-pick: 35 if: | 36 github.event_name == 'pull_request' || 37 + (fromJSON(inputs.baseBranch).stable && !contains(fromJSON(inputs.headBranch).type, 'development')) 38 permissions: 39 pull-requests: write 40 runs-on: ubuntu-24.04-arm
+7 -18
.github/workflows/labels.yml
··· 9 schedule: 10 - cron: '07,17,27,37,47,57 * * * *' 11 workflow_call: 12 workflow_dispatch: 13 inputs: 14 updatedWithin: ··· 275 name: Labels from touched files 276 if: | 277 github.event_name == 'pull_request_target' && 278 - (github.event.pull_request.head.repo.owner.login != 'NixOS' || !( 279 - github.head_ref == 'haskell-updates' || 280 - github.head_ref == 'python-updates' || 281 - github.head_ref == 'staging-next' || 282 - startsWith(github.head_ref, 'staging-next-') 283 - )) 284 with: 285 repo-token: ${{ secrets.GITHUB_TOKEN }} 286 configuration-path: .github/labeler.yml # default ··· 290 name: Labels from touched files (no sync) 291 if: | 292 github.event_name == 'pull_request_target' && 293 - (github.event.pull_request.head.repo.owner.login != 'NixOS' || !( 294 - github.head_ref == 'haskell-updates' || 295 - github.head_ref == 'python-updates' || 296 - github.head_ref == 'staging-next' || 297 - startsWith(github.head_ref, 'staging-next-') 298 - )) 299 with: 300 repo-token: ${{ secrets.GITHUB_TOKEN }} 301 configuration-path: .github/labeler-no-sync.yml ··· 308 # the backport labels. 309 if: | 310 github.event_name == 'pull_request_target' && 311 - (github.event.pull_request.head.repo.owner.login == 'NixOS' && ( 312 - github.head_ref == 'haskell-updates' || 313 - github.head_ref == 'python-updates' || 314 - github.head_ref == 'staging-next' || 315 - startsWith(github.head_ref, 'staging-next-') 316 - )) 317 with: 318 repo-token: ${{ secrets.GITHUB_TOKEN }} 319 configuration-path: .github/labeler-development-branches.yml
··· 9 schedule: 10 - cron: '07,17,27,37,47,57 * * * *' 11 workflow_call: 12 + inputs: 13 + headBranch: 14 + required: true 15 + type: string 16 workflow_dispatch: 17 inputs: 18 updatedWithin: ··· 279 name: Labels from touched files 280 if: | 281 github.event_name == 'pull_request_target' && 282 + !contains(fromJSON(inputs.headBranch).type, 'development') 283 with: 284 repo-token: ${{ secrets.GITHUB_TOKEN }} 285 configuration-path: .github/labeler.yml # default ··· 289 name: Labels from touched files (no sync) 290 if: | 291 github.event_name == 'pull_request_target' && 292 + !contains(fromJSON(inputs.headBranch).type, 'development') 293 with: 294 repo-token: ${{ secrets.GITHUB_TOKEN }} 295 configuration-path: .github/labeler-no-sync.yml ··· 302 # the backport labels. 303 if: | 304 github.event_name == 'pull_request_target' && 305 + contains(fromJSON(inputs.headBranch).type, 'development') 306 with: 307 repo-token: ${{ secrets.GITHUB_TOKEN }} 308 configuration-path: .github/labeler-development-branches.yml
+34 -2
.github/workflows/pr.yml
··· 22 prepare: 23 runs-on: ubuntu-24.04-arm 24 outputs: 25 mergedSha: ${{ steps.get-merge-commit.outputs.mergedSha }} 26 targetSha: ${{ steps.get-merge-commit.outputs.targetSha }} 27 systems: ${{ steps.systems.outputs.systems }} ··· 30 with: 31 sparse-checkout: | 32 .github/actions 33 ci/supportedSystems.json 34 - name: Check if the PR can be merged and get the test merge commit 35 uses: ./.github/actions/get-merge-commit ··· 40 run: | 41 echo "systems=$(jq -c <ci/supportedSystems.json)" >> "$GITHUB_OUTPUT" 42 43 check: 44 name: Check 45 uses: ./.github/workflows/check.yml 46 permissions: 47 # cherry-picks 48 pull-requests: write 49 50 lint: 51 name: Lint ··· 71 72 labels: 73 name: Labels 74 - needs: [eval] 75 uses: ./.github/workflows/labels.yml 76 permissions: 77 issues: write 78 pull-requests: write 79 80 reviewers: 81 name: Reviewers 82 needs: [prepare, eval] 83 - if: needs.prepare.outputs.targetSha 84 uses: ./.github/workflows/reviewers.yml 85 secrets: 86 OWNER_APP_PRIVATE_KEY: ${{ secrets.OWNER_APP_PRIVATE_KEY }} ··· 92 secrets: 93 CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }} 94 with: 95 mergedSha: ${{ needs.prepare.outputs.mergedSha }} 96 97 # This job's only purpose is to serve as a target for the "Required Status Checks" branch ruleset.
··· 22 prepare: 23 runs-on: ubuntu-24.04-arm 24 outputs: 25 + baseBranch: ${{ steps.branches.outputs.base }} 26 + headBranch: ${{ steps.branches.outputs.head }} 27 mergedSha: ${{ steps.get-merge-commit.outputs.mergedSha }} 28 targetSha: ${{ steps.get-merge-commit.outputs.targetSha }} 29 systems: ${{ steps.systems.outputs.systems }} ··· 32 with: 33 sparse-checkout: | 34 .github/actions 35 + ci/supportedBranches.js 36 ci/supportedSystems.json 37 - name: Check if the PR can be merged and get the test merge commit 38 uses: ./.github/actions/get-merge-commit ··· 43 run: | 44 echo "systems=$(jq -c <ci/supportedSystems.json)" >> "$GITHUB_OUTPUT" 45 46 + - name: Determine branch type 47 + id: branches 48 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 49 + with: 50 + script: | 51 + const { classify } = require('./ci/supportedBranches.js') 52 + const { base, head } = context.payload.pull_request 53 + 54 + const baseClassification = classify(base.ref) 55 + core.setOutput('base', baseClassification) 56 + core.info('base classification:', baseClassification) 57 + 58 + const headClassification = 59 + (base.repo.full_name == head.repo.full_name) ? 60 + classify(head.ref) : 61 + // PRs from forks are always considered WIP. 62 + { type: ['wip'] } 63 + core.setOutput('head', headClassification) 64 + core.info('head classification:', headClassification) 65 + 66 check: 67 name: Check 68 + needs: [prepare] 69 uses: ./.github/workflows/check.yml 70 permissions: 71 # cherry-picks 72 pull-requests: write 73 + with: 74 + baseBranch: ${{ needs.prepare.outputs.baseBranch }} 75 + headBranch: ${{ needs.prepare.outputs.headBranch }} 76 77 lint: 78 name: Lint ··· 98 99 labels: 100 name: Labels 101 + needs: [prepare, eval] 102 uses: ./.github/workflows/labels.yml 103 permissions: 104 issues: write 105 pull-requests: write 106 + with: 107 + headBranch: ${{ needs.prepare.outputs.headBranch }} 108 109 reviewers: 110 name: Reviewers 111 needs: [prepare, eval] 112 + if: | 113 + needs.prepare.outputs.targetSha && 114 + !contains(fromJSON(needs.prepare.outputs.headBranch).type, 'development') 115 uses: ./.github/workflows/reviewers.yml 116 secrets: 117 OWNER_APP_PRIVATE_KEY: ${{ secrets.OWNER_APP_PRIVATE_KEY }} ··· 123 secrets: 124 CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }} 125 with: 126 + baseBranch: ${{ needs.prepare.outputs.baseBranch }} 127 mergedSha: ${{ needs.prepare.outputs.mergedSha }} 128 129 # This job's only purpose is to serve as a target for the "Required Status Checks" branch ruleset.
+4
ci/.editorconfig
···
··· 1 + # TODO: Move to top-level via staging PR 2 + [*.js] 3 + indent_style = space 4 + indent_size = 2
+29
ci/README.md
··· 20 21 - `BASE_BRANCH`: The base branch to use, e.g. master or release-24.05 22 - `REPOSITORY`: The repository from which to fetch the base branch. Defaults to <https://github.com/NixOS/nixpkgs.git>.
··· 20 21 - `BASE_BRANCH`: The base branch to use, e.g. master or release-24.05 22 - `REPOSITORY`: The repository from which to fetch the base branch. Defaults to <https://github.com/NixOS/nixpkgs.git>. 23 + 24 + # Branch classification 25 + 26 + For the purposes of CI, branches in the NixOS/nixpkgs repository are classified as follows: 27 + 28 + - **Channel** branches 29 + - `nixos-` or `nixpkgs-` prefix 30 + - Are only updated from `master` or `release-` branches, when hydra passes. 31 + - Otherwise not worked on, Pull Requests are not allowed. 32 + - Long-lived, no deletion, no force push. 33 + - **Primary development** branches 34 + - `release-` prefix and `master` 35 + - Pull Requests required. 36 + - Long-lived, no deletion, no force push. 37 + - **Secondary development** branches 38 + - `staging-` prefix, `haskell-updates` and `python-updates` 39 + - Pull Requests normally required, except when merging development branches into each other. 40 + - Long-lived, no deletion, no force push. 41 + - **Work-In-Progress** branches 42 + - `backport-`, `revert-` and `wip-` prefixes. 43 + - Deprecated: All other branches, not matched by channel/development. 44 + - Pull Requests are optional. 45 + - Short-lived, force push allowed, deleted after merge. 46 + 47 + Some branches also have a version component, which is either `unstable` or `YY.MM`. 48 + 49 + `ci/supportedBranches.js` is a script imported by CI to classify the base and head branches of a Pull Request. 50 + This classification will then be used to skip certain jobs. 51 + This script can also be run locally to print basic test cases.
+62
ci/supportedBranches.js
···
··· 1 + #!/usr/bin/env nix-shell 2 + /* 3 + #!nix-shell -i node -p nodejs 4 + */ 5 + 6 + const typeConfig = { 7 + master: ['development', 'primary'], 8 + release: ['development', 'primary'], 9 + staging: ['development', 'secondary'], 10 + 'staging-next': ['development', 'secondary'], 11 + 'haskell-updates': ['development', 'secondary'], 12 + 'python-updates': ['development', 'secondary'], 13 + nixos: ['channel'], 14 + nixpkgs: ['channel'], 15 + } 16 + 17 + function split(branch) { 18 + return { ...branch.match(/(?<prefix>.+?)(-(?<version>\d{2}\.\d{2}|unstable)(?:-(?<suffix>.*))?)?$/).groups } 19 + } 20 + 21 + function classify(branch) { 22 + const { prefix, version } = split(branch) 23 + return { 24 + stable: (version ?? 'unstable') !== 'unstable', 25 + type: typeConfig[prefix] ?? [ 'wip' ] 26 + } 27 + } 28 + 29 + module.exports = { classify } 30 + 31 + // If called directly via CLI, runs the following tests: 32 + if (!module.parent) { 33 + console.log('split(branch)') 34 + function testSplit(branch) { 35 + console.log(branch, split(branch)) 36 + } 37 + testSplit('master') 38 + testSplit('release-25.05') 39 + testSplit('staging-next') 40 + testSplit('staging-25.05') 41 + testSplit('staging-next-25.05') 42 + testSplit('nixpkgs-25.05-darwin') 43 + testSplit('nixpkgs-unstable') 44 + testSplit('haskell-updates') 45 + testSplit('backport-123-to-release-25.05') 46 + 47 + console.log('') 48 + 49 + console.log('classify(branch)') 50 + function testClassify(branch) { 51 + console.log(branch, classify(branch)) 52 + } 53 + testClassify('master') 54 + testClassify('release-25.05') 55 + testClassify('staging-next') 56 + testClassify('staging-25.05') 57 + testClassify('staging-next-25.05') 58 + testClassify('nixpkgs-25.05-darwin') 59 + testClassify('nixpkgs-unstable') 60 + testClassify('haskell-updates') 61 + testClassify('backport-123-to-release-25.05') 62 + }