Layered EdgeZero deploy actions + Fastly staging lifecycle (design + impl, supersedes #303) #718
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: "Run Tests" | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| test: | |
| name: cargo test | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Cache Cargo dependencies | |
| uses: actions/cache@v5 | |
| with: | |
| path: | | |
| ~/.cargo/bin/ | |
| ~/.cargo/registry/index/ | |
| ~/.cargo/registry/cache/ | |
| ~/.cargo/git/db/ | |
| target/ | |
| key: ${{ runner.os }}-cargo-test-${{ hashFiles('**/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo-test- | |
| - name: Retrieve Rust version | |
| id: rust-version | |
| run: echo "rust-version=$(grep '^rust ' .tool-versions | awk '{print $2}')" >> $GITHUB_OUTPUT | |
| shell: bash | |
| - name: Set up Rust tool chain | |
| uses: actions-rust-lang/setup-rust-toolchain@v1 | |
| with: | |
| toolchain: ${{ steps.rust-version.outputs.rust-version }} | |
| - name: Add wasm targets | |
| run: rustup target add wasm32-wasip1 wasm32-wasip2 wasm32-unknown-unknown | |
| - name: Fetch dependencies (locked) | |
| run: cargo fetch --locked | |
| - name: No placeholder pins | |
| run: ./scripts/check_no_placeholder_pins.sh | |
| - name: No legacy typed reads | |
| run: ./scripts/check_no_legacy_typed_reads.sh | |
| - name: Nested AppConfig audit | |
| run: cargo run -q --bin check_no_nested_app_config --features nested-app-config-check -- examples/app-demo crates/edgezero-cli/src/templates | |
| # The checker's own unit tests live behind `required-features = | |
| # ["nested-app-config-check"]`, so the unfeatured | |
| # `cargo test --workspace` step below does not compile or run them. | |
| # Exercise them explicitly to keep the coverage closure enforced by CI. | |
| - name: Nested AppConfig checker tests | |
| run: cargo test -p edgezero-cli --features nested-app-config-check --bin check_no_nested_app_config | |
| - name: Run workspace tests | |
| run: cargo test --workspace --all-targets | |
| # The adapter CLI dispatch (build/deploy/stage/healthcheck/rollback) and | |
| # its tests live behind the `cli` feature, which the unfeatured | |
| # `cargo test --workspace` step above does not enable — so none of those | |
| # tests compile or run there. Exercise them explicitly. | |
| - name: Adapter CLI dispatch tests | |
| run: cargo test -p edgezero-adapter-fastly --all-targets --features cli | |
| - name: Check feature compilation | |
| run: cargo check --workspace --all-targets --features "fastly cloudflare spin" | |
| - name: Verify a generated project compiles | |
| run: cargo test -p edgezero-cli --test generated_project_builds -- --ignored | |
| # `examples/app-demo` is excluded from the root workspace, so | |
| # `cargo test --workspace` above does not cover it. Run its own | |
| # workspace tests separately. An end-to-end push → | |
| # AxumConfigStore → handler roundtrip in | |
| # `app-demo-cli/tests/config_flow.rs` exists to be exercised by | |
| # THIS step — without it, a regression in the JSON-file contract | |
| # between `config push --adapter axum` and | |
| # `AxumConfigStore::from_path` would not be caught by CI. | |
| # Axum-only path, no live external calls — intentionally kept | |
| # off the wasm matrix. | |
| - name: Run app-demo workspace tests | |
| working-directory: examples/app-demo | |
| run: cargo test --workspace --all-targets | |
| adapter-wasm-tests: | |
| name: ${{ matrix.adapter }} wasm tests | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - adapter: cloudflare | |
| target: wasm32-unknown-unknown | |
| runner_env: CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER | |
| runner_value: wasm-bindgen-test-runner | |
| - adapter: fastly | |
| target: wasm32-wasip1 | |
| runner_env: CARGO_TARGET_WASM32_WASIP1_RUNNER | |
| runner_value: viceroy run | |
| - adapter: spin | |
| target: wasm32-wasip2 | |
| runner_env: CARGO_TARGET_WASM32_WASIP2_RUNNER | |
| runner_value: wasmtime run | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Cache Cargo dependencies | |
| uses: actions/cache@v5 | |
| with: | |
| path: | | |
| ~/.cargo/bin/ | |
| ~/.cargo/registry/index/ | |
| ~/.cargo/registry/cache/ | |
| ~/.cargo/git/db/ | |
| ~/.wasmtime/bin/ | |
| target/ | |
| key: ${{ runner.os }}-cargo-${{ matrix.adapter }}-${{ hashFiles('**/Cargo.lock', '.tool-versions') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo-${{ matrix.adapter }}- | |
| - name: Retrieve Rust version | |
| id: rust-version | |
| run: echo "rust-version=$(grep '^rust ' .tool-versions | awk '{print $2}')" >> $GITHUB_OUTPUT | |
| shell: bash | |
| - name: Set up Rust tool chain | |
| uses: actions-rust-lang/setup-rust-toolchain@v1 | |
| with: | |
| toolchain: ${{ steps.rust-version.outputs.rust-version }} | |
| - name: Add wasm target | |
| run: rustup target add ${{ matrix.target }} | |
| - name: Resolve wasm-bindgen CLI version | |
| if: matrix.adapter == 'cloudflare' | |
| id: wasm-bindgen-version | |
| shell: bash | |
| run: | | |
| version="$( | |
| awk ' | |
| $1 == "name" && $3 == "\"wasm-bindgen\"" { in_pkg=1; next } | |
| in_pkg && $1 == "version" { | |
| gsub(/"/, "", $3) | |
| print $3 | |
| exit | |
| } | |
| ' Cargo.lock | |
| )" | |
| test -n "$version" | |
| echo "version=$version" >> "$GITHUB_OUTPUT" | |
| # `--force` is required because the cargo cache may restore an existing | |
| # `~/.cargo/bin/<binary>` from a prior run, which `cargo install` rejects | |
| # by default. Force-overwriting is safe — `--locked` pins the version. | |
| - name: Install wasm-bindgen test runner | |
| if: matrix.adapter == 'cloudflare' | |
| run: cargo install wasm-bindgen-cli --version "${{ steps.wasm-bindgen-version.outputs.version }}" --locked --force | |
| - name: Resolve Viceroy version | |
| if: matrix.adapter == 'fastly' | |
| id: viceroy-version | |
| shell: bash | |
| run: echo "version=$(grep '^viceroy ' .tool-versions | awk '{print $2}')" >> "$GITHUB_OUTPUT" | |
| - name: Setup Viceroy | |
| if: matrix.adapter == 'fastly' | |
| # Version comes from .tool-versions (single source of truth shared with | |
| # local dev). | |
| run: cargo install viceroy --version "${{ steps.viceroy-version.outputs.version }}" --locked --force | |
| - name: Resolve Wasmtime version | |
| if: matrix.adapter == 'spin' | |
| id: wasmtime-version | |
| shell: bash | |
| run: echo "version=$(grep '^wasmtime ' .tool-versions | awk '{print $2}')" >> "$GITHUB_OUTPUT" | |
| - name: Setup Wasmtime | |
| if: matrix.adapter == 'spin' | |
| # Direct GitHub-release tarball install. The official | |
| # `https://wasmtime.dev/install.sh` script broke as of | |
| # 2026-05-19 (interpolation failure: tried to download | |
| # version literal `{`), so we pin via .tool-versions and | |
| # land the binary in `~/.wasmtime/bin/` so the cache step | |
| # above actually short-circuits the download on subsequent | |
| # runs. | |
| # | |
| # The cache key now hashes `.tool-versions` too, so a | |
| # version bump invalidates the cached binary. We also | |
| # explicitly compare `wasmtime --version` against the pin | |
| # — without that a runner-provided wasmtime or a stale | |
| # cache hit would silently shadow the pinned version. | |
| run: | | |
| install_dir="$HOME/.wasmtime/bin" | |
| echo "$install_dir" >> "$GITHUB_PATH" | |
| export PATH="$install_dir:$PATH" | |
| version="${{ steps.wasmtime-version.outputs.version }}" | |
| # Compare exact versions so a pin like `44.0.1` does not silently | |
| # accept `wasmtime 44.0.10` from a stale cache or runner-provided | |
| # binary. | |
| actual="$(wasmtime --version 2>/dev/null | awk '{print $2}' || true)" | |
| if [ "$actual" != "$version" ]; then | |
| tag="v${version}" | |
| archive="wasmtime-${tag}-x86_64-linux" | |
| mkdir -p "$install_dir" | |
| curl -fL "https://github.com/bytecodealliance/wasmtime/releases/download/${tag}/${archive}.tar.xz" -o /tmp/wasmtime.tar.xz | |
| tar -xJf /tmp/wasmtime.tar.xz -C /tmp | |
| install -m 0755 "/tmp/${archive}/wasmtime" "$install_dir/wasmtime" | |
| fi | |
| actual="$(wasmtime --version | awk '{print $2}')" | |
| test "$actual" = "$version" | |
| wasmtime --version | |
| - name: Fetch dependencies (locked) | |
| run: cargo fetch --locked | |
| - name: Run ${{ matrix.adapter }} wasm tests | |
| env: | |
| ${{ matrix.runner_env }}: ${{ matrix.runner_value }} | |
| run: cargo test -p edgezero-adapter-${{ matrix.adapter }} --features ${{ matrix.adapter }} --target ${{ matrix.target }} --test contract | |
| - name: Check ${{ matrix.adapter }} wasm target | |
| run: cargo check -p edgezero-adapter-${{ matrix.adapter }} --features ${{ matrix.adapter }} --target ${{ matrix.target }} |