+51
.github/actions/checkout/action.yml
+51
.github/actions/checkout/action.yml
···
1
+
name: Checkout
2
+
3
+
description: 'Checkout into trusted / untrusted / pinned folders consistently.'
4
+
5
+
inputs:
6
+
merged-as-untrusted-at:
7
+
description: "Whether and which SHA to checkout for the merge commit in the ./untrusted folder."
8
+
pinned-from:
9
+
description: "Whether to checkout the pinned nixpkgs for CI and from where (trusted, untrusted)."
10
+
target-as-trusted-at:
11
+
description: "Whether and which SHA to checkout for the target commit in the ./trusted folder."
12
+
13
+
runs:
14
+
using: composite
15
+
steps:
16
+
- if: inputs.merged-as-untrusted-at
17
+
# Would be great to do the checkouts in git worktrees of the existing spare checkout instead,
18
+
# but Nix is broken with them:
19
+
# https://github.com/NixOS/nix/issues/6073
20
+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
21
+
with:
22
+
ref: ${{ inputs.merged-as-untrusted-at }}
23
+
path: untrusted
24
+
25
+
- if: inputs.target-as-trusted-at
26
+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
27
+
with:
28
+
ref: ${{ inputs.target-as-trusted-at }}
29
+
path: trusted
30
+
31
+
- if: inputs.pinned-from
32
+
id: pinned
33
+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
34
+
env:
35
+
PINNED_FROM: ${{ inputs.pinned-from }}
36
+
with:
37
+
script: |
38
+
const path = require('node:path')
39
+
const pinned = require(path.resolve(path.join(process.env.PINNED_FROM, 'ci', 'pinned.json')))
40
+
core.setOutput('pinned-at', pinned.pins.nixpkgs.revision)
41
+
42
+
- if: steps.pinned.outputs.pinned-at
43
+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
44
+
with:
45
+
ref: ${{ steps.pinned.outputs.pinned-at }}
46
+
path: pinned
47
+
sparse-checkout: |
48
+
lib
49
+
maintainers
50
+
nixos/lib
51
+
pkgs
-80
.github/actions/get-merge-commit/action.yml
-80
.github/actions/get-merge-commit/action.yml
···
1
-
name: Get merge commit
2
-
3
-
description: 'Checks whether the Pull Request is mergeable and checks out the repo at up to two commits: The result of a temporary merge of the head branch into the target branch ("merged"), and the parent of that commit on the target branch ("target"). Handles push events and merge conflicts gracefully.'
4
-
5
-
inputs:
6
-
mergedSha:
7
-
description: "The merge commit SHA, previously collected."
8
-
type: string
9
-
merged-as-untrusted:
10
-
description: "Whether to checkout the merge commit in the ./untrusted folder."
11
-
type: boolean
12
-
pinnedFrom:
13
-
description: "Whether to checkout the pinned nixpkgs for CI and from where (trusted, untrusted)."
14
-
type: string
15
-
targetSha:
16
-
description: "The target commit SHA, previously collected."
17
-
type: string
18
-
target-as-trusted:
19
-
description: "Whether to checkout the target commit in the ./trusted folder."
20
-
type: boolean
21
-
22
-
outputs:
23
-
mergedSha:
24
-
description: "The merge commit SHA"
25
-
value: ${{ steps.commits.outputs.mergedSha }}
26
-
targetSha:
27
-
description: "The target commit SHA"
28
-
value: ${{ steps.commits.outputs.targetSha }}
29
-
30
-
runs:
31
-
using: composite
32
-
steps:
33
-
- id: commits
34
-
if: ${{ !inputs.mergedSha && !inputs.targetSha }}
35
-
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
36
-
with:
37
-
script: |
38
-
require('./ci/github-script/prepare.js')({
39
-
github,
40
-
context,
41
-
core,
42
-
})
43
-
44
-
- if: inputs.merged-as-untrusted && (inputs.mergedSha || steps.commits.outputs.mergedSha)
45
-
# Would be great to do the checkouts in git worktrees of the existing spare checkout instead,
46
-
# but Nix is broken with them:
47
-
# https://github.com/NixOS/nix/issues/6073
48
-
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
49
-
with:
50
-
ref: ${{ inputs.mergedSha || steps.commits.outputs.mergedSha }}
51
-
path: untrusted
52
-
53
-
- if: inputs.target-as-trusted && (inputs.targetSha || steps.commits.outputs.targetSha)
54
-
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
55
-
with:
56
-
ref: ${{ inputs.targetSha || steps.commits.outputs.targetSha }}
57
-
path: trusted
58
-
59
-
- if: inputs.pinnedFrom
60
-
id: pinned
61
-
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
62
-
env:
63
-
PINNED_FROM: ${{ inputs.pinnedFrom }}
64
-
with:
65
-
script: |
66
-
const path = require('node:path')
67
-
const pinned = require(path.resolve(path.join(process.env.PINNED_FROM, 'ci', 'pinned.json')))
68
-
core.setOutput('pinnedSha', pinned.pins.nixpkgs.revision)
69
-
70
-
- if: steps.pinned.outputs.pinnedSha
71
-
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
72
-
with:
73
-
ref: ${{ steps.pinned.outputs.pinnedSha }}
74
-
path: pinned
75
-
sparse-checkout: |
76
-
lib
77
-
maintainers
78
-
nixos/lib
79
-
pkgs
80
-
+1
-1
.github/workflows/README.md
+1
-1
.github/workflows/README.md
···
17
17
This is a temporary commit that GitHub creates automatically as "what would happen, if this PR was merged into the base branch now?".
18
18
The checkout could be done via the virtual branch `refs/pull/<pr-number>/merge`, but doing so would cause failures when this virtual branch doesn't exist (anymore).
19
19
This can happen when the PR has conflicts, in which case the virtual branch is not created, or when the PR is getting merged while workflows are still running, in which case the branch won't exist anymore at the time of checkout.
20
-
Thus, we use the `get-merge-commit.yml` workflow to check whether the PR is mergeable and the test merge commit exists and only then run the relevant jobs.
20
+
Thus, we use the `prepare` job to check whether the PR is mergeable and the test merge commit exists and only then run the relevant jobs.
21
21
22
22
- Various workflows need to make comparisons against the base branch.
23
23
In this case, we checkout the parent of the "test merge commit" for best results.
+4
-5
.github/workflows/build.yml
+4
-5
.github/workflows/build.yml
···
47
47
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
48
48
with:
49
49
sparse-checkout: .github/actions
50
-
- name: Check if the PR can be merged and checkout the merge commit
51
-
uses: ./.github/actions/get-merge-commit
50
+
- name: Checkout the merge commit
51
+
uses: ./.github/actions/checkout
52
52
with:
53
-
mergedSha: ${{ inputs.mergedSha }}
54
-
merged-as-untrusted: true
55
-
pinnedFrom: untrusted
53
+
merged-as-untrusted-at: ${{ inputs.mergedSha }}
54
+
pinned-from: untrusted
56
55
57
56
- uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31
58
57
with:
+5
-7
.github/workflows/check.yml
+5
-7
.github/workflows/check.yml
···
99
99
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
100
100
with:
101
101
sparse-checkout: .github/actions
102
-
- name: Check if the PR can be merged and checkout the merge and target commits
103
-
uses: ./.github/actions/get-merge-commit
102
+
- name: Checkout merge and target commits
103
+
uses: ./.github/actions/checkout
104
104
with:
105
-
mergedSha: ${{ inputs.mergedSha }}
106
-
merged-as-untrusted: true
107
-
pinnedFrom: trusted
108
-
targetSha: ${{ inputs.targetSha }}
109
-
target-as-trusted: true
105
+
merged-as-untrusted-at: ${{ inputs.mergedSha }}
106
+
pinned-from: trusted
107
+
target-as-trusted-at: ${{ inputs.targetSha }}
110
108
111
109
- uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31
112
110
+9
-12
.github/workflows/eval.yml
+9
-12
.github/workflows/eval.yml
···
90
90
with:
91
91
sparse-checkout: .github/actions
92
92
- name: Check out the PR at the test merge commit
93
-
uses: ./.github/actions/get-merge-commit
93
+
uses: ./.github/actions/checkout
94
94
with:
95
-
mergedSha: ${{ inputs.mergedSha }}
96
-
merged-as-untrusted: true
97
-
pinnedFrom: untrusted
95
+
merged-as-untrusted-at: ${{ inputs.mergedSha }}
96
+
pinned-from: untrusted
98
97
99
98
- name: Install Nix
100
99
uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31
···
216
215
with:
217
216
sparse-checkout: .github/actions
218
217
- name: Check out the PR at the target commit
219
-
uses: ./.github/actions/get-merge-commit
218
+
uses: ./.github/actions/checkout
220
219
with:
221
-
targetSha: ${{ inputs.targetSha }}
222
-
target-as-trusted: true
223
-
pinnedFrom: trusted
220
+
target-as-trusted-at: ${{ inputs.targetSha }}
221
+
pinned-from: trusted
224
222
225
223
- name: Download output paths and eval stats for all systems
226
224
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
···
385
383
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
386
384
with:
387
385
sparse-checkout: .github/actions
388
-
- name: Check if the PR can be merged and checkout the merge commit
389
-
uses: ./.github/actions/get-merge-commit
386
+
- name: Checkout the merge commit
387
+
uses: ./.github/actions/checkout
390
388
with:
391
-
mergedSha: ${{ inputs.mergedSha }}
392
-
merged-as-untrusted: true
389
+
merged-as-untrusted-at: ${{ inputs.mergedSha }}
393
390
394
391
- name: Install Nix
395
392
uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31
+13
-17
.github/workflows/lint.yml
+13
-17
.github/workflows/lint.yml
···
27
27
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
28
28
with:
29
29
sparse-checkout: .github/actions
30
-
- name: Check if the PR can be merged and checkout the merge commit
31
-
uses: ./.github/actions/get-merge-commit
30
+
- name: Checkout the merge commit
31
+
uses: ./.github/actions/checkout
32
32
with:
33
-
mergedSha: ${{ inputs.mergedSha }}
34
-
merged-as-untrusted: true
35
-
pinnedFrom: untrusted
33
+
merged-as-untrusted-at: ${{ inputs.mergedSha }}
34
+
pinned-from: untrusted
36
35
37
36
- uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31
38
37
···
63
62
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
64
63
with:
65
64
sparse-checkout: .github/actions
66
-
- name: Check if the PR can be merged and checkout the merge commit
67
-
uses: ./.github/actions/get-merge-commit
65
+
- name: Checkout the merge commit
66
+
uses: ./.github/actions/checkout
68
67
with:
69
-
mergedSha: ${{ inputs.mergedSha }}
70
-
merged-as-untrusted: true
71
-
pinnedFrom: untrusted
68
+
merged-as-untrusted-at: ${{ inputs.mergedSha }}
69
+
pinned-from: untrusted
72
70
73
71
- uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31
74
72
···
92
90
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
93
91
with:
94
92
sparse-checkout: .github/actions
95
-
- name: Check if the PR can be merged and checkout merged and target commits
96
-
uses: ./.github/actions/get-merge-commit
93
+
- name: Checkout merge and target commits
94
+
uses: ./.github/actions/checkout
97
95
with:
98
-
mergedSha: ${{ inputs.mergedSha }}
99
-
merged-as-untrusted: true
100
-
pinnedFrom: untrusted
101
-
targetSha: ${{ inputs.targetSha }}
102
-
target-as-trusted: true
96
+
merged-as-untrusted-at: ${{ inputs.mergedSha }}
97
+
pinned-from: untrusted
98
+
target-as-trusted-at: ${{ inputs.targetSha }}
103
99
104
100
- uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31
105
101
+14
-49
.github/workflows/pr.yml
+14
-49
.github/workflows/pr.yml
···
3
3
on:
4
4
pull_request:
5
5
paths:
6
-
- .github/actions/get-merge-commit/action.yml
6
+
- .github/actions/checkout/action.yml
7
7
- .github/workflows/build.yml
8
8
- .github/workflows/check.yml
9
9
- .github/workflows/eval.yml
···
23
23
prepare:
24
24
runs-on: ubuntu-24.04-arm
25
25
outputs:
26
-
baseBranch: ${{ steps.branches.outputs.base }}
27
-
headBranch: ${{ steps.branches.outputs.head }}
28
-
mergedSha: ${{ steps.get-merge-commit.outputs.mergedSha }}
29
-
targetSha: ${{ steps.get-merge-commit.outputs.targetSha }}
30
-
systems: ${{ steps.systems.outputs.systems }}
31
-
touched: ${{ steps.files.outputs.touched }}
26
+
baseBranch: ${{ steps.prepare.outputs.base }}
27
+
headBranch: ${{ steps.prepare.outputs.head }}
28
+
mergedSha: ${{ steps.prepare.outputs.mergedSha }}
29
+
targetSha: ${{ steps.prepare.outputs.targetSha }}
30
+
systems: ${{ steps.prepare.outputs.systems }}
31
+
touched: ${{ steps.prepare.outputs.touched }}
32
32
steps:
33
33
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
34
34
with:
35
+
sparse-checkout-cone-mode: true # default, for clarity
35
36
sparse-checkout: |
36
-
.github/actions
37
37
ci/github-script
38
-
ci/supportedBranches.js
39
-
ci/supportedSystems.json
40
-
- name: Check if the PR can be merged and get the test merge commit
41
-
uses: ./.github/actions/get-merge-commit
42
-
id: get-merge-commit
43
-
44
-
- name: Load supported systems
45
-
id: systems
46
-
run: |
47
-
echo "systems=$(jq -c <ci/supportedSystems.json)" >> "$GITHUB_OUTPUT"
48
-
49
-
- name: Determine branch type
50
-
id: branches
38
+
- id: prepare
51
39
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
52
40
with:
53
41
script: |
54
-
const { classify } = require('./ci/supportedBranches.js')
55
-
const { base, head } = context.payload.pull_request
56
-
57
-
const baseClassification = classify(base.ref)
58
-
core.setOutput('base', baseClassification)
59
-
core.info('base classification:', baseClassification)
60
-
61
-
const headClassification =
62
-
(base.repo.full_name == head.repo.full_name) ?
63
-
classify(head.ref) :
64
-
// PRs from forks are always considered WIP.
65
-
{ type: ['wip'] }
66
-
core.setOutput('head', headClassification)
67
-
core.info('head classification:', headClassification)
68
-
69
-
- name: Determine changed files
70
-
id: files
71
-
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
72
-
with:
73
-
script: |
74
-
const files = (await github.paginate(github.rest.pulls.listFiles, {
75
-
...context.repo,
76
-
pull_number: context.payload.pull_request.number,
77
-
per_page: 100,
78
-
})).map(file => file.filename)
79
-
80
-
if (files.includes('ci/pinned.json')) core.setOutput('touched', ['pinned'])
81
-
else core.setOutput('touched', [])
42
+
require('./ci/github-script/prepare.js')({
43
+
github,
44
+
context,
45
+
core,
46
+
})
82
47
83
48
check:
84
49
name: Check
+31
-1
ci/github-script/prepare.js
+31
-1
ci/github-script/prepare.js
···
1
+
const { classify } = require('../supportedBranches.js')
2
+
1
3
module.exports = async ({ github, context, core }) => {
2
4
const pull_number = context.payload.pull_request.number
3
5
···
19
21
await new Promise((resolve) => setTimeout(resolve, retryInterval * 1000))
20
22
continue
21
23
}
24
+
25
+
const { base, head } = prInfo
22
26
23
27
let mergedSha, targetSha
24
28
···
39
43
targetSha = (
40
44
await github.rest.repos.compareCommitsWithBasehead({
41
45
...context.repo,
42
-
basehead: `${prInfo.base.sha}...${prInfo.head.sha}`,
46
+
basehead: `${base.sha}...${head.sha}`,
43
47
})
44
48
).data.merge_base_commit.sha
45
49
}
···
49
53
)
50
54
core.setOutput('mergedSha', mergedSha)
51
55
core.setOutput('targetSha', targetSha)
56
+
57
+
core.setOutput('systems', require('../supportedSystems.json'))
58
+
59
+
const baseClassification = classify(base.ref)
60
+
core.setOutput('base', baseClassification)
61
+
console.log('base classification:', baseClassification)
62
+
63
+
const headClassification =
64
+
base.repo.full_name === head.repo.full_name
65
+
? classify(head.ref)
66
+
: // PRs from forks are always considered WIP.
67
+
{ type: ['wip'] }
68
+
core.setOutput('head', headClassification)
69
+
console.log('head classification:', headClassification)
70
+
71
+
const files = (
72
+
await github.paginate(github.rest.pulls.listFiles, {
73
+
...context.repo,
74
+
pull_number: context.payload.pull_request.number,
75
+
per_page: 100,
76
+
})
77
+
).map((file) => file.filename)
78
+
79
+
if (files.includes('ci/pinned.json')) core.setOutput('touched', ['pinned'])
80
+
else core.setOutput('touched', [])
81
+
52
82
return
53
83
}
54
84
throw new Error(