Skip to content

CI

CI #228

Workflow file for this run

name: CI
on:
# Run CI for PRs to `main` and to release branches.
#
# Note that PRs to `main` will run a subset of tests and PRs to the
# `release-*` branches will run full CI.
pull_request:
branches:
- main
- 'release-*'
# Run full CI on the `main` branch once a day to prime the GitHub Actions
# caches used by PRs and the merge queue.
schedule:
- cron: '13 4 * * *'
# This is the CI that runs for PRs-to-merge.
merge_group:
push:
branches:
# Right now merge queues can't be used with wildcards in branch protections
# so full CI runs both on PRs to release branches as well as merges to
# release branches. Note that the merge to a release branch may produce a
# tag at the end of CI if successful and the tag will trigger the artifact
# uploads as well as publication to crates.io.
- 'release-*'
defaults:
run:
shell: bash
# Cancel any in-flight jobs for the same PR/branch so there's only one active
# at a time
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
# Check Code style quickly by running `rustfmt` over all code
rustfmt:
name: Rustfmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/install-rust
- run: rustup component add rustfmt
- run: cargo fmt --all -- --check
# common logic to cancel the entire run if this job fails
- run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
# Quick JS formatting/linting checks for the little bits of JS we have for the
# `wasmtime explore` UI.
check_js:
name: Check JS
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm install
working-directory: ./crates/explorer
- run: npm run lint
working-directory: ./crates/explorer
- run: npm run fmt-check
working-directory: ./crates/explorer
# common logic to cancel the entire run if this job fails
- run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
# Check Code style quickly by running `clang-format` over all the C/C++ code
#
# Note that `wasmtime-platform.h` is excluded here as it's auto-generated.
clangformat:
name: Clang format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- run: |
git ls-files '*.h' '*.c' '*.cpp' | \
grep -v wasmtime-platform.h | \
grep -v wasm.h | \
xargs clang-format-15 --dry-run --Werror --verbose
# common logic to cancel the entire run if this job fails
- run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
# Lint dependency graph for security advisories, duplicate versions, and
# incompatible licences
cargo_deny:
name: Cargo deny
needs: determine
if: needs.determine.outputs.audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/install-rust
- run: |
set -e
curl -L https://github.com/EmbarkStudios/cargo-deny/releases/download/0.14.5/cargo-deny-0.14.5-x86_64-unknown-linux-musl.tar.gz | tar xzf -
mv cargo-deny-*-x86_64-unknown-linux-musl/cargo-deny cargo-deny
echo `pwd` >> $GITHUB_PATH
- run: cargo deny check bans licenses
# common logic to cancel the entire run if this job fails
- run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
# Ensure dependencies are vetted. See https://mozilla.github.io/cargo-vet/
#
# Note that this step, on PRs only, is allowed to fail. This is then followed
# up with the `cargo_vet_failure_for_prs` step below. The intention is to
# avoid causing this check to fail PRs while still enabling it to fail the
# merge queue checks. That way PRs can enter the merge queue when this step is
# failing if `main` has picked up `cargo vet` entries in the meantime for the
# failures.
cargo_vet:
name: Cargo vet
needs: determine
if: needs.determine.outputs.audit
runs-on: ubuntu-latest
outputs:
outcome: ${{ steps.vet.outcome }}
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/install-rust
- uses: ./.github/actions/install-cargo-vet
- id: vet
run: cargo vet --locked
continue-on-error: ${{ github.event_name == 'pull_request' }}
# Double-check that if versions are bumped that `cargo vet` still works.
# This is intended to weed out mistakes such as #9115 from happening again.
- run: rustc scripts/publish.rs && ./publish bump-patch && cargo vet
name: Ensure `cargo vet` works if versions are bumped
# common logic to cancel the entire run if this job fails
- run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
cargo_vet_failure_for_prs:
name: Cargo vet failed on a Pull Request
needs:
- determine
- cargo_vet
if: |
needs.determine.outputs.audit
&& github.event_name == 'pull_request'
&& needs.cargo_vet.outputs.outcome == 'failure'
runs-on: ubuntu-latest
steps:
# NB: this message ideally would link back to the previous step, but I'm not
# sure how to easily do that.
- run: |
echo 'failed to run "cargo vet", see previous `Cargo vet` step'
echo 'exiting with a nonzero status now to alert PR authors'
echo 'note, though, that this PR can still enter the merge queue'
echo ''
echo 'See https://docs.wasmtime.dev/contributing-coding-guidelines.html#cargo-vet-for-contributors'
echo 'for more information about the vetting process for Wasmtime'
exit 1
# This job is a dependency of many of the jobs below. This calculates what's
# actually being run for this workflow. For example:
#
# * Pushes to branches, which is currently both pushes to merge queue branches
# as well as release branches, perform full CI.
# * PRs to release branches (not `main`) run full CI.
# * PRs to `main` will only run a few smoke tests above plus some elements of
# the test matrix. The test matrix here is determined dynamically by the
# `./ci/build-test-matrix.js` script given the commits that happened and
# the files modified.
determine:
name: Determine CI jobs to run
runs-on: ubuntu-latest
outputs:
run-full: ${{ steps.calculate.outputs.run-full }}
test-matrix: ${{ steps.calculate.outputs.test-matrix }}
build-matrix: ${{ steps.calculate.outputs.build-matrix }}
test-capi: ${{ steps.calculate.outputs.test-capi }}
test-nightly: ${{ steps.calculate.outputs.test-nightly }}
test-miri: ${{ steps.calculate.outputs.test-miri }}
audit: ${{ steps.calculate.outputs.audit }}
preview1-adapter: ${{ steps.calculate.outputs.preview1-adapter }}
run-dwarf: ${{ steps.calculate.outputs.run-dwarf }}
steps:
- uses: actions/checkout@v4
- id: calculate
env:
GH_TOKEN: ${{ github.token }}
run: |
touch commits.log names.log
# Note that CI doesn't run on pushes to `main`, only pushes to merge
# queue branches and release branches, so this only runs full CI in
# those locations.
if [ "${{ github.event_name }}" != "pull_request" ]; then
run_full=true
else
pr=${{ github.event.number }}
gh pr view $pr --json commits | tee commits.log
gh pr diff $pr --name-only | tee names.log || echo "failed to get files"
if [ "${{ github.base_ref }}" != "main" ]; then
run_full=true
elif grep -q 'prtest:full' commits.log; then
run_full=true
elif grep -q 'prtest:debug' commits.log; then
echo run-dwarf=true >> $GITHUB_OUTPUT
fi
if grep -q crates.c-api names.log; then
echo test-capi=true >> $GITHUB_OUTPUT
fi
if grep -q fuzz names.log; then
echo test-nightly=true >> $GITHUB_OUTPUT
fi
if grep -q sys.custom names.log; then
echo test-nightly=true >> $GITHUB_OUTPUT
fi
if grep -q Cargo.lock names.log; then
echo audit=true >> $GITHUB_OUTPUT
fi
if grep -q supply-chain names.log; then
echo audit=true >> $GITHUB_OUTPUT
fi
if grep -q component-adapter names.log; then
echo preview1-adapter=true >> $GITHUB_OUTPUT
fi
if grep -q debug names.log; then
echo run-dwarf=true >> $GITHUB_OUTPUT
fi
if grep -q pulley names.log; then
echo test-nightly=true >> $GITHUB_OUTPUT
echo test-miri=true >> $GITHUB_OUTPUT
fi
fi
matrix="$(node ./ci/build-test-matrix.js ./commits.log ./names.log $run_full)"
echo "test-matrix={\"include\":$(echo $matrix)}" >> $GITHUB_OUTPUT
echo "$matrix"
matrix="$(node ./ci/build-build-matrix.js)"
echo "build-matrix={\"include\":$(echo $matrix)}" >> $GITHUB_OUTPUT
if [ "$run_full" = "true" ]; then
echo run-full=true >> $GITHUB_OUTPUT
echo test-capi=true >> $GITHUB_OUTPUT
echo test-nightly=true >> $GITHUB_OUTPUT
echo test-miri=true >> $GITHUB_OUTPUT
echo audit=true >> $GITHUB_OUTPUT
echo preview1-adapter=true >> $GITHUB_OUTPUT
echo run-dwarf=true >> $GITHUB_OUTPUT
fi
# Build all documentation of Wasmtime, including the C API documentation,
# mdbook documentation, etc. This produces a `gh-pages` artifact which is what
# gets uploaded to the `gh-pages` branch later on.
doc:
needs: determine
if: needs.determine.outputs.run-full
name: Doc build
runs-on: ubuntu-latest
env:
CARGO_MDBOOK_VERSION: 0.4.37
RUSTDOCFLAGS: -Dbroken_intra_doc_links --cfg docsrs
OPENVINO_SKIP_LINKING: 1
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/install-rust
with:
toolchain: wasmtime-ci-pinned-nightly
# Build C API documentation
- run: curl -L https://sourceforge.net/projects/doxygen/files/rel-1.9.3/doxygen-1.9.3.linux.bin.tar.gz/download | tar xzf -
- run: echo "`pwd`/doxygen-1.9.3/bin" >> $GITHUB_PATH
- run: cmake -S crates/c-api -B target/c-api
- run: cmake --build target/c-api --target doc
# install mdbook, build the docs, and test the docs
- uses: actions/cache@v4
with:
path: ${{ runner.tool_cache }}/mdbook
key: cargo-mdbook-bin-${{ env.CARGO_MDBOOK_VERSION }}
- run: |
echo "${{ runner.tool_cache }}/mdbook/bin" >> $GITHUB_PATH
cargo install --root ${{ runner.tool_cache }}/mdbook --version ${{ env.CARGO_MDBOOK_VERSION }} mdbook --locked
- run: (cd docs && mdbook build)
- run: cargo build -p wasi-common --features wasmtime/wat,wasmtime/cranelift
- run: (cd docs && mdbook test -L ../target/debug/deps)
# Build Rust API documentation.
#
# Enable extra features in crates as well to ensure they're documented
- run: |
cargo doc --no-deps --workspace \
--exclude wasmtime-cli \
--exclude test-programs \
--exclude cranelift-codegen-meta \
--features call-hook
env:
RUSTDOCFLAGS: --cfg=docsrs
- run: cargo doc --package cranelift-codegen-meta --document-private-items
env:
RUSTDOCFLAGS: --cfg=docsrs
# Assemble the documentation, and always upload it as an artifact for
# inspection on PRs and such.
- run: |
mv docs/book gh-pages
mv crates/c-api/html gh-pages/c-api
mv target/doc gh-pages/api
tar czf gh-pages.tar.gz gh-pages
- uses: actions/upload-artifact@v4
with:
name: gh-pages
path: gh-pages.tar.gz
# common logic to cancel the entire run if this job fails
- run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
# Checks of various feature combinations and whether things compile. The goal
# here isn't to run tests, mostly just serve as a double-check that Rust code
# compiles and is likely to work everywhere else.
micro_checks:
name: Check ${{matrix.name}}
strategy:
fail-fast: true
matrix:
include:
- name: wasmtime
checks: |
-p wasmtime --no-default-features
-p wasmtime --no-default-features --features wat
-p wasmtime --no-default-features --features profiling
-p wasmtime --no-default-features --features cache
-p wasmtime --no-default-features --features async
-p wasmtime --no-default-features --features pooling-allocator
-p wasmtime --no-default-features --features cranelift
-p wasmtime --no-default-features --features component-model
-p wasmtime --no-default-features --features runtime,component-model
-p wasmtime --no-default-features --features cranelift,wat,async,cache
-p wasmtime --no-default-features --features winch
-p wasmtime --no-default-features --features wmemcheck
-p wasmtime --no-default-features --features wmemcheck,cranelift,runtime
-p wasmtime --no-default-features --features demangle
-p wasmtime --no-default-features --features addr2line
-p wasmtime --no-default-features --features gc
-p wasmtime --no-default-features --features runtime,gc
-p wasmtime --no-default-features --features cranelift,gc
-p wasmtime --no-default-features --features runtime
-p wasmtime --no-default-features --features threads
-p wasmtime --no-default-features --features runtime,threads
-p wasmtime --no-default-features --features cranelift,threads
-p wasmtime --features incremental-cache
-p wasmtime --all-features
- name: wasmtime-cli
checks: |
-p wasmtime-cli --no-default-features
-p wasmtime-cli --no-default-features --features pooling-allocator
-p wasmtime-cli --no-default-features --features run
-p wasmtime-cli --no-default-features --features run,component-model
-p wasmtime-cli --no-default-features --features run,pooling-allocator
-p wasmtime-cli --no-default-features --features compile
-p wasmtime-cli --no-default-features --features compile,cranelift
-p wasmtime-cli --no-default-features --features compile,cranelift,component-model
-p wasmtime-cli --all-features
-p wasmtime-cli --features component-model
- name: cranelift-codegen
checks: |
-p cranelift-codegen --benches
-p cranelift-codegen --no-default-features --features std,unwind,pulley
- name: wasmtime-bench-api
checks: |
-p wasmtime-bench-api
- name: wasmtime-c-api
checks: |
-p wasmtime-c-api --no-default-features
-p wasmtime-c-api --no-default-features --features wat
-p wasmtime-c-api --no-default-features --features wasi
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/install-rust
# Run the check.
- run: |
checks=$(cat <<END
${{ matrix.checks }}
END
)
echo "$checks" | xargs -I CHECK sh -c 'echo "=== cargo check CHECK ==="; cargo check CHECK'
# Common logic to cancel the entire run if this job fails.
- run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
# Checks for no_std support, ensure that crates can build on a no_std target
no_std_checks:
name: no_std checks
runs-on: ubuntu-latest
env:
CARGO_NDK_VERSION: 2.12.2
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/install-rust
- run: rustup target add x86_64-unknown-none
- run: cargo check --target x86_64-unknown-none -p wasmtime --no-default-features --features runtime,gc,component-model
- run: cargo check --target x86_64-unknown-none -p cranelift-control --no-default-features
- run: cargo check --target x86_64-unknown-none -p pulley-interpreter --features encode,decode,disas,interp
# common logic to cancel the entire run if this job fails
- run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
# Check that Clippy lints are passing.
clippy:
name: Clippy
runs-on: ubuntu-latest
env:
CARGO_NDK_VERSION: 2.12.2
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/install-rust
- run: rustup component add clippy
- run: cargo clippy --workspace --all-targets
# common logic to cancel the entire run if this job fails
- run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
# Similar to `micro_checks` but where we need to install some more state
# (e.g. Android NDK) and we haven't factored support for those things out into
# a parallel jobs yet.
monolith_checks:
name: Monolith Checks
runs-on: ubuntu-latest
env:
CARGO_NDK_VERSION: 2.12.2
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/install-rust
# Check that wasmtime compiles with panic=abort since there's some `#[cfg]`
# for specifically panic=abort there.
- run: cargo check -p wasmtime
env:
RUSTFLAGS: -Cpanic=abort
# Check a few builds of the cranelift backend
# - only x86 backend support,
# - only arm64 backend support,
# - no debug_assertions.
- run: cargo check --manifest-path=./cranelift/Cargo.toml --bin clif-util --no-default-features --features=cranelift-codegen/arm64
- run: cargo check --manifest-path=./cranelift/Cargo.toml --bin clif-util --no-default-features --features=cranelift-codegen/x86
- run: cargo check --manifest-path=./cranelift/Cargo.toml --bin clif-util
env:
CARGO_PROFILE_DEV_DEBUG_ASSERTIONS: false
# Check whether `wasmtime` cross-compiles to x86_64-unknown-freebsd
# TODO: We aren't building with default features since the `ittapi` crate fails to compile on freebsd.
- run: rustup target add x86_64-unknown-freebsd
- run: cargo check -p wasmtime --no-default-features --features cranelift,wat,async,cache --target x86_64-unknown-freebsd
# Re-vendor all WIT files and ensure that they're all up-to-date by ensuring
# that there's no git changes.
- name: Re-vendor WIT
run: ./ci/vendor-wit.sh
- run: git diff --exit-code
# Re-vendor the C API and make sure it's up-to-date.
- name: Re-vendor C API
run: ./ci/vendor-c-api-headers.sh
- run: git diff --exit-code
# common logic to cancel the entire run if this job fails
- run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
# Check whether `wasmtime` cross-compiles to aarch64-pc-windows-msvc
# We don't build nor test it because it lacks trap handling.
# Tracking issue: https://github.com/bytecodealliance/wasmtime/issues/4992
checks_winarm64:
needs: determine
if: needs.determine.outputs.run-full
name: Check Windows ARM64
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/install-rust
- run: rustup target add aarch64-pc-windows-msvc
- run: cargo check -p wasmtime --target aarch64-pc-windows-msvc
# common logic to cancel the entire run if this job fails
- run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
# Run tests that require a nightly compiler, such as building fuzz targets.
test_nightly:
needs: determine
if: needs.determine.outputs.test-nightly
name: Nightly tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
# Note that nightly is pinned here to insulate us from breakage that might
# happen upstream. This is periodically updated through a PR.
- uses: ./.github/actions/install-rust
with:
toolchain: wasmtime-ci-pinned-nightly
# Check that `pulley-interpreter` compiles with tail calls enabled. Don't
# actually run the tests with tail calls enabled, because they are not yet
# implemented in rustc and cause an ICE.
- run: cargo check -p pulley-interpreter
env:
RUSTFLAGS: "--cfg pulley_tail_calls"
# Ensure that fuzzers still build.
#
# Install the OCaml packages necessary for fuzz targets that use the
# `wasm-spec-interpreter`.
- run: cargo install cargo-fuzz --vers "^0.11" --locked
- run: sudo apt-get update && sudo apt install -y ocaml-nox ocamlbuild ocaml-findlib libzarith-ocaml-dev
- run: cargo fetch
working-directory: ./fuzz
- run: cargo fuzz build --dev
- run: cargo fuzz build --dev --fuzz-dir ./cranelift/isle/fuzz
- run: cargo fuzz build --dev --fuzz-dir ./crates/environ/fuzz --features component-model
# common logic to cancel the entire run if this job fails
- run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
# Perform all tests of the c-api
test_capi:
needs: determine
name: Test C-API ${{ matrix.os }}
runs-on: ${{ matrix.os }}
if: needs.determine.outputs.test-capi
strategy:
fail-fast: true
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/install-rust
# Build and test the C API with example C programs along with the example
# Rust programs. Note that this only executes if the `determine` step told
# us to test the capi which is off-by-default for PRs.
- run: cmake -Sexamples -Bexamples/build -DBUILD_SHARED_LIBS=OFF
- run: cmake --build examples/build --config Debug
- run: cmake -E env CTEST_OUTPUT_ON_FAILURE=1 cmake --build examples/build --config Debug --target RUN_TESTS
env:
RUST_BACKTRACE: 1
if: matrix.os == 'windows-latest'
- run: cmake -E env CTEST_OUTPUT_ON_FAILURE=1 cmake --build examples/build --config Debug --target test
env:
RUST_BACKTRACE: 1
if: matrix.os != 'windows-latest'
# Perform all tests (debug mode) for `wasmtime`.
#
# Note that the full matrix for what may run here is defined within
# `./ci/build-test-matrix.js` and the execution of the `determine` step will
# calculate whether the tests are actually run as part of PRs and such.
test:
needs: determine
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
env:
QEMU_BUILD_VERSION: 8.1.5
strategy:
fail-fast: ${{ github.event_name != 'pull_request' }}
matrix: ${{ fromJson(needs.determine.outputs.test-matrix) }}
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/install-rust
with:
toolchain: ${{ matrix.rust }}
# Install targets in order to build various tests throughout the repo
- run: rustup target add wasm32-wasip1 wasm32-unknown-unknown ${{ matrix.target }}
- run: echo CARGO_BUILD_TARGET=${{ matrix.target }} >> $GITHUB_ENV
if: matrix.target != ''
# Fix an ICE for now in gcc when compiling zstd with debuginfo (??)
- run: echo CFLAGS=-g0 >> $GITHUB_ENV
if: matrix.target == 'x86_64-pc-windows-gnu'
# Update binutils if MinGW due to https://github.com/rust-lang/rust/issues/112368
- run: C:/msys64/usr/bin/pacman.exe -S --needed mingw-w64-x86_64-gcc --noconfirm
if: matrix.target == 'x86_64-pc-windows-gnu'
- shell: pwsh
run: echo "C:\msys64\mingw64\bin" >> $Env:GITHUB_PATH
if: matrix.target == 'x86_64-pc-windows-gnu'
- run: cargo fetch --locked
- name: Install cross-compilation tools
run: |
set -ex
sudo apt-get update
sudo apt-get install -y ${{ matrix.gcc_package }} ninja-build
# Configure Cargo for cross compilation and tell it how it can run
# cross executables
upcase=$(echo ${{ matrix.target }} | awk '{ print toupper($0) }' | sed 's/-/_/g')
echo CARGO_TARGET_${upcase}_LINKER=${{ matrix.gcc }} >> $GITHUB_ENV
if: matrix.gcc != ''
- uses: actions/cache@v4
with:
path: ${{ runner.tool_cache }}/qemu
key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}-patchcpuinfo
if: matrix.qemu != ''
- name: Install qemu
run: |
set -ex
upcase=$(echo ${{ matrix.target }} | awk '{ print toupper($0) }' | sed 's/-/_/g')
echo CARGO_TARGET_${upcase}_RUNNER=${{ runner.tool_cache }}/qemu/bin/${{ matrix.qemu }} >> $GITHUB_ENV
# QEMU emulation is not always the speediest, so total testing time
# goes down if we build the libs in release mode when running tests.
echo CARGO_PROFILE_DEV_OPT_LEVEL=2 >> $GITHUB_ENV
# See comments in the source for why we enable this during QEMU
# emulation.
echo WASMTIME_TEST_NO_HOG_MEMORY=1 >> $GITHUB_ENV
# See if qemu is already in the cache
if [ -f ${{ runner.tool_cache }}/qemu/built ]; then
exit 0
fi
# Download and build qemu from source since the most recent release is
# way faster at arm emulation than the current version github actions'
# ubuntu image uses. Disable as much as we can to get it to build
# quickly.
curl https://download.qemu.org/qemu-$QEMU_BUILD_VERSION.tar.xz | tar xJf -
cd qemu-$QEMU_BUILD_VERSION
./configure --target-list=${{ matrix.qemu_target }} --prefix=${{ runner.tool_cache}}/qemu --disable-tools --disable-slirp --disable-fdt --disable-capstone --disable-docs
ninja -C build install
touch ${{ runner.tool_cache }}/qemu/built
if: matrix.qemu != ''
# Record some CPU details; this is helpful information if tests fail due
# to CPU-specific features.
- name: CPU information
run: lscpu
if: matrix.os == 'ubuntu-latest'
- name: CPU information
run: sysctl hw
if: contains(matrix.os, 'macos')
- name: CPU information
run: wmic cpu list /format:list
shell: pwsh
if: matrix.os == 'windows-latest'
# Since MPK (PKU) is not present on some GitHub runners, we check if it is
# available before force-enabling it. This occasional testing is better than
# none at all; ideally we would test in a system-mode QEMU VM.
- name: Force-run with MPK enabled, if available
if: ${{ contains(matrix.name, 'MPK') }}
run: |
if cargo run --example mpk-available; then
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."
echo WASMTIME_TEST_FORCE_MPK=1 >> $GITHUB_ENV
else
echo "::warning::This CI run will not test MPK; it has been detected as not available on this machine (\`cargo run --example mpk-available\`)."
fi
# Install VTune, see `cli_tests::profile_with_vtune`.
- name: Install VTune
if: matrix.filter == 'linux-x64' && contains(matrix.bucket, 'wasmtime-cli')
uses: abrown/install-vtune-action@v1
# Build and test all features
- run: ./ci/run-tests.sh --locked ${{ matrix.bucket }}
env:
RUST_BACKTRACE: 1
# NB: the test job here is explicitly lacking in cancellation of this run if
# something goes wrong. These take the longest anyway and otherwise if
# Windows fails GitHub Actions will confusingly mark the failed Windows job
# as cancelled instead of failed.
# Test `wasmtime-wasi-nn` in its own job, as not all of its backends are
# compatible with all targets, and each must be tested separately anyways.
test_wasi_nn:
strategy:
matrix:
feature: ["openvino", "onnx"]
os: ["ubuntu-latest", "windows-latest"]
include:
- os: windows-latest
feature: winml
name: Test wasi-nn (${{ matrix.feature }}, ${{ matrix.os }})
runs-on: ${{ matrix.os }}
needs: determine
if: needs.determine.outputs.run-full
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/install-rust
# Install OpenVINO
- uses: abrown/install-openvino-action@v9
if: runner.arch == 'X64'
# Install WinML for testing wasi-nn WinML backend. WinML is only available
# on Windows clients and Windows Server with desktop experience enabled.
# GitHub Actions Window Server image doesn't have desktop experience
# enabled, so we download the standalone library from ONNX Runtime project.
- uses: nuget/setup-nuget@v2
if: (matrix.os == 'windows-latest') && (matrix.feature == 'winml')
- run: nuget install Microsoft.AI.MachineLearning
if: (matrix.os == 'windows-latest') && (matrix.feature == 'winml')
# Install Rust targets.
- run: rustup target add wasm32-wasip1
# Run the tests!
- run: cargo test -p wasmtime-wasi-nn --features ${{ matrix.feature }}
env:
RUST_BACKTRACE: 1
# common logic to cancel the entire run if this job fails
- run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
# Test the `wasmtime-fuzzing` crate. Split out from the main tests because
# `--all-features` brings in OCaml, which is a pain to get setup for all
# targets.
test_fuzzing:
needs: determine
if: needs.determine.outputs.run-full
name: Test wasmtime-fuzzing
runs-on: 'ubuntu-latest'
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/install-rust
# Run the tests
- run: |
cargo test -p wasmtime-fuzzing -p wasm-spec-interpreter
env:
RUST_BACKTRACE: 1
# common logic to cancel the entire run if this job fails
- run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
# Test debug (DWARF) related functionality.
test_debug_dwarf:
needs: determine
if: needs.determine.outputs.run-dwarf
name: Test DWARF debugging
runs-on: 'ubuntu-latest'
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/install-rust
- run: rustup target add wasm32-wasip1 wasm32-unknown-unknown
- run: |
sudo apt-get update && sudo apt-get install -y gdb lldb-15 llvm
# workaround for https://bugs.launchpad.net/ubuntu/+source/llvm-defaults/+bug/1972855
sudo mkdir -p /usr/lib/local/lib/python3.10/dist-packages/lldb
sudo ln -s /usr/lib/llvm-15/lib/python3.10/dist-packages/lldb/* /usr/lib/python3/dist-packages/lldb/
cargo test --test all -- --ignored --test-threads 1 debug::
env:
RUST_BACKTRACE: 1
LLDB: lldb-15 # override default version, 14
# common logic to cancel the entire run if this job fails
- run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
build-preview1-component-adapter:
name: Build wasi-preview1-component-adapter
needs: determine
if: needs.determine.outputs.preview1-adapter
runs-on: ubuntu-latest
permissions:
deployments: write
contents: write
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/install-rust
- run: rustup target add wasm32-wasip1 wasm32-unknown-unknown
- name: Install wasm-tools
run: |
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 -
echo `pwd`/wasm-tools-1.0.27-x86_64-linux >> $GITHUB_PATH
- run: ./ci/build-wasi-preview1-component-adapter.sh
env:
VERSION: ${{ github.sha }}
- uses: actions/upload-artifact@v4
with:
name: bins-wasi-preview1-component-adapter
path: target/wasm32-unknown-unknown/release/wasi_snapshot_preview1.*.wasm
# common logic to cancel the entire run if this job fails
- run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
build-preview1-component-adapter-provider:
name: Build wasi-preview1-component-adapter-provider
needs: build-preview1-component-adapter
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/install-rust
- uses: ./.github/actions/build-adapter-provider
with:
run-id: ${{ github.run_id }}
# common logic to cancel the entire run if this job fails
- run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
# Verify the "min platform" example still works.
test-min-platform-example:
name: Test the min-platform example
needs: determine
if: needs.determine.outputs.run-full
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/install-rust
- run: cargo install cbindgen --vers "^0.26" --locked
- run: rustup target add x86_64-unknown-none
- run: ./build.sh x86_64-unknown-none
working-directory: ./examples/min-platform
# Afterwards make sure the generated header file is up to date by ensuring
# that the regeneration process didn't change anything in-tree.
- run: git diff --exit-code
# Add the `wasmtime-platform.h` file as a release artifact
- uses: actions/upload-artifact@v4
with:
name: wasmtime-platform-header
path: examples/min-platform/embedding/wasmtime-platform.h
# common logic to cancel the entire run if this job fails
- run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
build-wasmtime-target-wasm32:
name: Build wasmtime-target-wasm32
if: needs.determine.outputs.run-full
needs: determine
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/install-rust
- run: rustup target add wasm32-wasip1 wasm32-unknown-unknown
- run: cargo build --target wasm32-wasip1 --no-default-features --features compile,cranelift,all-arch
env:
VERSION: ${{ github.sha }}
# common logic to cancel the entire run if this job fails
- run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
bench:
needs: determine
if: needs.determine.outputs.run-full
name: Run benchmarks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/install-rust
- run: rustup target add wasm32-wasip1
- run: cargo test --benches --release
# common logic to cancel the entire run if this job fails
- run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
# Verify that cranelift's code generation is deterministic
meta_deterministic_check:
needs: determine
if: needs.determine.outputs.run-full
name: Meta deterministic check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/install-rust
- run: cd cranelift/codegen && cargo build --features all-arch
- run: ci/ensure_deterministic_build.sh
# common logic to cancel the entire run if this job fails
- run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
verify-publish:
needs: determine
if: github.repository == 'bytecodealliance/wasmtime' && needs.determine.outputs.run-full
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/install-rust
- run: |
cd ${{ runner.tool_cache }}
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 -
echo "`pwd`/sccache-0.2.13-x86_64-unknown-linux-musl" >> $GITHUB_PATH
echo RUSTC_WRAPPER=sccache >> $GITHUB_ENV
- run: rustc scripts/publish.rs
# Make sure the tree is publish-able as-is
- run: ./publish verify
# Make sure we can bump version numbers for the next release
- run: ./publish bump
# common logic to cancel the entire run if this job fails
- run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
# Run a subset of tests under MIRI on CI to help check the `unsafe` code in
# Wasmtime to make sure it's at least not obviously incorrect for basic usage.
# Note that this doesn't run the full test suite since MIRI can't actually run
# WebAssembly itself at this time (aka it doesn't support a JIT). There are a
# number of annotations throughout the code which gates some tests on MIRI not
# being run.
#
# Note that `cargo nextest` is used here additionally to get parallel test
# execution by default to help cut down on the time in CI.
miri:
strategy:
matrix:
crate:
- "wasmtime"
- "wasmtime-cli"
- "wasmtime-environ"
- "pulley-interpreter --all-features"
needs: determine
if: needs.determine.outputs.test-miri && github.repository == 'bytecodealliance/wasmtime'
name: Miri
runs-on: ubuntu-latest
env:
CARGO_NEXTEST_VERSION: 0.9.67
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/install-rust
with:
toolchain: wasmtime-ci-pinned-nightly
- run: rustup component add rust-src miri
- uses: actions/cache@v4
with:
path: ${{ runner.tool_cache }}/cargo-nextest
key: cargo-nextest-bin-${{ env.CARGO_NEXTEST_VERSION }}
- run: echo "${{ runner.tool_cache }}/cargo-nextest/bin" >> $GITHUB_PATH
- run: cargo install --root ${{ runner.tool_cache }}/cargo-nextest --version ${{ env.CARGO_NEXTEST_VERSION }} cargo-nextest --locked
- run: |
cargo miri nextest run -j4 --no-fail-fast -p ${{ matrix.crate }}
env:
MIRIFLAGS: -Zmiri-strict-provenance
# common logic to cancel the entire run if this job fails
- run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
# Perform release builds of `wasmtime` and `libwasmtime.so`. Builds a variety
# of platforms and architectures and then uploads the release artifacts to
# this workflow run's list of artifacts.
#
# Note that the full matrix is computed by `ci/build-build-matrix.js`.
build:
needs: determine
if: needs.determine.outputs.run-full
name: Release build for ${{ matrix.build }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: ${{ github.event_name != 'pull_request' }}
matrix: ${{ fromJson(needs.determine.outputs.build-matrix) }}
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/install-rust
with:
toolchain: ${{ matrix.rust }}
- run: |
rustup component add rust-src
rustup target add ${{ matrix.target }}
# On one builder produce the source tarball since there's no need to produce
# it everywhere
- run: ./ci/build-src-tarball.sh
if: matrix.build == 'x86_64-linux'
- uses: ./.github/actions/binary-compatible-builds
with:
name: ${{ matrix.build }}
- uses: ./.github/actions/android-ndk
if: contains(matrix.target, 'android')
with:
target: ${{ matrix.target }}
- run: $CENTOS ./ci/build-release-artifacts.sh "${{ matrix.build }}" "${{ matrix.target }}"
# Assemble release artifacts appropriate for this platform, then upload them
# unconditionally to this workflow's files so we have a copy of them.
- run: ./ci/build-tarballs.sh "${{ matrix.build }}" "${{ matrix.target }}"
- uses: actions/upload-artifact@v4
with:
name: bins-${{ matrix.build }}
path: dist
# common logic to cancel the entire run if this job fails
- run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
# This is a "join node" which depends on all prior workflows. The merge queue,
# for example, gates on this to ensure that everything has executed
# successfully.
#
# Note that this is required currently for odd reasons with github. Notably
# the set of checks to enter the merge queue and leave the merge queue must
# be the same which means that the "build" step for example shows as skipped
# for PRs but expands to many different steps for merge-queue-based PRs. That
# means that for that step there's no single name to gate on, so it's required
# to have a "join" node here which joins everything.
#
# Note that this currently always runs to always report a status, even on
# cancellation and even if dependency steps fail. Each dependency tries to
# cancel the whole run if it fails, so if a test matrix entry fails, for
# example, it cancels the build matrix entries too. This step then tries to
# fail on cancellation to ensure that the dependency failures are propagated
# correctly.
ci-status:
name: Record the result of testing and building steps
runs-on: ubuntu-latest
needs:
- test
- test_capi
- test_debug_dwarf
- test_fuzzing
- test_wasi_nn
- test_nightly
- build
- rustfmt
- clangformat
- cargo_deny
- cargo_vet
- doc
- micro_checks
- no_std_checks
- clippy
- monolith_checks
- checks_winarm64
- bench
- meta_deterministic_check
- verify-publish
- determine
- miri
- build-preview1-component-adapter
- build-preview1-component-adapter-provider
- build-wasmtime-target-wasm32
- test-min-platform-example
- check_js
if: always()
steps:
- name: Successful test and build
if: ${{ !(contains(needs.*.result, 'failure')) }}
run: exit 0
- name: Failing test and build
if: ${{ contains(needs.*.result, 'failure') }}
run: exit 1
- name: Report failure on cancellation
if: ${{ contains(needs.*.result, 'cancelled') || cancelled() }}
run: exit 1
# The purpose of this jobs is to watch for changes on the `release-*`
# branches of this repository and look for the term
# "automatically-tag-and-release-this-commit" within merged PRs/commits. Once
# that term is found the current version of `Cargo.toml`, the `wasmtime-cli`
# Cargo.toml, is created as a tag and the tag is pushed to the repo.
# Currently the tag is created through the GitHub API with an access token to
# ensure that CI is further triggered for the tag itself which performs the
# full release process.
#
# Note that this depends on the `ci-status` step above which is the "join"
# point of this workflow for when everything succeeds. the purpose of that is
# so that the tag is only created after the aftifacts have been uploaded for
# this workflow as the `publish-artifacts.yml` workflow will download these
# artifacts and then publish them to the tag.
push-tag:
runs-on: ubuntu-latest
needs: ci-status
if: |
always()
&& needs.ci-status.result == 'success'
&& github.event_name == 'push'
&& startsWith(github.ref, 'refs/heads/release-')
&& github.repository == 'bytecodealliance/wasmtime'
steps:
- uses: actions/checkout@v4
with:
submodules: true
fetch-depth: 0
- name: Test if tag is needed
run: |
git log ${{ github.event.before }}...${{ github.event.after }} | tee main.log
version=$(grep '^version =' Cargo.toml | head -n 1 | sed 's/.*"\(.*\)"/\1/')
echo "version: $version"
echo "version=$version" >> $GITHUB_OUTPUT
echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
if grep -q "automatically-tag-and-release-this-commit" main.log; then
echo push-tag
echo "push_tag=yes" >> $GITHUB_OUTPUT
else
echo no-push-tag
echo "push_tag=no" >> $GITHUB_OUTPUT
fi
id: tag
- name: Push the tag
run: |
git_refs_url=$(jq .repository.git_refs_url $GITHUB_EVENT_PATH | tr -d '"' | sed 's/{\/sha}//g')
curl -iX POST $git_refs_url \
-H "Authorization: token ${{ secrets.PERSONAL_ACCESS_TOKEN }}" \
-d @- << EOF
{
"ref": "refs/tags/v${{ steps.tag.outputs.version }}",
"sha": "${{ steps.tag.outputs.sha }}"
}
EOF
if: steps.tag.outputs.push_tag == 'yes'