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