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