Skip to content

chore: release (#955) #2928

chore: release (#955)

chore: release (#955) #2928

Workflow file for this run

name: CI
on:
pull_request:
merge_group:
push:
branches: [main]
permissions:
contents: read
env:
STABLE_TOOLCHAIN: "1.94.1"
jobs:
fmt:
name: Cargo fmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master
with:
toolchain: nightly
components: rustfmt
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
save-if: ${{ github.ref == 'refs/heads/main' }}
- run: cargo fmt --all -- --check
clippy:
name: Cargo clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master
with:
toolchain: ${{ env.STABLE_TOOLCHAIN }}
components: clippy
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Run clippy check
run: cargo clippy --all-targets --all-features -- -D warnings
env:
RUSTFLAGS: "--cfg tokio_unstable"
build:
name: Build (${{ matrix.os }}, ${{ matrix.toolchain }})
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
toolchain: ["1.94.1"]
# aarch64 Linux exercises arch-specific unwind asm, PAC stripping,
# and ucontext layout that x86_64 Linux doesn't cover.
include:
- os: ubuntu-24.04-arm
toolchain: "1.94.1"
env:
RUST_BACKTRACE: 1
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: ./.github/actions/rust-build
with:
toolchain: ${{ matrix.toolchain }}
save-if: ${{ github.ref == 'refs/heads/main' }}
freebsd:
name: FreeBSD 15.1
runs-on: ubuntu-latest
continue-on-error: true
timeout-minutes: 30
env:
RUST_BACKTRACE: 1
RUSTFLAGS: "--cfg tokio_unstable -C force-frame-pointers=yes"
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Build and test in FreeBSD
uses: vmactions/freebsd-vm@77ed28d336d03fe19a3f4f7266c1d2c4714dd79d # v1.5.2
with:
release: "15.1"
usesh: true
copyback: false
cache-after-prepare: true
envs: "RUST_BACKTRACE RUSTFLAGS"
prepare: |
pkg install -y rustup-init
rustup-init -y --profile minimal --default-toolchain "${{ env.STABLE_TOOLCHAIN }}"
. "$HOME/.cargo/env"
run: |
. "$HOME/.cargo/env"
freebsd-version
rustc --version
cargo test -p dial9-core \
freebsd_tid_matches_kernel_thread_id
cargo test -p dial9-tokio-telemetry \
--test park_unpark_tid \
--test process_resource_usage
cargo test -p dial9-perf-self-profile \
--features "process-resource test-util" \
process_resource
windows-cli-check:
name: Windows CLI check
runs-on: windows-latest
if: github.event_name == 'push'
env:
RUSTFLAGS: "--cfg tokio_unstable"
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master
with:
toolchain: ${{ env.STABLE_TOOLCHAIN }}
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
save-if: ${{ github.ref == 'refs/heads/main' }}
- run: cargo check -p dial9-viewer
- run: cargo check -p dial9 --features cli
android-aarch64-build:
name: Android aarch64 build
runs-on: ubuntu-latest
env:
ANDROID_API: "30"
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master
with:
toolchain: ${{ env.STABLE_TOOLCHAIN }}
targets: aarch64-linux-android
- name: Build CPU profiling example
run: |
toolchain="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin"
export AR="$toolchain/llvm-ar"
export RANLIB="$toolchain/llvm-ranlib"
export CC_aarch64_linux_android="$toolchain/aarch64-linux-android$ANDROID_API-clang"
export CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER="$CC_aarch64_linux_android"
cargo build -p dial9-perf-self-profile \
--example basic \
--target aarch64-linux-android
# TEMPORARY: the nightly build is disabled while aws-runtime fails to compile
# on nightly rustc (E0282 type-inference regression upstream). This gate skips
# `build-nightly` until 2026-07-20 (UTC), after which the job re-enables
# automatically. Remove this `nightly-gate` job and the `needs:`/`if:` lines on
# `build-nightly` once the upstream issue resolves.
nightly-gate:
name: Nightly build gate
runs-on: ubuntu-latest
outputs:
enabled: ${{ steps.check.outputs.enabled }}
steps:
- id: check
run: |
if [[ "$(date -u +%Y-%m-%d)" < "2026-07-20" ]]; then
echo "Nightly build temporarily disabled until 2026-07-20; skipping."
echo "enabled=false" >> "$GITHUB_OUTPUT"
else
echo "enabled=true" >> "$GITHUB_OUTPUT"
fi
build-nightly:
name: Build (${{ matrix.os }}, nightly)
runs-on: ${{ matrix.os }}
# Nightly builds against the LATEST dependency versions (the rust-build
# action deletes Cargo.lock on nightly). This is an early-warning canary for
# toolchain/ecosystem breakage and is intentionally NOT part of `ci-pass`, so
# a nightly rustc regression or a freshly published dependency does not block
# PRs. Watch it on main; fix forward when it goes red.
needs: nightly-gate
if: needs.nightly-gate.outputs.enabled == 'true'
continue-on-error: true
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
env:
RUST_BACKTRACE: 1
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: ./.github/actions/rust-build
with:
toolchain: nightly
save-if: ${{ github.ref == 'refs/heads/main' }}
feature-check:
name: Feature combinations
runs-on: ubuntu-latest
env:
RUSTFLAGS: "--cfg tokio_unstable"
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master
with:
toolchain: ${{ env.STABLE_TOOLCHAIN }}
- uses: taiki-e/install-action@184183c2401be73c3bf42c2e61268aa5855379c1 # v2
with:
tool: cargo-hack
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Check each feature compiles
run: >
cargo hack check
--each-feature --no-dev-deps
--workspace
--exclude metrics-service
--exclude simple-local
--exclude-features _shuttle
- name: Test viewer without S3
run: cargo test -p dial9-viewer --no-default-features --lib
- name: Check local-only viewer excludes AWS dependencies
run: |
cargo tree -p dial9-viewer --no-default-features \
--target all --edges normal --prefix none --format '{p}' \
> /tmp/dial9-viewer-local-tree.txt
if grep -E '^(aws-|s3s)' /tmp/dial9-viewer-local-tree.txt; then
echo "AWS SDK/S3 dependencies found in the local-only viewer graph"
exit 1
fi
- name: Check S3 CLI includes the AWS SDK
run: |
cargo tree -p dial9 --no-default-features --features cli \
--target all --edges normal --prefix none --format '{p}' \
> /tmp/dial9-cli-s3-tree.txt
if ! grep -qE '^aws-sdk-s3 ' /tmp/dial9-cli-s3-tree.txt; then
echo "S3 CLI no longer includes aws-sdk-s3"
exit 1
fi
no-tokio-unstable:
name: Build without tokio_unstable
runs-on: ubuntu-latest
# Drops the cfg but keeps the frame pointers the repo config also sets,
# since env RUSTFLAGS replaces [build] rustflags wholesale.
env:
RUSTFLAGS: "-C force-frame-pointers=yes"
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master
with:
toolchain: ${{ env.STABLE_TOOLCHAIN }}
- uses: taiki-e/install-action@184183c2401be73c3bf42c2e61268aa5855379c1 # v2
with:
tool: nextest
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Enable perf_event_open and kallsyms for tests
run: |
sudo sysctl kernel.perf_event_paranoid=1
sudo sysctl kernel.kptr_restrict=0
# `__nonlinux_all_features` is every feature except `taskdump`, which
# forwards to tokio/taskdump and is a hard compile error without the cfg.
- name: Test dial9-tokio-telemetry
run: |
# Raise locked-memory limit for large perf ring buffers, as the
# rust-build action does. Without it perf_event_open cannot map its
# ring and the profiler falls back to ctimer.
sudo prlimit --pid $$ --memlock=unlimited:unlimited
cargo nextest run -p dial9-tokio-telemetry --features __nonlinux_all_features
- name: Check the facade
run: cargo check -p dial9 --features tokio,analysis,cpu-profiling
check-docs:
name: Check docs.rs
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master
with:
toolchain: nightly
components: rust-docs
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
save-if: ${{ github.ref == 'refs/heads/main' }}
- run: command -v jq >/dev/null || (sudo apt-get update && sudo apt-get install -y jq)
- run: cargo install cargo-docs-rs
- run: ./scripts/check-docsrs.sh
trace-integrity:
name: Trace Integrity & Analysis
runs-on: ubuntu-latest
services:
dynamodb-local:
image: amazon/dynamodb-local
ports:
- 8000:8000
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master
with:
toolchain: ${{ env.STABLE_TOOLCHAIN }}
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
save-if: ${{ github.ref == 'refs/heads/main' }}
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: 24
- name: Enable perf_event_open and kallsyms for tests
run: |
sudo sysctl kernel.perf_event_paranoid=1
sudo sysctl kernel.kptr_restrict=0
- run: scripts/e2e-trace-tests.sh
ui:
name: UI (tsc, vitest, vite build)
runs-on: ubuntu-latest
defaults:
run:
working-directory: dial9-viewer/ui
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: 24
cache: npm
cache-dependency-path: dial9-viewer/ui/package-lock.json
- run: npm ci
- run: npx tsc --noEmit
# Re-checks src/types/*.d.ts with skipLibCheck OFF: the main config's
# skipLibCheck (for node_modules) also skips our hand-written frozen-core
# declarations, which is how three of them drifted from the JS.
- run: npm run check:types
- run: npm run test
- run: npm run build
asan:
name: AddressSanitizer (perf-self-profile)
runs-on: ubuntu-latest
env:
RUST_BACKTRACE: 1
RUSTFLAGS: "--cfg tokio_unstable -C force-frame-pointers=yes -Zsanitizer=address"
RUSTDOCFLAGS: "-Zsanitizer=address"
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master
with:
toolchain: nightly
components: rust-src
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
- name: Enable perf_event_open and kallsyms
run: |
sudo sysctl kernel.perf_event_paranoid=1
sudo sysctl kernel.kptr_restrict=0
- name: Run perf-self-profile tests under ASAN (perf path)
run: |
sudo prlimit --pid $$ --memlock=unlimited:unlimited
cargo test -p dial9-perf-self-profile --lib --all-features \
-Z build-std --target x86_64-unknown-linux-gnu
- name: Run memory profiler under ASAN without frame pointers
env:
CARGO_TARGET_DIR: target/asan-no-frame-pointers
RUSTFLAGS: "--cfg tokio_unstable -C force-frame-pointers=no -Zsanitizer=address"
run: |
cargo test --release \
-p dial9-perf-self-profile \
--test memory_profiler_no_frame_pointers \
--features memory-profiling \
-Z build-std --target x86_64-unknown-linux-gnu \
-- --exact allocation_hook_survives_best_effort_stack_capture
- name: Restrict perf_event_open to force ctimer path
run: sudo sysctl kernel.perf_event_paranoid=3
- name: Run perf-self-profile tests under ASAN (ctimer path)
# paranoid=3 blocks perf_event_open
# With paranoid=3, /proc/kallsyms shows zero kernel addresses on this runner
run: |
sudo prlimit --pid $$ --memlock=unlimited:unlimited
cargo test -p dial9-perf-self-profile --lib --all-features \
-Z build-std --target x86_64-unknown-linux-gnu \
-- --skip sys::linux::symbolize::tests::resolve_kernel_symbol_returns_name
ecs-sim:
name: ECS simulation (ctimer fallback)
runs-on: ubuntu-latest
env:
RUST_BACKTRACE: 1
RUSTFLAGS: "--cfg tokio_unstable -C force-frame-pointers=yes"
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master
with:
toolchain: ${{ env.STABLE_TOOLCHAIN }}
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
- name: Restrict perf_event_open (simulate ECS/Fargate)
# paranoid=3 blocks perf_event_open to trigger the ctimer fallback path
run: sudo sysctl kernel.perf_event_paranoid=3
- name: Run perf-self-profile tests (auto-fallback path)
# With paranoid=3, /proc/kallsyms also shows zero kernel addresses on this runner
# (exact mechanism is kernel/distro specific), so resolve_kernel_symbol_returns_name fails.
# Kernel symbolization is also irrelevant to this path: frame-pointer unwinding only captures
# userspace addresses.
run: |
cargo test -p dial9-perf-self-profile --lib --all-features \
-- --skip sys::linux::symbolize::tests::resolve_kernel_symbol_returns_name
frame-pointer-detection:
name: Missing frame pointers are detected
runs-on: ubuntu-latest
env:
RUST_BACKTRACE: 1
# Deliberately omits `-C force-frame-pointers=yes` so the ignored test below exercises a real
# missing-frame-pointers build.
RUSTFLAGS: "--cfg tokio_unstable"
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master
with:
toolchain: ${{ env.STABLE_TOOLCHAIN }}
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
- name: Verify MemoryProfiler::install() detects missing frame pointers
run: |
cargo test -p dial9 --features memory-profiling \
--test memory_profiling_missing_frame_pointers -- --ignored
shuttle:
name: Shuttle tests
runs-on: ubuntu-latest
env:
RUST_BACKTRACE: 1
RUSTFLAGS: "--cfg tokio_unstable --cfg shuttle"
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master
with:
toolchain: ${{ env.STABLE_TOOLCHAIN }}
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Run shuttle tests
run: scripts/test-shuttle.sh
semver-checks:
name: Semver checks
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
# Need full history so cargo-semver-checks can use origin/main as the baseline.
fetch-depth: 0
- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master
with:
toolchain: ${{ env.STABLE_TOOLCHAIN }}
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Install cargo-semver-checks
uses: taiki-e/install-action@184183c2401be73c3bf42c2e61268aa5855379c1 # v2
with:
tool: cargo-semver-checks
- name: Check semver compliance
env:
RUSTFLAGS: "--cfg tokio_unstable"
# Compare against origin/main rather than the latest crates.io release. This
# surfaces only breaking changes introduced *by this PR* — accumulated breaks
# already on main don't relitigate on every PR. release-plz's own
# semver_check (at release time) is the gate that ensures a major bump
# before publishing.
run: |
cargo semver-checks \
--baseline-rev origin/main \
-p dial9-trace-format-derive \
-p dial9-trace-format \
-p dial9-core \
-p dial9-perf-self-profile \
-p dial9-macro \
-p dial9-utils \
-p dial9-tokio-telemetry \
-p dial9-metrique \
-p dial9-destinations-s3
package:
name: Cargo package
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master
with:
toolchain: ${{ env.STABLE_TOOLCHAIN }}
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Verify all publishable crates package cleanly
env:
RUSTFLAGS: "--cfg tokio_unstable"
run: |
cargo package \
-p dial9-trace-format-derive \
-p dial9-trace-format \
-p dial9-core \
-p dial9-utils \
-p dial9-destinations-s3 \
-p dial9-perf-self-profile \
-p dial9-macro \
-p dial9-metrique \
-p dial9-tokio-telemetry \
-p dial9-viewer \
-p dial9
- name: Verify the skills are packaged as real files
# `dial9/skills`, the toolkit libraries and the viewer URL contract are
# symlinks; cargo must materialize them. `cargo package --list` cannot
# show that, the tarball can.
run: |
for c in dial9 dial9-viewer; do
rm -rf "/tmp/pkg-$c" && mkdir -p "/tmp/pkg-$c"
tar -xzf target/package/"$c"-[0-9]*.crate -C "/tmp/pkg-$c"
test -s "/tmp/pkg-$c"/*/skills/dial9-toolkit/scripts/trace_parser.js \
|| { echo "$c: toolkit not packaged"; exit 1; }
test -s "/tmp/pkg-$c"/*/skills/dial9-zoom-window/references/viewer-urls.md \
|| { echo "$c: viewer URL contract not packaged"; exit 1; }
if find "/tmp/pkg-$c" -path '*/skills/*' \( -type l -o -type f -empty \) | grep .; then
echo "$c: symlinked or empty skill files in the package (above)"; exit 1
fi
done
doctests:
name: Doc tests (dial9)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master
with:
toolchain: ${{ env.STABLE_TOOLCHAIN }}
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Run dial9 doctests
run: cargo test -p dial9 --doc --all-features
env:
RUSTFLAGS: "--cfg tokio_unstable"
ci-pass:
name: CI Pass
runs-on: ubuntu-latest
needs: [fmt, clippy, build, android-aarch64-build, feature-check, no-tokio-unstable, check-docs, trace-integrity, ui, asan, ecs-sim, frame-pointer-detection, shuttle, package, doctests]
if: always()
steps:
- run: |
if [[ "${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}" == "true" ]]; then
echo "One or more required jobs failed or were cancelled"
exit 1
fi