Raw
1 name: CI
2
3 on: [push, pull_request]
4
5 env:
6 DEVELOPER: 1
7
8 # For pull requests, only the latest workflow run is allowed to proceed.
9 # Older runs are canceled when a new revision is pushed.
10 #
11 # For pushes, if more than one workflow run is triggered for the very same
12 # commit hash (which happens when multiple branches point to the same commit),
13 # only the first one is allowed to run. This allows a successful completion of
14 # the first run to be reused in the second run via the `skip-if-redundant`
15 # logic in the `config` job.
16 #
17 # For more details about the `concurrency` attribute, see:
18 # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#concurrency
19 concurrency:
20 group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
21 cancel-in-progress: ${{ github.event_name == 'pull_request' }}
22
23 jobs:
24 ci-config:
25 name: config
26 if: vars.CI_BRANCHES == '' || contains(vars.CI_BRANCHES, github.ref_name)
27 runs-on: ubuntu-latest
28 outputs:
29 enabled: ${{ steps.check-ref.outputs.enabled }}${{ steps.skip-if-redundant.outputs.enabled }}
30 skip_concurrent: ${{ steps.check-ref.outputs.skip_concurrent }}
31 steps:
32 - name: try to clone ci-config branch
33 run: |
34 git -c protocol.version=2 clone \
35 --no-tags \
36 --single-branch \
37 -b ci-config \
38 --depth 1 \
39 --no-checkout \
40 --filter=blob:none \
41 https://github.com/${{ github.repository }} \
42 config-repo &&
43 cd config-repo &&
44 git checkout HEAD -- ci/config || : ignore
45 - id: check-ref
46 name: check whether CI is enabled for ref
47 run: |
48 enabled=yes
49 if test -x config-repo/ci/config/allow-ref
50 then
51 echo "::warning::ci/config/allow-ref is deprecated; use CI_BRANCHES instead"
52 if ! config-repo/ci/config/allow-ref '${{ github.ref }}'
53 then
54 enabled=no
55 fi
56 fi
57
58 skip_concurrent=yes
59 if test -x config-repo/ci/config/skip-concurrent &&
60 ! config-repo/ci/config/skip-concurrent '${{ github.ref }}'
61 then
62 skip_concurrent=no
63 fi
64 echo "enabled=$enabled" >>$GITHUB_OUTPUT
65 echo "skip_concurrent=$skip_concurrent" >>$GITHUB_OUTPUT
66 - name: skip if the commit or tree was already tested
67 id: skip-if-redundant
68 uses: actions/github-script@v9
69 if: steps.check-ref.outputs.enabled == 'yes'
70 with:
71 github-token: ${{secrets.GITHUB_TOKEN}}
72 script: |
73 try {
74 // Figure out workflow ID, commit and tree
75 const { data: run } = await github.rest.actions.getWorkflowRun({
76 owner: context.repo.owner,
77 repo: context.repo.repo,
78 run_id: context.runId,
79 });
80 const workflow_id = run.workflow_id;
81 const head_sha = run.head_sha;
82 const tree_id = run.head_commit.tree_id;
83
84 // See whether there is a successful run for that commit or tree
85 const { data: runs } = await github.rest.actions.listWorkflowRuns({
86 owner: context.repo.owner,
87 repo: context.repo.repo,
88 per_page: 500,
89 status: 'success',
90 workflow_id,
91 });
92 for (const run of runs.workflow_runs) {
93 if (head_sha === run.head_sha) {
94 core.warning(`Successful run for the commit ${head_sha}: ${run.html_url}`);
95 core.setOutput('enabled', ' but skip');
96 break;
97 }
98 if (run.head_commit && tree_id === run.head_commit.tree_id) {
99 core.warning(`Successful run for the tree ${tree_id}: ${run.html_url}`);
100 core.setOutput('enabled', ' but skip');
101 break;
102 }
103 }
104 } catch (e) {
105 core.warning(e);
106 }
107
108 windows-build:
109 name: win build
110 needs: ci-config
111 if: needs.ci-config.outputs.enabled == 'yes'
112 runs-on: windows-latest
113 concurrency:
114 group: windows-build-${{ github.ref }}
115 cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
116 steps:
117 - uses: actions/checkout@v6
118 - uses: git-for-windows/setup-git-for-windows-sdk@v2
119 - name: build
120 shell: bash
121 env:
122 HOME: ${{runner.workspace}}
123 NO_PERL: 1
124 run: . /etc/profile && ci/make-test-artifacts.sh artifacts
125 - name: zip up tracked files
126 run: git archive -o artifacts/tracked.tar.gz HEAD
127 - name: upload tracked files and build artifacts
128 uses: actions/upload-artifact@v7
129 with:
130 name: windows-artifacts
131 path: artifacts
132 windows-test:
133 name: win test
134 runs-on: windows-latest
135 needs: [ci-config, windows-build]
136 strategy:
137 fail-fast: false
138 matrix:
139 nr: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
140 concurrency:
141 group: windows-test-${{ matrix.nr }}-${{ github.ref }}
142 cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
143 steps:
144 - name: download tracked files and build artifacts
145 uses: actions/download-artifact@v8
146 with:
147 name: windows-artifacts
148 path: ${{github.workspace}}
149 - name: extract tracked files and build artifacts
150 shell: bash
151 run: tar xf artifacts.tar.gz && tar xf tracked.tar.gz
152 - uses: git-for-windows/setup-git-for-windows-sdk@v2
153 - name: test
154 shell: bash
155 run: . /etc/profile && ci/run-test-slice.sh $((${{matrix.nr}} + 1)) 10
156 - name: print test failures
157 if: failure() && env.FAILED_TEST_ARTIFACTS != ''
158 shell: bash
159 run: ci/print-test-failures.sh
160 - name: Upload failed tests' directories
161 if: failure() && env.FAILED_TEST_ARTIFACTS != ''
162 uses: actions/upload-artifact@v7
163 with:
164 name: failed-tests-windows-${{ matrix.nr }}
165 path: ${{env.FAILED_TEST_ARTIFACTS}}
166 vs-build:
167 name: win+VS build
168 needs: ci-config
169 if: github.event.repository.owner.login == 'git-for-windows' && needs.ci-config.outputs.enabled == 'yes'
170 env:
171 NO_PERL: 1
172 GIT_CONFIG_PARAMETERS: "'user.name=CI' 'user.email=ci@git'"
173 runs-on: windows-latest
174 concurrency:
175 group: vs-build-${{ github.ref }}
176 cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
177 steps:
178 - uses: actions/checkout@v6
179 - uses: git-for-windows/setup-git-for-windows-sdk@v2
180 - name: initialize vcpkg
181 uses: actions/checkout@v6
182 with:
183 repository: 'microsoft/vcpkg'
184 path: 'compat/vcbuild/vcpkg'
185 - name: download vcpkg artifacts
186 uses: git-for-windows/get-azure-pipelines-artifact@v0
187 with:
188 repository: git/git
189 definitionId: 9
190 - name: add msbuild to PATH
191 uses: microsoft/setup-msbuild@v3
192 - name: copy dlls to root
193 shell: cmd
194 run: compat\vcbuild\vcpkg_copy_dlls.bat release
195 - name: generate Visual Studio solution
196 shell: bash
197 run: |
198 cmake `pwd`/contrib/buildsystems/ -DCMAKE_PREFIX_PATH=`pwd`/compat/vcbuild/vcpkg/installed/x64-windows \
199 -DNO_GETTEXT=YesPlease -DPERL_TESTS=OFF -DPYTHON_TESTS=OFF -DCURL_NO_CURL_CMAKE=ON
200 - name: MSBuild
201 run: msbuild git.sln -property:Configuration=Release -property:Platform=x64 -maxCpuCount:4 -property:PlatformToolset=v142
202 - name: bundle artifact tar
203 shell: bash
204 env:
205 MSVC: 1
206 VCPKG_ROOT: ${{github.workspace}}\compat\vcbuild\vcpkg
207 run: |
208 mkdir -p artifacts &&
209 eval "$(make -n artifacts-tar INCLUDE_DLLS_IN_ARTIFACTS=YesPlease ARTIFACTS_DIRECTORY=artifacts NO_GETTEXT=YesPlease 2>&1 | grep ^tar)"
210 - name: zip up tracked files
211 run: git archive -o artifacts/tracked.tar.gz HEAD
212 - name: upload tracked files and build artifacts
213 uses: actions/upload-artifact@v7
214 with:
215 name: vs-artifacts
216 path: artifacts
217 vs-test:
218 name: win+VS test
219 runs-on: windows-latest
220 needs: [ci-config, vs-build]
221 strategy:
222 fail-fast: false
223 matrix:
224 nr: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
225 concurrency:
226 group: vs-test-${{ matrix.nr }}-${{ github.ref }}
227 cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
228 steps:
229 - uses: git-for-windows/setup-git-for-windows-sdk@v2
230 - name: download tracked files and build artifacts
231 uses: actions/download-artifact@v8
232 with:
233 name: vs-artifacts
234 path: ${{github.workspace}}
235 - name: extract tracked files and build artifacts
236 shell: bash
237 run: tar xf artifacts.tar.gz && tar xf tracked.tar.gz
238 - name: test
239 shell: bash
240 env:
241 NO_SVN_TESTS: 1
242 run: . /etc/profile && ci/run-test-slice.sh $((${{matrix.nr}} + 1)) 10
243 - name: print test failures
244 if: failure() && env.FAILED_TEST_ARTIFACTS != ''
245 shell: bash
246 run: ci/print-test-failures.sh
247 - name: Upload failed tests' directories
248 if: failure() && env.FAILED_TEST_ARTIFACTS != ''
249 uses: actions/upload-artifact@v7
250 with:
251 name: failed-tests-windows-vs-${{ matrix.nr }}
252 path: ${{env.FAILED_TEST_ARTIFACTS}}
253
254 windows-meson-build:
255 name: win+Meson build
256 needs: ci-config
257 if: needs.ci-config.outputs.enabled == 'yes'
258 runs-on: windows-latest
259 concurrency:
260 group: windows-meson-build-${{ github.ref }}
261 cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
262 steps:
263 - uses: actions/checkout@v6
264 - uses: actions/setup-python@v6
265 - name: Set up dependencies
266 shell: pwsh
267 run: pip install meson ninja
268 - name: Setup
269 shell: pwsh
270 run: meson setup build --vsenv -Dbuildtype=release -Dperl=disabled -Dcredential_helpers=wincred
271 - name: Compile
272 shell: pwsh
273 run: meson compile -C build
274 - name: Upload build artifacts
275 uses: actions/upload-artifact@v7
276 with:
277 name: windows-meson-artifacts
278 path: build
279 windows-meson-test:
280 name: win+Meson test
281 runs-on: windows-latest
282 needs: [ci-config, windows-meson-build]
283 strategy:
284 fail-fast: false
285 matrix:
286 nr: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
287 concurrency:
288 group: windows-meson-test-${{ matrix.nr }}-${{ github.ref }}
289 cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
290 steps:
291 - uses: actions/checkout@v6
292 - uses: actions/setup-python@v6
293 - name: Set up dependencies
294 shell: pwsh
295 run: pip install meson ninja
296 - name: Download build artifacts
297 uses: actions/download-artifact@v8
298 with:
299 name: windows-meson-artifacts
300 path: build
301 - name: Test
302 shell: bash
303 run: ci/run-test-slice-meson.sh build $((${{matrix.nr}} + 1)) 10
304 - name: print test failures
305 if: failure() && env.FAILED_TEST_ARTIFACTS != ''
306 shell: bash
307 run: ci/print-test-failures.sh
308 - name: Upload failed tests' directories
309 if: failure() && env.FAILED_TEST_ARTIFACTS != ''
310 uses: actions/upload-artifact@v7
311 with:
312 name: failed-tests-windows-meson-${{ matrix.nr }}
313 path: ${{env.FAILED_TEST_ARTIFACTS}}
314
315 regular:
316 name: ${{matrix.vector.jobname}} (${{matrix.vector.pool}})
317 needs: ci-config
318 if: needs.ci-config.outputs.enabled == 'yes'
319 concurrency:
320 group: ${{ matrix.vector.jobname }}-${{ matrix.vector.pool }}-${{ github.ref }}
321 cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
322 strategy:
323 fail-fast: false
324 matrix:
325 vector:
326 - jobname: osx-clang
327 cc: clang
328 pool: macos-14
329 - jobname: osx-reftable
330 cc: clang
331 pool: macos-14
332 - jobname: osx-gcc
333 cc: gcc-13
334 pool: macos-14
335 - jobname: osx-meson
336 cc: clang
337 pool: macos-14
338 env:
339 CC: ${{matrix.vector.cc}}
340 CC_PACKAGE: ${{matrix.vector.cc_package}}
341 jobname: ${{matrix.vector.jobname}}
342 CI_JOB_IMAGE: ${{matrix.vector.pool}}
343 TEST_OUTPUT_DIRECTORY: ${{github.workspace}}/t
344 runs-on: ${{matrix.vector.pool}}
345 steps:
346 - uses: actions/checkout@v6
347 - run: ci/install-dependencies.sh
348 - run: ci/run-build-and-tests.sh
349 - name: print test failures
350 if: failure() && env.FAILED_TEST_ARTIFACTS != ''
351 run: ci/print-test-failures.sh
352 - name: Upload failed tests' directories
353 if: failure() && env.FAILED_TEST_ARTIFACTS != ''
354 uses: actions/upload-artifact@v7
355 with:
356 name: failed-tests-${{matrix.vector.jobname}}
357 path: ${{env.FAILED_TEST_ARTIFACTS}}
358 fuzz-smoke-test:
359 name: fuzz smoke test
360 needs: ci-config
361 if: needs.ci-config.outputs.enabled == 'yes'
362 env:
363 CC: clang
364 CI_JOB_IMAGE: ubuntu-latest
365 runs-on: ubuntu-latest
366 steps:
367 - uses: actions/checkout@v6
368 - run: ci/install-dependencies.sh
369 - run: ci/run-build-and-minimal-fuzzers.sh
370 dockerized:
371 name: ${{matrix.vector.jobname}} (${{matrix.vector.image}})
372 needs: ci-config
373 if: needs.ci-config.outputs.enabled == 'yes'
374 concurrency:
375 group: dockerized-${{ matrix.vector.jobname }}-${{ matrix.vector.image }}-${{ github.ref }}
376 cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
377 strategy:
378 fail-fast: false
379 matrix:
380 vector:
381 - jobname: linux-sha256
382 image: ubuntu:rolling
383 cc: clang
384 - jobname: linux-reftable
385 image: ubuntu:rolling
386 cc: clang
387 - jobname: linux-TEST-vars
388 image: ubuntu:20.04
389 cc: gcc
390 cc_package: gcc-8
391 - jobname: linux-breaking-changes
392 cc: gcc
393 image: ubuntu:rolling
394 - jobname: fedora-breaking-changes-meson
395 image: fedora:latest
396 - jobname: linux-leaks
397 image: ubuntu:rolling
398 cc: gcc
399 - jobname: linux-reftable-leaks
400 image: ubuntu:rolling
401 cc: gcc
402 - jobname: linux-asan-ubsan
403 image: ubuntu:rolling
404 cc: clang
405 - jobname: linux-meson
406 image: ubuntu:rolling
407 cc: gcc
408 - jobname: linux-musl-meson
409 image: alpine:latest
410 # Supported until 2025-04-02.
411 - jobname: linux32
412 image: i386/ubuntu:20.04
413 # A RHEL 8 compatible distro. Supported until 2029-05-31.
414 - jobname: almalinux-8
415 image: almalinux:8
416 # Supported until 2026-08-31.
417 - jobname: debian-11
418 image: debian:11
419 env:
420 jobname: ${{matrix.vector.jobname}}
421 CC: ${{matrix.vector.cc}}
422 CI_JOB_IMAGE: ${{matrix.vector.image}}
423 CUSTOM_PATH: /custom
424 runs-on: ubuntu-latest
425 container:
426 image: ${{ matrix.vector.image }}
427 options: ${{ github.repository_visibility == 'private' && '--pids-limit 16384 --ulimit nproc=16384:16384 --ulimit nofile=32768:32768' || '' }}
428 steps:
429 - name: prepare libc6 for actions
430 if: matrix.vector.jobname == 'linux32'
431 run: apt -q update && apt -q -y install libc6-amd64 lib64stdc++6
432 - name: install git in container
433 run: |
434 if command -v git
435 then
436 : # nothing to do
437 elif command -v apk
438 then
439 apk add --update git
440 elif command -v dnf
441 then
442 dnf -yq update && dnf -yq install git
443 else
444 apt-get -q update && apt-get -q -y install git
445 fi
446 - uses: actions/checkout@v6
447 - run: ci/install-dependencies.sh
448 - run: useradd builder --create-home
449 - run: chown -R builder .
450 - run: chmod a+w $GITHUB_ENV && sudo --preserve-env --set-home --user=builder ci/run-build-and-tests.sh
451 - name: print test failures
452 if: failure() && env.FAILED_TEST_ARTIFACTS != ''
453 run: sudo --preserve-env --set-home --user=builder ci/print-test-failures.sh
454 - name: Upload failed tests' directories
455 if: failure() && env.FAILED_TEST_ARTIFACTS != ''
456 uses: actions/upload-artifact@v7
457 with:
458 name: failed-tests-${{matrix.vector.jobname}}
459 path: ${{env.FAILED_TEST_ARTIFACTS}}
460 static-analysis:
461 needs: ci-config
462 if: needs.ci-config.outputs.enabled == 'yes'
463 env:
464 jobname: StaticAnalysis
465 CI_JOB_IMAGE: ubuntu-latest
466 runs-on: ubuntu-latest
467 concurrency:
468 group: static-analysis-${{ github.ref }}
469 cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
470 steps:
471 - uses: actions/checkout@v6
472 - run: ci/install-dependencies.sh
473 - run: ci/run-static-analysis.sh
474 - run: ci/check-directional-formatting.bash
475 rust-analysis:
476 needs: ci-config
477 if: needs.ci-config.outputs.enabled == 'yes'
478 env:
479 jobname: RustAnalysis
480 CI_JOB_IMAGE: ubuntu:rolling
481 runs-on: ubuntu-latest
482 container: ubuntu:rolling
483 concurrency:
484 group: rust-analysis-${{ github.ref }}
485 cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
486 steps:
487 - uses: actions/checkout@v6
488 - run: ci/install-dependencies.sh
489 - run: ci/run-rust-checks.sh
490 sparse:
491 needs: ci-config
492 if: needs.ci-config.outputs.enabled == 'yes'
493 env:
494 jobname: sparse
495 CI_JOB_IMAGE: ubuntu-22.04
496 runs-on: ubuntu-22.04
497 concurrency:
498 group: sparse-${{ github.ref }}
499 cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
500 steps:
501 - uses: actions/checkout@v6
502 - name: Install other dependencies
503 run: ci/install-dependencies.sh
504 - run: make sparse
505 documentation:
506 name: documentation
507 needs: ci-config
508 if: needs.ci-config.outputs.enabled == 'yes'
509 concurrency:
510 group: documentation-${{ github.ref }}
511 cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
512 env:
513 jobname: Documentation
514 CI_JOB_IMAGE: ubuntu-latest
515 runs-on: ubuntu-latest
516 steps:
517 - uses: actions/checkout@v6
518 - run: ci/install-dependencies.sh
519 - run: ci/test-documentation.sh