-
Notifications
You must be signed in to change notification settings - Fork 7
377 lines (335 loc) · 13.9 KB
/
ci-workflow.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
name: nixbuild-ci
on:
workflow_call:
secrets:
nixbuild_token:
required: true
description: |
The private auth token used to access nixbuild.net.
You should not add your private token directly to the workflow file but
instead define a GitHub Secret for it, to avoid mistakenly sharing your
token with others.
Follow the instructions in the README of this action for instructions
on how to create and configure your auth token.
The token must have the permissions 'build:read', 'build:write',
'store:read' and 'store:write'.
See https://docs.nixbuild.net/access-control/ for more details on auth
tokens and permissions.
github_access_token:
required: false
description: |
Defines the access token Nix should use when fetching from GitHub.
outputs:
success:
value: ${{ jobs.summary.outputs.success }}
description: |
Outputs the string 'true' if all builds succeeded, otherwise 'false'.
You need to set `ignore_build_failures` to `true` in order to get the
'false' result, otherwise your workflow will be terminated before
you can use this output.
results:
value: ${{ jobs.summary.outputs.results }}
description: |
Contains a JSON object that maps each build to its result. Look at the
file `examples/using-the-ci-workflow/expected-result.json` to see an
example.
inputs:
nix_version:
type: string
default: '2.21.0'
required: false
description: |
The version of Nix that should be used.
See available versions at
https://github.com/nixbuild/nix-quick-install-action/releases/tag/v28.
nix_conf:
type: string
default: ''
required: false
description: |
Nix configuration passed to `nix-quick-install-action`.
ignore_build_failures:
type: boolean
required: false
default: false
description: |
If true, the workflow will not fail even if one or more builds fail.
This is useful if you want to process the build results in a
subsequent job. For an example of this, see the workflow in
`.github/workflows/ci-example.yml`.
fail_fast:
type: boolean
required: false
default: false
description: |
If true, any remaining builds will be cancelled when the first build
failure is found. If false, all builds will be attempted no matter how
many builds fail. Note, `ignore_build_failures` must be false for this
option have any effect. If `ignore_build_failures` is true, no builds
will be cancelled.
filter_builds:
type: string
required: false
default: '.top_attr == "checks"'
description: |
A `jq` boolean expression that decides which builds from `flake.nix`
to build. See the `jq` documentation for info on how to write boolean
expressions: https://stedolan.github.io/jq/manual/.
When evaluating the expression, the following fields will be
available:
.top_attr : Either "checks" or "packages"
.system : The build's system ("x86_64-linux", "aarch64-linux" etc)
.attr : The build's attribute name, as defined in your flake
.name : The build's derivation name
label_builds:
type: string
required: false
default: '"\(.attr) [\(.system)]"'
description: |
A `jq` string expression that defines the label of the build. The
label is visible in the GitHub Actions UI.
See the `jq` documentation for info on how to write string
expressions: https://stedolan.github.io/jq/manual/.
When evaluating the expression, the following fields will be
available:
.top_attr : Either "checks" or "packages"
.system : The build's system ("x86_64-linux", "aarch64-linux" etc)
.attr : The build's attribute name, as defined in your flake
.name : The build's derivation name
flake_directory:
type: string
required: false
default: '.'
description: |
The path to the directory in your repository that contains the
`flake.nix` file you want the workflow to build.
pre_evaluation_script:
type: string
required: false
default: ''
description: |
Bash script that should be executed before evaluating the flake.
pre_build_script:
type: string
required: false
default: ''
description: |
Bash script that should be executed before running each build. Note,
every build runs as a separate job so this script (and all builds)
will be executed in parallel.
generate_build_summary:
type: boolean
default: true
description: |
Generate a summary of all builds that has been running during the
workflow. If you are using ci-workflow.yml multiple times in your
workflow, it can make sense to disable this summary since otherwise
you will get the same summary generated multiple times. In such cases,
you can add an explicit summary job that runs after all other workflow
jobs and uses nixbuild-action to generate the summary only one time.
caches:
type: string
default: ''
required: false
description: |
Set the caches setting in nixbuild.net. For documentation
see https://docs.nixbuild.net/settings/#caches.
Separate multiple caches with a comma.
You must have corresponding access tokens setup in your account on
nixbuild.net, see https://docs.nixbuild.net/settings/#access-tokens.
reuse-build-failures:
type: boolean
default: true
required: false
description: |
Set the reuse-build-failures setting in nixbuild.net. For
documentation see
https://docs.nixbuild.net/settings/#reuse-build-failures.
reuse-build-timeouts:
type: boolean
default: false
required: false
description: |
Set the reuse-build-timeouts setting in nixbuild.net. For
documentation see
https://docs.nixbuild.net/settings/#reuse-build-timeouts.
lfs:
type: boolean
default: false
required: false
description: |
Use git-lfs when checking out the repository for the build job.
See: https://github.com/actions/checkout
nix_on_tmpfs:
type: boolean
default: false
required: false
description: |
On the GitHub runner, put /nix on tmpfs to speed up evaluation. This
is usually fine to do, since only files used for evaluation will be
stored in the local Nix store. However, if you have many large
sources you might run out of disk space during evaluation.
artifact_prefix:
type: string
default: ''
required: false
description: |
The CI workflow stores two build artifacts, one for build logs and
one for JSON representations of the build results. To be able to
reuse the CI workflow multiple times inside the same workflow, a
unique artifact prefix is generated. If you want to set the prefix
yourself you can do it with this setting. Remember that you can't
use the same prefix for multiple invocations of the CI workflow
within the same workflow.
jobs:
eval-flake:
name: "Evaluate flake"
runs-on: ubuntu-latest
outputs:
builds: ${{ steps.find-builds.outputs.builds }}
steps:
- uses: actions/checkout@v4
- uses: nixbuild/nix-quick-install-action@master
with:
github_access_token: ${{secrets.github_access_token}}
nix_on_tmpfs: ${{inputs.nix_on_tmpfs}}
nix_conf: |
experimental-features = nix-command flakes
${{inputs.nix_conf}}
nix_version: ${{inputs.nix_version}}
- name: Pre-evaluation script
run: ${{inputs.pre_evaluation_script}}
- name: Find builds
id: find-builds
run: |
set -eo pipefail
flake_json="$(mktemp)"
# For Nix >= 2.14 we need --all-systems
if [[ "${{inputs.nix_version}}" =~ 2\.1[456789].* ]]; then
all_systems="--all-systems"
elif [[ "${{inputs.nix_version}}" =~ 2\.2.* ]]; then
all_systems="--all-systems"
else
all_systems=""
fi
nix flake show "./${{inputs.flake_directory}}" $all_systems --json > "$flake_json"
jq < "$flake_json" -rc '{checks: (.checks // {}), packages: (.packages // {})}|to_entries|map(.key as $top_attr | .value|to_entries|map(.key as $sys | .value|to_entries|map(.key as $attr | {name: "", description: "", top_attr: $top_attr, system: $sys, attr: $attr} + .value)))|flatten|map(select(${{inputs.filter_builds}}))|map(. as $x | (${{inputs.label_builds}}) as $l | $x + {label: $l})|"builds=\(.)"' >> "$GITHUB_OUTPUT"
build:
name: ${{matrix.build.label}}
needs: eval-flake
runs-on: ubuntu-latest
strategy:
fail-fast: ${{ inputs.fail_fast }}
matrix:
build: ${{fromJSON(needs.eval-flake.outputs.builds)}}
steps:
- uses: actions/checkout@v4
with:
lfs: ${{ inputs.lfs }}
- uses: nixbuild/nix-quick-install-action@master
with:
github_access_token: ${{secrets.github_access_token}}
nix_on_tmpfs: ${{inputs.nix_on_tmpfs}}
nix_conf: |
experimental-features = nix-command flakes
${{inputs.nix_conf}}
nix_version: ${{inputs.nix_version}}
- uses: nixbuild/nixbuild-action@master
with:
nixbuild_token: ${{secrets.nixbuild_token}}
caches: ${{inputs.caches}}
reuse-build-failures: ${{inputs.reuse-build-failures}}
reuse-build-timeouts: ${{inputs.reuse-build-timeouts}}
- name: Pre-build script
run: ${{inputs.pre_build_script}}
- name: "Build ${{matrix.build.top_attr}}.${{matrix.build.system}}.${{matrix.build.attr}}"
id: build
run: |
ARTIFACT_PREFIX="$(echo "${{matrix.build.top_attr}}.${{matrix.build.system}}.${{matrix.build.attr}}" | tr '":<>|*?\\/' '_')-$RANDOM$RANDOM"
echo "ARTIFACT_PREFIX=$ARTIFACT_PREFIX" >> "$GITHUB_ENV"
RESULTS="build.json"
LOGS="$ARTIFACT_PREFIX.log"
touch "$RESULTS"
nix build "./${{inputs.flake_directory}}#${{matrix.build.top_attr}}.${{matrix.build.system}}.${{matrix.build.attr}}" \
--print-build-logs \
--eval-store auto \
--store ssh-ng://eu.nixbuild.net \
--builders "" --max-jobs 2 \
--json > "$RESULTS" \
2> >(tee -a "$LOGS" >&2) || true
status=0
if ! [ -s "$RESULTS" ]; then
echo '[{"success":false}]' > "$RESULTS"
if [ "${{ inputs.ignore_build_failures }}" == "true" ]; then
echo "::error title=${{matrix.build.top_attr}}.${{matrix.build.system}}.${{matrix.build.attr}}::Build failed"
else
status=1
fi
fi
jq -c '{success: true, name: "${{matrix.build.name}}", description: "${{matrix.build.description}}", label: "${{matrix.build.label}}"} + .[0] | {"${{matrix.build.top_attr}}": {"${{matrix.build.system}}": {"${{matrix.build.attr}}": .}}}' "$RESULTS" > "$ARTIFACT_PREFIX.json"
exit "$status"
- name: Upload result
if: always()
uses: actions/upload-artifact@v4
with:
name: |
build-result-${{ env.ARTIFACT_PREFIX }}
path: |
${{ env.ARTIFACT_PREFIX }}.json
- name: Upload logs
if: always()
uses: actions/upload-artifact@v4
with:
name: |
build-log-${{ env.ARTIFACT_PREFIX }}
path: |
${{ env.ARTIFACT_PREFIX }}.log
summary:
name: "Summary"
needs: build
runs-on: ubuntu-latest
outputs:
success: ${{ steps.merge.outputs.success }}
results: ${{ steps.merge.outputs.results }}
steps:
- id: generate-artifact-prefix
run: |
if [ -z "${{ inputs.artifact_prefix }}" ]; then
ARTIFACT_PREFIX="$RANDOM$RANDOM"
else
ARTIFACT_PREFIX="${{ inputs.artifact_prefix }}"
fi
echo "ARTIFACT_PREFIX=$ARTIFACT_PREFIX" >> "$GITHUB_ENV"
- id: merge-results
uses: actions/upload-artifact/merge@v4
with:
name: ${{ env.ARTIFACT_PREFIX }}-build-results
pattern: build-result-*
delete-merged: true
- id: merge-logs
uses: actions/upload-artifact/merge@v4
with:
name: ${{ env.ARTIFACT_PREFIX }}-build-logs
pattern: build-log-*
delete-merged: true
- id: download
uses: actions/download-artifact@v4
with:
name: ${{ env.ARTIFACT_PREFIX }}-build-results
path: ~/results
- id: merge
run: |
jq -rcs 'reduce .[] as $x ({}; . * $x)|"results=\(.)"' \
"${{steps.download.outputs.download-path}}"/*.json \
>> "$GITHUB_OUTPUT"
if jq -s '..|.success?|select(if . == false then ""|halt_error(1) else false end)' "${{steps.download.outputs.download-path}}"/*.json; then
echo "success=true" >> "$GITHUB_OUTPUT"
else
echo "success=false" >> "$GITHUB_OUTPUT"
fi
- name: Generate nixbuild.net summary
if: ${{ always() && inputs.generate_build_summary }}
uses: nixbuild/nixbuild-action@master
with:
nixbuild_token: ${{secrets.nixbuild_token}}
generate_summary_for: 'workflow'