1name: CI
2on:
3  # Run CI for PRs to `main` and to release branches.
4  #
5  # Note that PRs to `main` will run a subset of tests and PRs to the
6  # `release-*` branches will run full CI.
7  pull_request:
8    branches:
9    - main
10    - 'release-*'
11
12  # This is the CI that runs for PRs-to-merge.
13  merge_group:
14
15  push:
16    branches:
17    # Right now merge queues can't be used with wildcards in branch protections
18    # so full CI runs both on PRs to release branches as well as merges to
19    # release branches. Note that the merge to a release branch may produce a
20    # tag at the end of CI if successful and the tag will trigger the artifact
21    # uploads as well as publication to crates.io.
22    - 'release-*'
23
24  # Allow manually triggering this request via a button or another workflow.
25  workflow_dispatch:
26
27defaults:
28  run:
29    shell: bash
30
31# Cancel any in-flight jobs for the same PR/branch so there's only one active
32# at a time
33concurrency:
34  group: ${{ github.workflow }}-${{ github.ref }}
35  cancel-in-progress: true
36
37jobs:
38  # Check Code style quickly by running `rustfmt` over all code
39  rustfmt:
40    name: Rustfmt
41    runs-on: ubuntu-latest
42    steps:
43    - uses: actions/checkout@v4
44      with:
45        submodules: true
46    - uses: ./.github/actions/install-rust
47    - run: rustup component add rustfmt
48    - run: cargo fmt --all -- --check
49
50    # common logic to cancel the entire run if this job fails
51    - uses: ./.github/actions/cancel-on-failure
52      if: failure()
53
54  # Quick JS formatting/linting checks for the little bits of JS we have for the
55  # `wasmtime explore` UI.
56  check_js:
57    name: Check JS
58    runs-on: ubuntu-latest
59    steps:
60    - uses: actions/checkout@v4
61    - run: npm install
62      working-directory: ./crates/explorer
63    - run: npm run lint
64      working-directory: ./crates/explorer
65    - run: npm run fmt-check
66      working-directory: ./crates/explorer
67
68    # common logic to cancel the entire run if this job fails
69    - uses: ./.github/actions/cancel-on-failure
70      if: failure()
71
72  # Check Code style quickly by running `clang-format` over all the C/C++ code
73  #
74  # Note that `wasmtime-platform.h` is excluded here as it's auto-generated.
75  clangformat:
76    name: Clang format
77    runs-on: ubuntu-24.04
78    steps:
79    - uses: actions/checkout@v4
80      with:
81        submodules: true
82    - run: |
83        git ls-files '*.h' '*.c' '*.cpp' | \
84          grep -v wasmtime-platform.h | \
85          grep -v wasm.h | \
86          xargs clang-format-18 --dry-run --Werror --verbose
87
88    # common logic to cancel the entire run if this job fails
89    - uses: ./.github/actions/cancel-on-failure
90      if: failure()
91
92  # Lint dependency graph for security advisories, duplicate versions, and
93  # incompatible licences
94  cargo_deny:
95    name: Cargo deny
96    needs: determine
97    if: needs.determine.outputs.audit
98    runs-on: ubuntu-latest
99    steps:
100    - uses: actions/checkout@v4
101      with:
102        submodules: true
103    - uses: ./.github/actions/install-rust
104    - run: |
105        set -e
106        curl -L https://github.com/EmbarkStudios/cargo-deny/releases/download/0.14.5/cargo-deny-0.14.5-x86_64-unknown-linux-musl.tar.gz | tar xzf -
107        mv cargo-deny-*-x86_64-unknown-linux-musl/cargo-deny cargo-deny
108        echo `pwd` >> $GITHUB_PATH
109    - run: cargo deny check bans licenses
110
111    # common logic to cancel the entire run if this job fails
112    - uses: ./.github/actions/cancel-on-failure
113      if: failure()
114
115  # Ensure dependencies are vetted. See https://mozilla.github.io/cargo-vet/
116  #
117  # Note that this step, on PRs only, is allowed to fail. This is then followed
118  # up with the `cargo_vet_failure_for_prs` step below. The intention is to
119  # avoid causing this check to fail PRs while still enabling it to fail the
120  # merge queue checks. That way PRs can enter the merge queue when this step is
121  # failing if `main` has picked up `cargo vet` entries in the meantime for the
122  # failures.
123  cargo_vet:
124    name: Cargo vet
125    needs: determine
126    if: needs.determine.outputs.audit
127    runs-on: ubuntu-latest
128    outputs:
129      outcome: ${{ steps.vet.outcome }}
130    steps:
131    - uses: actions/checkout@v4
132      with:
133        submodules: true
134    - uses: ./.github/actions/install-rust
135    - uses: ./.github/actions/install-cargo-vet
136    - id: vet
137      run: cargo vet --locked
138      continue-on-error: ${{ github.event_name == 'pull_request' }}
139
140    # Double-check that if versions are bumped that `cargo vet` still works.
141    # This is intended to weed out mistakes such as #9115 from happening again.
142    - run: rustc scripts/publish.rs && ./publish bump-patch && cargo vet
143      name: Ensure `cargo vet` works if versions are bumped
144
145    # common logic to cancel the entire run if this job fails
146    - uses: ./.github/actions/cancel-on-failure
147      if: failure()
148
149  cargo_vet_failure_for_prs:
150    name: Cargo vet failed on a Pull Request
151    needs:
152    - determine
153    - cargo_vet
154    if: |
155      needs.determine.outputs.audit
156      && github.event_name == 'pull_request'
157      && needs.cargo_vet.outputs.outcome == 'failure'
158    runs-on: ubuntu-latest
159    steps:
160    # NB: this message ideally would link back to the previous step, but I'm not
161    # sure how to easily do that.
162    - run: |
163        echo 'failed to run "cargo vet", see previous `Cargo vet` step'
164        echo 'exiting with a nonzero status now to alert PR authors'
165        echo 'note, though, that this PR can still enter the merge queue'
166        echo ''
167        echo 'See https://docs.wasmtime.dev/contributing-coding-guidelines.html#cargo-vet-for-contributors'
168        echo 'for more information about the vetting process for Wasmtime'
169        exit 1
170
171  # This job is a dependency of many of the jobs below. This calculates what's
172  # actually being run for this workflow. For example:
173  #
174  # * Pushes to branches, which is currently both pushes to merge queue branches
175  #   as well as release branches, perform full CI.
176  # * PRs to release branches (not `main`) run full CI.
177  # * PRs to `main` will only run a few smoke tests above plus some elements of
178  #   the test matrix. The test matrix here is determined dynamically by the
179  #   `./ci/build-test-matrix.js` script given the commits that happened and
180  #   the files modified.
181  determine:
182    name: Determine CI jobs to run
183    runs-on: ubuntu-latest
184    outputs:
185      run-full: ${{ steps.calculate.outputs.run-full }}
186      test-matrix: ${{ steps.calculate.outputs.test-matrix }}
187      build-matrix: ${{ steps.calculate.outputs.build-matrix }}
188      test-capi: ${{ steps.calculate.outputs.test-capi }}
189      test-nightly: ${{ steps.calculate.outputs.test-nightly }}
190      test-miri: ${{ steps.calculate.outputs.test-miri }}
191      audit: ${{ steps.calculate.outputs.audit }}
192      preview1-adapter: ${{ steps.calculate.outputs.preview1-adapter }}
193      run-dwarf: ${{ steps.calculate.outputs.run-dwarf }}
194      platform-checks: ${{ steps.calculate.outputs.platform-checks }}
195    steps:
196    - uses: actions/checkout@v4
197    - id: calculate
198      env:
199        GH_TOKEN: ${{ github.token }}
200      run: |
201        touch commits.log names.log
202        # Note that CI doesn't run on pushes to `main`, only pushes to merge
203        # queue branches and release branches, so this only runs full CI in
204        # those locations.
205        if [ "${{ github.event_name }}" != "pull_request" ]; then
206          run_full=true
207        else
208          pr=${{ github.event.number }}
209          gh pr view $pr --json commits | tee commits.log
210          gh pr diff $pr --name-only | tee names.log || echo "failed to get files"
211          if [ "${{ github.base_ref }}" != "main" ]; then
212            run_full=true
213          elif grep -q 'prtest:full' commits.log; then
214            run_full=true
215          elif grep -q 'prtest:debug' commits.log; then
216            echo run-dwarf=true >> $GITHUB_OUTPUT
217          elif grep -q 'prtest:platform-checks' commits.log; then
218            echo platform-checks=true >> $GITHUB_OUTPUT
219          elif grep -q 'prtest:miri' commits.log; then
220            echo test-miri=true >> $GITHUB_OUTPUT
221          fi
222          if grep -q crates.c-api names.log; then
223            echo test-capi=true >> $GITHUB_OUTPUT
224          fi
225          if grep -q fuzz names.log; then
226            echo test-nightly=true >> $GITHUB_OUTPUT
227          fi
228          if grep -q sys.custom names.log; then
229            echo test-nightly=true >> $GITHUB_OUTPUT
230          fi
231          if grep -q Cargo.lock names.log; then
232            echo audit=true >> $GITHUB_OUTPUT
233          fi
234          if grep -q supply-chain names.log; then
235            echo audit=true >> $GITHUB_OUTPUT
236          fi
237          if grep -q component-adapter names.log; then
238            echo preview1-adapter=true >> $GITHUB_OUTPUT
239          fi
240          if grep -q debug names.log; then
241            echo run-dwarf=true >> $GITHUB_OUTPUT
242          fi
243          if grep -q pulley names.log; then
244            echo test-nightly=true >> $GITHUB_OUTPUT
245          fi
246        fi
247        matrix="$(node ./ci/build-test-matrix.js ./commits.log ./names.log $run_full)"
248        echo "test-matrix={\"include\":$(echo $matrix)}" >> $GITHUB_OUTPUT
249        echo "$matrix"
250
251        matrix="$(node ./ci/build-build-matrix.js)"
252        echo "build-matrix={\"include\":$(echo $matrix)}" >> $GITHUB_OUTPUT
253
254        if [ "$run_full" = "true" ]; then
255            echo run-full=true >> $GITHUB_OUTPUT
256            echo test-capi=true >> $GITHUB_OUTPUT
257            echo test-nightly=true >> $GITHUB_OUTPUT
258            echo test-miri=true >> $GITHUB_OUTPUT
259            echo audit=true >> $GITHUB_OUTPUT
260            echo preview1-adapter=true >> $GITHUB_OUTPUT
261            echo run-dwarf=true >> $GITHUB_OUTPUT
262            echo platform-checks=true >> $GITHUB_OUTPUT
263        fi
264
265  # Build all documentation of Wasmtime, including the C API documentation,
266  # mdbook documentation, etc. This produces a `gh-pages` artifact which is what
267  # gets uploaded to the `gh-pages` branch later on.
268  doc:
269    needs: determine
270    if: needs.determine.outputs.run-full
271    name: Doc build
272    runs-on: ubuntu-latest
273    env:
274      CARGO_MDBOOK_VERSION: 0.4.37
275      RUSTDOCFLAGS: -Dbroken_intra_doc_links --cfg docsrs
276      OPENVINO_SKIP_LINKING: 1
277    steps:
278    - uses: actions/checkout@v4
279      with:
280        submodules: true
281    - uses: ./.github/actions/install-rust
282      with:
283        toolchain: wasmtime-ci-pinned-nightly
284
285    # Build C API documentation
286    - run: curl -L https://sourceforge.net/projects/doxygen/files/rel-1.9.3/doxygen-1.9.3.linux.bin.tar.gz/download | tar xzf -
287    - run: echo "`pwd`/doxygen-1.9.3/bin" >> $GITHUB_PATH
288    - run: cmake -S crates/c-api -B target/c-api
289    - run: cmake --build target/c-api --target doc
290
291    # install mdbook, build the docs, and test the docs
292    - uses: actions/cache@v4
293      with:
294        path: ${{ runner.tool_cache }}/mdbook
295        key: cargo-mdbook-bin-${{ env.CARGO_MDBOOK_VERSION }}
296    - run: |
297        echo "${{ runner.tool_cache }}/mdbook/bin" >> $GITHUB_PATH
298        cargo install --root ${{ runner.tool_cache }}/mdbook --version ${{ env.CARGO_MDBOOK_VERSION }} mdbook --locked
299    - run: (cd docs && mdbook build)
300    - run: cargo build -p wasi-common --features wasmtime/wat,wasmtime/cranelift
301    - run: (cd docs && mdbook test -L ../target/debug/deps)
302
303    # Build Rust API documentation.
304    #
305    # Enable extra features in crates as well to ensure they're documented
306    - run: |
307        cargo doc --no-deps --workspace \
308          --exclude wasmtime-cli \
309          --exclude test-programs \
310          --exclude cranelift-codegen-meta \
311          --features call-hook
312      env:
313        RUSTDOCFLAGS: --cfg=docsrs
314    - run: cargo doc --package cranelift-codegen-meta --document-private-items
315      env:
316        RUSTDOCFLAGS: --cfg=docsrs
317
318    # Assemble the documentation, and always upload it as an artifact for
319    # inspection on PRs and such.
320    - run: |
321        mv docs/book gh-pages
322        mv crates/c-api/html gh-pages/c-api
323        mv target/doc gh-pages/api
324        tar czf gh-pages.tar.gz gh-pages
325    - uses: actions/upload-artifact@v4
326      with:
327        name: gh-pages
328        path: gh-pages.tar.gz
329
330    # common logic to cancel the entire run if this job fails
331    - uses: ./.github/actions/cancel-on-failure
332      if: failure()
333
334  # Checks of various feature combinations and whether things compile. The goal
335  # here isn't to run tests, mostly just serve as a double-check that Rust code
336  # compiles and is likely to work everywhere else.
337  micro_checks:
338    name: Check ${{matrix.name}}
339    strategy:
340      fail-fast: true
341      matrix:
342        include:
343          - name: wasmtime
344            checks: |
345              -p wasmtime --no-default-features
346              -p wasmtime --no-default-features --features wat
347              -p wasmtime --no-default-features --features profiling
348              -p wasmtime --no-default-features --features cache
349              -p wasmtime --no-default-features --features async
350              -p wasmtime --no-default-features --features std
351              -p wasmtime --no-default-features --features pooling-allocator
352              -p wasmtime --no-default-features --features cranelift
353              -p wasmtime --no-default-features --features component-model
354              -p wasmtime --no-default-features --features runtime,component-model
355              -p wasmtime --no-default-features --features cranelift,wat,async,std,cache
356              -p wasmtime --no-default-features --features winch
357              -p wasmtime --no-default-features --features wmemcheck
358              -p wasmtime --no-default-features --features wmemcheck,cranelift,runtime
359              -p wasmtime --no-default-features --features demangle
360              -p wasmtime --no-default-features --features addr2line
361              -p wasmtime --no-default-features --features gc
362              -p wasmtime --no-default-features --features runtime,gc
363              -p wasmtime --no-default-features --features cranelift,gc
364              -p wasmtime --no-default-features --features gc-drc
365              -p wasmtime --no-default-features --features runtime,gc-drc
366              -p wasmtime --no-default-features --features cranelift,gc-drc
367              -p wasmtime --no-default-features --features gc-null
368              -p wasmtime --no-default-features --features runtime,gc-null
369              -p wasmtime --no-default-features --features cranelift,gc-null
370              -p wasmtime --no-default-features --features runtime
371              -p wasmtime --no-default-features --features threads
372              -p wasmtime --no-default-features --features runtime,threads
373              -p wasmtime --no-default-features --features cranelift,threads
374              -p wasmtime --features incremental-cache
375              -p wasmtime --features profile-pulley
376              -p wasmtime --all-features
377
378          - name: wasmtime-fiber
379            checks: |
380              -p wasmtime-fiber --no-default-features
381              -p wasmtime-fiber --no-default-features --features std
382              -p wasmtime-fiber --all-features
383
384          - name: wasmtime-cli
385            checks: |
386              -p wasmtime-cli --no-default-features
387              -p wasmtime-cli --no-default-features --features pooling-allocator
388              -p wasmtime-cli --no-default-features --features run
389              -p wasmtime-cli --no-default-features --features run,component-model
390              -p wasmtime-cli --no-default-features --features run,pooling-allocator
391              -p wasmtime-cli --no-default-features --features compile
392              -p wasmtime-cli --no-default-features --features compile,cranelift
393              -p wasmtime-cli --no-default-features --features compile,cranelift,component-model
394              -p wasmtime-cli --no-default-features --features objdump
395              -p wasmtime-cli --all-features
396              -p wasmtime-cli --features component-model
397
398          - name: cranelift-codegen
399            checks: |
400              -p cranelift-codegen --benches
401              -p cranelift-codegen --no-default-features --features std,unwind,pulley
402
403          - name: cranelift-entity
404            checks: |
405              -p cranelift-entity --no-default-features
406              -p cranelift-entity --no-default-features --features enable-serde
407
408          - name: wasmtime-bench-api
409            checks: |
410              -p wasmtime-bench-api
411
412          - name: wasmtime-c-api
413            checks: |
414              -p wasmtime-c-api --no-default-features
415              -p wasmtime-c-api --no-default-features --features wat
416              -p wasmtime-c-api --no-default-features --features wasi
417    runs-on: ubuntu-latest
418    steps:
419    - uses: actions/checkout@v4
420      with:
421        submodules: true
422    - uses: ./.github/actions/install-rust
423
424    # Run the check.
425    - run: |
426        checks=$(cat <<END
427        ${{ matrix.checks }}
428        END
429        )
430        echo "$checks" | xargs -I CHECK sh -c 'echo "=== cargo check CHECK ==="; cargo check CHECK'
431
432    # common logic to cancel the entire run if this job fails
433    - uses: ./.github/actions/cancel-on-failure
434      if: failure()
435
436  fiber_tests:
437    name: wasmtime-fiber tests
438    runs-on: ubuntu-latest
439    env:
440      CARGO_NDK_VERSION: 2.12.2
441    steps:
442    - uses: actions/checkout@v4
443      with:
444        submodules: true
445    - uses: ./.github/actions/install-rust
446    - run: cargo test -p wasmtime-fiber --no-default-features
447
448    # common logic to cancel the entire run if this job fails
449    - uses: ./.github/actions/cancel-on-failure
450      if: failure()
451
452  # Check that Clippy lints are passing.
453  clippy:
454    name: Clippy
455    runs-on: ubuntu-latest
456    env:
457      CARGO_NDK_VERSION: 2.12.2
458    steps:
459    - uses: actions/checkout@v4
460      with:
461        submodules: true
462    - uses: ./.github/actions/install-rust
463
464    - run: rustup component add clippy
465    - run: cargo clippy --workspace --all-targets
466
467    # common logic to cancel the entire run if this job fails
468    - uses: ./.github/actions/cancel-on-failure
469      if: failure()
470
471  # Similar to `micro_checks` but where we need to install some more state
472  # (e.g. Android NDK) and we haven't factored support for those things out into
473  # a parallel jobs yet.
474  monolith_checks:
475    name: Monolith Checks
476    runs-on: ubuntu-latest
477    env:
478      CARGO_NDK_VERSION: 2.12.2
479    steps:
480    - uses: actions/checkout@v4
481      with:
482        submodules: true
483    - uses: ./.github/actions/install-rust
484
485    # Check that wasmtime compiles with panic=abort since there's some `#[cfg]`
486    # for specifically panic=abort there.
487    - run: cargo check -p wasmtime
488      env:
489        RUSTFLAGS: -Cpanic=abort
490
491    # Check a few builds of the cranelift backend
492    # - only x86 backend support,
493    # - only arm64 backend support,
494    # - no debug_assertions.
495    - run: cargo check --manifest-path=./cranelift/Cargo.toml --bin clif-util --no-default-features --features=cranelift-codegen/arm64
496    - run: cargo check --manifest-path=./cranelift/Cargo.toml --bin clif-util --no-default-features --features=cranelift-codegen/x86
497    - run: cargo check --manifest-path=./cranelift/Cargo.toml --bin clif-util
498      env:
499        CARGO_PROFILE_DEV_DEBUG_ASSERTIONS: false
500
501    # Re-vendor all WIT files and ensure that they're all up-to-date by ensuring
502    # that there's no git changes.
503    - name: Re-vendor WIT
504      run: ./ci/vendor-wit.sh
505    - run: git diff --exit-code
506
507    # Re-vendor the C API and make sure it's up-to-date.
508    - name: Re-vendor C API
509      run: ./ci/vendor-c-api-headers.sh
510    - run: git diff --exit-code
511
512    # common logic to cancel the entire run if this job fails
513    - uses: ./.github/actions/cancel-on-failure
514      if: failure()
515
516  # Various checks that Wasmtime builds for a variety of platforms. Each
517  # platform may not include the entire dependency tree and maybe just a few
518  # features here and there, see the `include` matrix for more details.
519  platform_checks:
520    needs: determine
521    if: needs.determine.outputs.platform-checks
522    name: "Platform: ${{ matrix.target }}"
523    runs-on: ${{ matrix.os }}
524    strategy:
525      fail-fast: true
526      matrix:
527        include:
528        - target: x86_64-unknown-freebsd
529          os: ubuntu-latest
530          test: cargo check
531        - target: aarch64-pc-windows-msvc
532          os: windows-latest
533          test: cargo check
534        # While we're here testing a windows target also test a feature'd build
535        # on Windows. Note that this isn't covered by `micro_checks` above since
536        # that's for unix platforms, not Windows, so include a small check here
537        # which isn't the full `micro_checks` matrix but hopefully enough bang
538        # for our buck.
539        - target: i686-pc-windows-msvc
540          os: windows-latest
541          test: cargo check && cargo build -p wasmtime --no-default-features --features runtime
542        # This is used for general compatibility with `#![no_std]` targets and a
543        # variety of crates are tested here.
544        - target: x86_64-unknown-none
545          os: ubuntu-latest
546          test: >
547            cargo check -p wasmtime --no-default-features --features runtime,component-model &&
548            cargo check -p wasmtime --no-default-features --features runtime,gc,component-model,async &&
549            cargo check -p cranelift-control --no-default-features &&
550            cargo check -p pulley-interpreter --features encode,decode,disas,interp &&
551            cargo check -p wasmtime-wasi-io --no-default-features
552        # Use `cross` for illumos to have a C compiler/linker available.
553        - target: x86_64-unknown-illumos
554          os: ubuntu-latest
555          cross: true
556          test: cross build
557        - target: wasm32-wasip1
558          os: ubuntu-latest
559          test: cargo build --no-default-features --features compile,cranelift,all-arch
560        - target: aarch64-apple-ios
561          os: macos-latest
562          test: cargo build
563          env:
564            IPHONEOS_DEPLOYMENT_TARGET: 13.0
565        # Test that when Cranelift has no support for an architecture, even a
566        # 64-bit one, that Wasmtime still compiles. Note that this is also
567        # intended to test various fallbacks in the codebase where we have no
568        # support at all for a particular architecture. In theory if someone
569        # adds powerpc64 support to Wasmtime this should get switched to some
570        # other architecture.
571        - target: powerpc64le-unknown-linux-gnu
572          os: ubuntu-latest
573          test: cargo build
574          apt_packages: gcc-powerpc64le-linux-gnu
575          env:
576            CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER: powerpc64le-linux-gnu-gcc
577        # A no_std target without 64-bit atomics
578        - target: riscv32imac-unknown-none-elf
579          os: ubuntu-latest
580          test: cargo check -p wasmtime --no-default-features --features runtime,gc,component-model,async
581    env: ${{ matrix.env || fromJSON('{}') }}
582    steps:
583    - uses: actions/checkout@v4
584      with:
585        submodules: true
586    - uses: ./.github/actions/install-rust
587    - run: rustup target add ${{ matrix.target }}
588    - name: Install cross
589      run: |
590        curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash
591        cargo binstall --no-confirm cross
592      if: ${{ matrix.cross }}
593    - name: Install apt packages
594      if: ${{ matrix.apt_packages }}
595      run: sudo apt-get update && sudo apt-get install -y ${{ matrix.apt_packages }}
596    - run: ${{ matrix.test }}
597      env:
598        CARGO_BUILD_TARGET: ${{ matrix.target }}
599
600    # common logic to cancel the entire run if this job fails
601    - uses: ./.github/actions/cancel-on-failure
602      if: failure()
603
604  # Run tests that require a nightly compiler, such as building fuzz targets.
605  test_nightly:
606    needs: determine
607    if: needs.determine.outputs.test-nightly
608    name: Nightly tests
609    runs-on: ubuntu-latest
610    steps:
611    - uses: actions/checkout@v4
612      with:
613        submodules: true
614    # Note that nightly is pinned here to insulate us from breakage that might
615    # happen upstream. This is periodically updated through a PR.
616    - uses: ./.github/actions/install-rust
617      with:
618        toolchain: wasmtime-ci-pinned-nightly
619
620    # Check that `pulley-interpreter` compiles with tail calls enabled.  Don't
621    # actually run the tests with tail calls enabled, because they are not yet
622    # implemented in rustc and cause an ICE.
623    - run: cargo check -p pulley-interpreter --all-features
624      env:
625        RUSTFLAGS: "--cfg pulley_tail_calls"
626    - run: cargo test -p pulley-interpreter --all-features --release
627      env:
628        RUSTFLAGS: "--cfg pulley_assume_llvm_makes_tail_calls"
629
630    # Ensure that fuzzers still build.
631    #
632    # Install the OCaml packages necessary for fuzz targets that use the
633    # `wasm-spec-interpreter`.
634    - run: cargo install cargo-fuzz --vers "^0.11" --locked
635    - run: sudo apt-get update && sudo apt install -y ocaml-nox ocamlbuild ocaml-findlib libzarith-ocaml-dev
636    - run: cargo fetch
637      working-directory: ./fuzz
638    - run: cargo fuzz build --dev
639    - run: cargo fuzz build --dev --fuzz-dir ./cranelift/isle/fuzz
640    - run: cargo fuzz build --dev --fuzz-dir ./crates/environ/fuzz --features component-model
641    - run: cargo fuzz build --dev --fuzz-dir ./cranelift/assembler-x64/fuzz
642
643    # common logic to cancel the entire run if this job fails
644    - uses: ./.github/actions/cancel-on-failure
645      if: failure()
646
647  # Perform all tests of the c-api
648  test_capi:
649    needs: determine
650    name: Test C-API ${{ matrix.os }}
651    runs-on: ${{ matrix.os }}
652    if: needs.determine.outputs.test-capi
653
654    strategy:
655      fail-fast: true
656      matrix:
657        os: [ubuntu-24.04, macos-14, windows-2025]
658
659    steps:
660    - uses: actions/checkout@v4
661      with:
662        submodules: true
663    - uses: ./.github/actions/install-rust
664
665    # Build and test the C API with example C programs along with the example
666    # Rust programs. Note that this only executes if the `determine` step told
667    # us to test the capi which is off-by-default for PRs.
668    - run: rustup target add wasm32-wasip2 # wasip2 target needed by example programs
669    - run: cmake -Sexamples -Bexamples/build -DBUILD_SHARED_LIBS=OFF
670    - run: cmake --build examples/build --config Debug
671    - run: cmake -E env CTEST_OUTPUT_ON_FAILURE=1 cmake --build examples/build --config Debug --target RUN_TESTS
672      if: runner.os == 'Windows'
673    - run: cmake -E env CTEST_OUTPUT_ON_FAILURE=1 cmake --build examples/build --config Debug --target test
674      if: runner.os != 'Windows'
675
676    # common logic to cancel the entire run if this job fails
677    - uses: ./.github/actions/cancel-on-failure
678      if: failure()
679
680  # Perform all tests (debug mode) for `wasmtime`.
681  #
682  # Note that the full matrix for what may run here is defined within
683  # `./ci/build-test-matrix.js` and the execution of the `determine` step will
684  # calculate whether the tests are actually run as part of PRs and such.
685  test:
686    needs: determine
687    name: ${{ matrix.name }}
688    runs-on: ${{ matrix.os }}
689    env:
690      QEMU_BUILD_VERSION: 9.1.2
691    strategy:
692      fail-fast: ${{ github.event_name != 'pull_request' }}
693      matrix: ${{ fromJson(needs.determine.outputs.test-matrix) }}
694    steps:
695    - uses: actions/checkout@v4
696      with:
697        submodules: true
698    - uses: ./.github/actions/install-rust
699      with:
700        toolchain: ${{ matrix.rust }}
701
702    # Install targets in order to build various tests throughout the repo
703    - run: rustup target add wasm32-wasip1 wasm32-unknown-unknown ${{ matrix.target }}
704    - run: echo CARGO_BUILD_TARGET=${{ matrix.target }} >> $GITHUB_ENV
705      if: matrix.target != ''
706
707    # Fix an ICE for now in gcc when compiling zstd with debuginfo (??)
708    - run: echo CFLAGS=-g0 >> $GITHUB_ENV
709      if: matrix.target == 'x86_64-pc-windows-gnu'
710
711    # Update binutils if MinGW due to https://github.com/rust-lang/rust/issues/112368
712    - run: C:/msys64/usr/bin/pacman.exe -S --needed mingw-w64-x86_64-gcc --noconfirm
713      if: matrix.target == 'x86_64-pc-windows-gnu'
714    - shell: pwsh
715      run: echo "C:\msys64\mingw64\bin" >> $Env:GITHUB_PATH
716      if: matrix.target == 'x86_64-pc-windows-gnu'
717
718    - run: cargo fetch --locked
719
720    - name: Install cross-compilation tools
721      run: |
722        set -ex
723
724        sudo apt-get update
725        sudo apt-get install -y ${{ matrix.gcc_package }}
726
727        # Configure Cargo for cross compilation and tell it how it can run
728        # cross executables
729        upcase=$(echo ${{ matrix.target }} | awk '{ print toupper($0) }' | sed 's/-/_/g')
730        echo CARGO_TARGET_${upcase}_LINKER=${{ matrix.gcc }} >> $GITHUB_ENV
731      if: matrix.gcc != ''
732
733    - uses: actions/cache@v4
734      with:
735        path: ${{ runner.tool_cache }}/qemu
736        key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}-patchcpuinfo
737      if: matrix.qemu != ''
738    - name: Install qemu
739      run: |
740        set -ex
741
742        upcase=$(echo ${{ matrix.target }} | awk '{ print toupper($0) }' | sed 's/-/_/g')
743        echo CARGO_TARGET_${upcase}_RUNNER=${{ runner.tool_cache }}/qemu/bin/${{ matrix.qemu }} >> $GITHUB_ENV
744
745        # QEMU emulation is not always the speediest, so total testing time
746        # goes down if we build the libs in release mode when running tests.
747        echo CARGO_PROFILE_DEV_OPT_LEVEL=2 >> $GITHUB_ENV
748
749        # See comments in the source for why we enable this during QEMU
750        # emulation.
751        echo WASMTIME_TEST_NO_HOG_MEMORY=1 >> $GITHUB_ENV
752
753        # See if qemu is already in the cache
754        if [ -f ${{ runner.tool_cache }}/qemu/built ]; then
755          exit 0
756        fi
757
758        # Install build dependencies of QEMU itself.
759        sudo apt-get install -y libglib2.0-dev ninja-build
760
761        # Download and build qemu from source since the most recent release is
762        # way faster at arm emulation than the current version github actions'
763        # ubuntu image uses. Disable as much as we can to get it to build
764        # quickly.
765        curl https://download.qemu.org/qemu-$QEMU_BUILD_VERSION.tar.xz | tar xJf -
766        cd qemu-$QEMU_BUILD_VERSION
767        ./configure --target-list=${{ matrix.qemu_target }} --prefix=${{ runner.tool_cache}}/qemu --disable-tools --disable-slirp --disable-fdt --disable-capstone --disable-docs
768        ninja -C build install
769        touch ${{ runner.tool_cache }}/qemu/built
770      if: matrix.qemu != ''
771
772    # Record some CPU details; this is helpful information if tests fail due
773    # to CPU-specific features.
774    - name: CPU information
775      run: lscpu
776      if: runner.os == 'Linux'
777    - name: CPU information
778      run: sysctl hw
779      if: runner.os == 'macOS'
780    - name: CPU information
781      run: Get-WmiObject Win32_Processor
782      shell: pwsh
783      if: runner.os == 'Windows'
784
785    # Since MPK (PKU) is not present on some GitHub runners, we check if it is
786    # available before force-enabling it. This occasional testing is better than
787    # none at all; ideally we would test in a system-mode QEMU VM.
788    - name: Force-run with MPK enabled, if available
789      if: ${{ contains(matrix.name, 'MPK') }}
790      run: |
791        if cargo run --example mpk-available; then
792          echo "::notice::This CI run will force-enable MPK; this ensures tests conditioned with the \`WASMTIME_TEST_FORCE_MPK\` environment variable will run with MPK-protected memory pool stripes."
793          echo WASMTIME_TEST_FORCE_MPK=1 >> $GITHUB_ENV
794        else
795          echo "::warning::This CI run will not test MPK; it has been detected as not available on this machine (\`cargo run --example mpk-available\`)."
796        fi
797
798    # Install VTune, see `cli_tests::profile_with_vtune`.
799    - name: Install VTune
800      if: matrix.filter == 'linux-x64' && contains(matrix.bucket, 'wasmtime-cli')
801      uses: abrown/install-vtune-action@v1
802
803    # Build and test all features
804    - run: ./ci/run-tests.sh --locked ${{ matrix.bucket }}
805
806    # common logic to cancel the entire run if this job fails
807    - uses: ./.github/actions/cancel-on-failure
808      if: failure()
809
810  # Test `wasmtime-wasi-nn` in its own job, as not all of its backends are
811  # compatible with all targets, and each must be tested separately anyways.
812  test_wasi_nn:
813    strategy:
814      matrix:
815        feature: ["openvino"]
816        os: ["ubuntu-24.04", "windows-2025"]
817        include:
818          - os: windows-2025
819            feature: winml
820    name: Test wasi-nn (${{ matrix.feature }}, ${{ matrix.os }})
821    runs-on: ${{ matrix.os }}
822    needs: determine
823    if: needs.determine.outputs.run-full
824    steps:
825    - uses: actions/checkout@v4
826      with:
827        submodules: true
828    - uses: ./.github/actions/install-rust
829
830    # Install OpenVINO
831    - uses: abrown/install-openvino-action@v9
832      if: runner.arch == 'X64'
833
834    # Install WinML for testing wasi-nn WinML backend. WinML is only available
835    # on Windows clients and Windows Server with desktop experience enabled.
836    # GitHub Actions Window Server image doesn't have desktop experience
837    # enabled, so we download the standalone library from ONNX Runtime project.
838    - uses: nuget/setup-nuget@v2
839      if: (runner.os == 'Windows') && (matrix.feature == 'winml')
840    - run: nuget install Microsoft.AI.MachineLearning
841      if: (runner.os == 'Windows') && (matrix.feature == 'winml')
842
843    # Install Rust targets.
844    - run: rustup target add wasm32-wasip1
845
846    # Run the tests!
847    - run: cargo test -p wasmtime-wasi-nn --features ${{ matrix.feature }}
848
849    # common logic to cancel the entire run if this job fails
850    - uses: ./.github/actions/cancel-on-failure
851      if: failure()
852
853  # Test the `wasmtime-fuzzing` crate. Split out from the main tests because
854  # `--all-features` brings in OCaml, which is a pain to get setup for all
855  # targets.
856  test_fuzzing:
857    needs: determine
858    if: needs.determine.outputs.run-full
859    name: Test wasmtime-fuzzing
860    runs-on: 'ubuntu-latest'
861    steps:
862    - uses: actions/checkout@v4
863      with:
864        submodules: true
865    - uses: ./.github/actions/install-rust
866
867    # Run the tests
868    - run: |
869        cargo test -p wasmtime-fuzzing -p wasm-spec-interpreter
870
871    # common logic to cancel the entire run if this job fails
872    - uses: ./.github/actions/cancel-on-failure
873      if: failure()
874
875  # Test debug (DWARF) related functionality.
876  test_debug_dwarf:
877    needs: determine
878    if: needs.determine.outputs.run-dwarf
879    name: Test DWARF debugging
880    runs-on: ubuntu-22.04 # FIXME: fails on `ubuntu-24.04` right now
881    steps:
882    - uses: actions/checkout@v4
883      with:
884        submodules: true
885    - uses: ./.github/actions/install-rust
886    - run: |
887        rustup target add wasm32-wasip1 wasm32-unknown-unknown
888        cd /tmp
889        curl -OL https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-24/wasi-sdk-24.0-x86_64-linux.tar.gz
890        tar -xzf wasi-sdk-24.0-x86_64-linux.tar.gz
891        mv wasi-sdk-24.0-x86_64-linux wasi-sdk
892    - run: |
893        sudo apt-get update && sudo apt-get install -y gdb lldb-15 llvm
894        # workaround for https://bugs.launchpad.net/ubuntu/+source/llvm-defaults/+bug/1972855
895        sudo mkdir -p /usr/lib/local/lib/python3.10/dist-packages/lldb
896        sudo ln -s /usr/lib/llvm-15/lib/python3.10/dist-packages/lldb/* /usr/lib/python3/dist-packages/lldb/
897        # Only testing release since it is more likely to expose issues with our low-level symbol handling.
898        cargo test --release --test all -- --ignored --test-threads 1 debug::
899      env:
900        LLDB: lldb-15 # override default version, 14
901        WASI_SDK_PATH: /tmp/wasi-sdk
902
903    # common logic to cancel the entire run if this job fails
904    - uses: ./.github/actions/cancel-on-failure
905      if: failure()
906
907  build-preview1-component-adapter:
908    name: Build wasi-preview1-component-adapter
909    needs: determine
910    if: needs.determine.outputs.preview1-adapter
911    runs-on: ubuntu-latest
912    permissions:
913      deployments: write
914      contents: write
915    steps:
916    - uses: actions/checkout@v4
917      with:
918        submodules: true
919    - uses: ./.github/actions/install-rust
920    - run: rustup target add wasm32-wasip1 wasm32-unknown-unknown
921
922    - name: Install wasm-tools
923      run: |
924        curl -L https://github.com/bytecodealliance/wasm-tools/releases/download/wasm-tools-1.0.27/wasm-tools-1.0.27-x86_64-linux.tar.gz | tar xfz -
925        echo `pwd`/wasm-tools-1.0.27-x86_64-linux >> $GITHUB_PATH
926
927    - run: ./ci/build-wasi-preview1-component-adapter.sh
928      env:
929        VERSION: ${{ github.sha }}
930
931    - uses: actions/upload-artifact@v4
932      with:
933        name: bins-wasi-preview1-component-adapter
934        path: target/wasm32-unknown-unknown/release/wasi_snapshot_preview1.*.wasm
935
936
937    # common logic to cancel the entire run if this job fails
938    - uses: ./.github/actions/cancel-on-failure
939      if: failure()
940
941  build-preview1-component-adapter-provider:
942    name: Build wasi-preview1-component-adapter-provider
943    needs: build-preview1-component-adapter
944    runs-on: ubuntu-latest
945    steps:
946    - uses: actions/checkout@v4
947      with:
948        submodules: true
949    - uses: ./.github/actions/install-rust
950    - uses: ./.github/actions/build-adapter-provider
951      with:
952        run-id: ${{ github.run_id }}
953
954    # common logic to cancel the entire run if this job fails
955    - uses: ./.github/actions/cancel-on-failure
956      if: failure()
957
958  # Verify the "min platform" example still works.
959  test-min-platform-example:
960    name: Test the min-platform example
961    needs: determine
962    if: needs.determine.outputs.run-full
963    runs-on: ubuntu-latest
964    steps:
965    - uses: actions/checkout@v4
966      with:
967        submodules: true
968    - uses: ./.github/actions/install-rust
969    - run: cargo install cbindgen --vers "^0.28" --locked
970    - run: rustup target add x86_64-unknown-none
971    - run: rustup target add wasm32-wasip2
972    - run: ./build.sh x86_64-unknown-none
973      working-directory: ./examples/min-platform
974
975    # Afterwards make sure the generated header file is up to date by ensuring
976    # that the regeneration process didn't change anything in-tree.
977    - run: git diff --exit-code
978
979    # Test some other feature combinations
980    - run: ./build.sh x86_64-unknown-none
981      working-directory: ./examples/min-platform
982      env:
983        WASMTIME_SIGNALS_BASED_TRAPS: 1
984
985    - run: ./build.sh x86_64-unknown-none
986      working-directory: ./examples/min-platform
987      env:
988        WASMTIME_SIGNALS_BASED_TRAPS: 1
989        MIN_PLATFORM_TEST_DISABLE_WASI: 1
990
991    # Add the `wasmtime-platform.h` file as a release artifact
992    - uses: actions/upload-artifact@v4
993      with:
994        name: wasmtime-platform-header
995        path: examples/min-platform/embedding/wasmtime-platform.h
996
997    # common logic to cancel the entire run if this job fails
998    - uses: ./.github/actions/cancel-on-failure
999      if: failure()
1000
1001  bench:
1002    needs: determine
1003    if: needs.determine.outputs.run-full
1004    name: Run benchmarks
1005    runs-on: ubuntu-latest
1006    steps:
1007    - uses: actions/checkout@v4
1008      with:
1009        submodules: true
1010    - uses: ./.github/actions/install-rust
1011    - run: rustup target add wasm32-wasip1
1012    - run: cargo test --benches --release
1013
1014    # common logic to cancel the entire run if this job fails
1015    - uses: ./.github/actions/cancel-on-failure
1016      if: failure()
1017
1018  # Verify that cranelift's code generation is deterministic
1019  meta_deterministic_check:
1020    needs: determine
1021    if: needs.determine.outputs.run-full
1022    name: Meta deterministic check
1023    runs-on: ubuntu-latest
1024    steps:
1025    - uses: actions/checkout@v4
1026      with:
1027        submodules: true
1028    - uses: ./.github/actions/install-rust
1029    - run: cd cranelift/codegen && cargo build --features all-arch
1030    - run: ci/ensure_deterministic_build.sh
1031
1032    # common logic to cancel the entire run if this job fails
1033    - uses: ./.github/actions/cancel-on-failure
1034      if: failure()
1035
1036  verify-publish:
1037    needs: determine
1038    if: github.repository == 'bytecodealliance/wasmtime' && needs.determine.outputs.run-full
1039    runs-on: ubuntu-latest
1040    steps:
1041    - uses: actions/checkout@v4
1042      with:
1043        submodules: true
1044    - uses: ./.github/actions/install-rust
1045    - run: |
1046        cd ${{ runner.tool_cache }}
1047        curl -L https://github.com/mozilla/sccache/releases/download/0.2.13/sccache-0.2.13-x86_64-unknown-linux-musl.tar.gz | tar xzf -
1048        echo "`pwd`/sccache-0.2.13-x86_64-unknown-linux-musl" >> $GITHUB_PATH
1049        echo RUSTC_WRAPPER=sccache >> $GITHUB_ENV
1050    - run: rustc scripts/publish.rs
1051    # Make sure the tree is publish-able as-is
1052    - run: ./publish verify
1053    # Make sure we can bump version numbers for the next release
1054    - run: ./publish bump
1055
1056    # common logic to cancel the entire run if this job fails
1057    - uses: ./.github/actions/cancel-on-failure
1058      if: failure()
1059
1060  # Run a subset of tests under MIRI on CI to help check the `unsafe` code in
1061  # Wasmtime to make sure it's at least not obviously incorrect for basic usage.
1062  # Note that this doesn't run the full test suite since MIRI can't actually run
1063  # WebAssembly itself at this time (aka it doesn't support a JIT). There are a
1064  # number of annotations throughout the code which gates some tests on MIRI not
1065  # being run.
1066  #
1067  # Note that `cargo nextest` is used here additionally to get parallel test
1068  # execution by default to help cut down on the time in CI.
1069  miri:
1070    strategy:
1071      matrix:
1072        include:
1073          - crate: "wasmtime --features pulley"
1074          - crate: "wasmtime-cli"
1075          - crate: "wasmtime-environ --all-features"
1076          - crate: "pulley-interpreter --all-features"
1077          - script: ./ci/miri-provenance-test.sh
1078    needs: determine
1079    if: needs.determine.outputs.test-miri && github.repository == 'bytecodealliance/wasmtime'
1080    name: Miri
1081    runs-on: ubuntu-latest
1082    env:
1083      CARGO_NEXTEST_VERSION: 0.9.88
1084      MIRIFLAGS: -Zmiri-permissive-provenance
1085    steps:
1086    - uses: actions/checkout@v4
1087      with:
1088        submodules: true
1089    - uses: ./.github/actions/install-rust
1090      with:
1091        toolchain: wasmtime-ci-pinned-nightly
1092    - run: rustup component add rust-src miri
1093    - uses: actions/cache@v4
1094      with:
1095        path: ${{ runner.tool_cache }}/cargo-nextest
1096        key: cargo-nextest-bin-${{ env.CARGO_NEXTEST_VERSION }}
1097    - run: echo "${{ runner.tool_cache }}/cargo-nextest/bin" >> $GITHUB_PATH
1098    - run: cargo install --root ${{ runner.tool_cache }}/cargo-nextest --version ${{ env.CARGO_NEXTEST_VERSION }} cargo-nextest --locked
1099    - run: |
1100        cargo miri nextest run -j4 --no-fail-fast -p ${{ matrix.crate }}
1101      if: ${{ matrix.crate }}
1102    - run: ${{ matrix.script }}
1103      if: ${{ matrix.script }}
1104
1105    # common logic to cancel the entire run if this job fails
1106    - uses: ./.github/actions/cancel-on-failure
1107      if: failure()
1108
1109  # Perform release builds of `wasmtime` and `libwasmtime.so`. Builds a variety
1110  # of platforms and architectures and then uploads the release artifacts to
1111  # this workflow run's list of artifacts.
1112  #
1113  # Note that the full matrix is computed by `ci/build-build-matrix.js`.
1114  build:
1115    needs: determine
1116    if: needs.determine.outputs.run-full
1117    name: Release build for ${{ matrix.build }}
1118    runs-on: ${{ matrix.os }}
1119    strategy:
1120      fail-fast: ${{ github.event_name != 'pull_request' }}
1121      matrix: ${{ fromJson(needs.determine.outputs.build-matrix) }}
1122    env: ${{ matrix.env || fromJSON('{}') }}
1123    steps:
1124    - uses: actions/checkout@v4
1125      with:
1126        submodules: true
1127
1128    - uses: ./.github/actions/install-ninja
1129    - uses: ./.github/actions/install-rust
1130      with:
1131        toolchain: ${{ matrix.rust }}
1132    - run: |
1133        rustup component add rust-src
1134        rustup target add ${{ matrix.target }}
1135
1136    # On one builder produce the source tarball since there's no need to produce
1137    # it everywhere
1138    - run: ./ci/build-src-tarball.sh
1139      if: matrix.build == 'x86_64-linux'
1140
1141    - uses: ./.github/actions/android-ndk
1142      if: contains(matrix.target, 'android')
1143      with:
1144        target: ${{ matrix.target }}
1145
1146    - run: ./ci/build-release-artifacts.sh "${{ matrix.build }}" "${{ matrix.target }}"
1147
1148    # Assemble release artifacts appropriate for this platform, then upload them
1149    # unconditionally to this workflow's files so we have a copy of them.
1150    - run: ./ci/build-tarballs.sh "${{ matrix.build }}" "${{ matrix.target }}"
1151
1152    - uses: actions/upload-artifact@v4
1153      with:
1154        name: bins-${{ matrix.build }}
1155        path: dist
1156
1157    # common logic to cancel the entire run if this job fails
1158    - uses: ./.github/actions/cancel-on-failure
1159      if: failure()
1160
1161  # This is a "join node" which depends on all prior workflows. The merge queue,
1162  # for example, gates on this to ensure that everything has executed
1163  # successfully.
1164  #
1165  # Note that this is required currently for odd reasons with github. Notably
1166  # the set of checks to enter the merge queue and leave the merge queue must
1167  # be the same which means that the "build" step for example shows as skipped
1168  # for PRs but expands to many different steps for merge-queue-based PRs. That
1169  # means that for that step there's no single name to gate on, so it's required
1170  # to have a "join" node here which joins everything.
1171  #
1172  # Note that this currently always runs to always report a status, even on
1173  # cancellation and even if dependency steps fail. Each dependency tries to
1174  # cancel the whole run if it fails, so if a test matrix entry fails, for
1175  # example, it cancels the build matrix entries too. This step then tries to
1176  # fail on cancellation to ensure that the dependency failures are propagated
1177  # correctly.
1178  ci-status:
1179    name: Record the result of testing and building steps
1180    runs-on: ubuntu-latest
1181    needs:
1182      - test
1183      - test_capi
1184      - test_debug_dwarf
1185      - test_fuzzing
1186      - test_wasi_nn
1187      - test_nightly
1188      - build
1189      - rustfmt
1190      - clangformat
1191      - cargo_deny
1192      - cargo_vet
1193      - doc
1194      - micro_checks
1195      - fiber_tests
1196      - clippy
1197      - monolith_checks
1198      - platform_checks
1199      - bench
1200      - meta_deterministic_check
1201      - verify-publish
1202      - determine
1203      - miri
1204      - build-preview1-component-adapter
1205      - build-preview1-component-adapter-provider
1206      - test-min-platform-example
1207      - check_js
1208    if: always()
1209    steps:
1210    - name: Successful test and build
1211      if: ${{ !(contains(needs.*.result, 'failure')) }}
1212      run: exit 0
1213    - name: Failing test and build
1214      if: ${{ contains(needs.*.result, 'failure') }}
1215      run: exit 1
1216    - name: Report failure on cancellation
1217      if: ${{ contains(needs.*.result, 'cancelled') || cancelled() }}
1218      run: exit 1
1219
1220  # The purpose of this jobs is to watch for changes on the `release-*`
1221  # branches of this repository and look for the term
1222  # "automatically-tag-and-release-this-commit" within merged PRs/commits. Once
1223  # that term is found the current version of `Cargo.toml`, the `wasmtime-cli`
1224  # Cargo.toml, is created as a tag and the tag is pushed to the repo.
1225  # Currently the tag is created through the GitHub API with an access token to
1226  # ensure that CI is further triggered for the tag itself which performs the
1227  # full release process.
1228  #
1229  # Note that this depends on the `ci-status` step above which is the "join"
1230  # point of this workflow for when everything succeeds. the purpose of that is
1231  # so that the tag is only created after the aftifacts have been uploaded for
1232  # this workflow as the `publish-artifacts.yml` workflow will download these
1233  # artifacts and then publish them to the tag.
1234  push-tag:
1235    runs-on: ubuntu-latest
1236    needs: ci-status
1237    if: |
1238      always()
1239      && needs.ci-status.result == 'success'
1240      && github.event_name == 'push'
1241      && startsWith(github.ref, 'refs/heads/release-')
1242      && github.repository == 'bytecodealliance/wasmtime'
1243    steps:
1244    - uses: actions/checkout@v4
1245      with:
1246        submodules: true
1247        fetch-depth: 0
1248    - name: Test if tag is needed
1249      run: |
1250        git log ${{ github.event.before }}...${{ github.event.after }} | tee main.log
1251        version=$(grep '^version =' Cargo.toml | head -n 1 | sed 's/.*"\(.*\)"/\1/')
1252        echo "version: $version"
1253        echo "version=$version" >> $GITHUB_OUTPUT
1254        echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
1255        if grep -q "automatically-tag-and-release-this-commit" main.log; then
1256          echo push-tag
1257          echo "push_tag=yes" >> $GITHUB_OUTPUT
1258        else
1259          echo no-push-tag
1260          echo "push_tag=no" >> $GITHUB_OUTPUT
1261        fi
1262      id: tag
1263    - name: Push the tag
1264      run: |
1265        git_refs_url=$(jq .repository.git_refs_url $GITHUB_EVENT_PATH | tr -d '"' | sed 's/{\/sha}//g')
1266        curl -iX POST $git_refs_url \
1267          -H "Authorization: token ${{ secrets.PERSONAL_ACCESS_TOKEN }}" \
1268          -d @- << EOF
1269        {
1270          "ref": "refs/tags/v${{ steps.tag.outputs.version }}",
1271          "sha": "${{ steps.tag.outputs.sha }}"
1272        }
1273        EOF
1274      if: steps.tag.outputs.push_tag == 'yes'
1275
1276  # File an issue on the repo if this run failed and was triggered via
1277  # `workflow_dispatch`, which mostly means that
1278  # `.github/workflows/trigger-release-branch-ci.yml` will file issues on
1279  # failure so we get to see a notification when a build fails for a historical
1280  # release branch.
1281  file-issue-on-error:
1282    name: File an issue if this build failed and was cron-triggered
1283    runs-on: ubuntu-latest
1284    needs: ci-status
1285    if: |
1286      always()
1287      && needs.ci-status.result != 'success'
1288      && github.event_name == 'workflow_dispatch'
1289    permissions:
1290      issues: write
1291    steps:
1292    - uses: actions/github-script@v7
1293      with:
1294        script: |
1295          github.rest.issues.create({
1296            owner: context.repo.owner,
1297            repo: context.repo.repo,
1298            title: `Failed CI build for ${context.ref}`,
1299            body: `See https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`,
1300          })
1301