fix: two files shipped in 0.3.0 that cannot compile from a tarball #141
Workflow file for this run
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: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| workflow_dispatch: | |
| env: | |
| CARGO_TERM_COLOR: always | |
| RUST_BACKTRACE: 1 | |
| jobs: | |
| python-lint: | |
| name: ruff | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| # The four `.py` files here are test helpers, not a package, so there is | |
| # nothing to install — `uvx` fetches ruff and runs it. Configuration lives | |
| # in the repository's pyproject.toml. | |
| - uses: astral-sh/setup-uv@v5 | |
| - name: ruff check | |
| run: uvx ruff check . | |
| - name: ruff format | |
| run: uvx ruff format --check . | |
| go-skiff-reference: | |
| name: pinned Go Skiff reference | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: actions/setup-go@v6 | |
| with: | |
| go-version: "1.25.x" | |
| - name: Go SDK v0.0.33 Skiff vectors | |
| working-directory: tests/skiff-go-interop | |
| run: go test ./... | |
| go-rpc-reference: | |
| name: pinned Go RPC wire-format reference | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: actions/setup-go@v6 | |
| with: | |
| go-version: "1.25.x" | |
| # Regenerates the byte vectors the Rust tests consume, and fails if the | |
| # Go SDK's own encoder and decoder disagree. `git diff --exit-code` | |
| # afterwards is what catches a vector that has silently changed: the | |
| # checked-in files must be exactly what the pinned SDK produces. | |
| - name: Go SDK v0.0.33 RPC vectors | |
| working-directory: tests/rpc-go-interop | |
| run: go test ./... | |
| - name: The checked-in vectors are the ones the Go SDK produces | |
| run: git diff --exit-code -- tests/rpc-go-interop | |
| check: | |
| name: fmt + clippy + test | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| # `ytsaurus-proto`'s bindings are committed, so the build no longer needs | |
| # this — the drift check below does. Not `submodules: true` on the | |
| # checkout above: that clones the whole YTsaurus monorepo, and the script | |
| # takes the shallow, sparse path that fetches only `yt/yt_proto/`. | |
| - name: Check out the YTsaurus protos | |
| run: ./scripts/init-protos.sh | |
| # rust-toolchain.toml pins the channel, components and targets. | |
| - name: Install toolchain | |
| run: rustup show active-toolchain || rustup toolchain install | |
| - uses: Swatinem/rust-cache@v2 | |
| # The committed bindings must be exactly what the pinned submodule | |
| # produces. Same shape as the Go RPC vector check above, and for the same | |
| # reason: generated code that is committed can drift from its source, and | |
| # the only thing that catches it is regenerating and diffing. | |
| - name: The committed protobuf bindings are the ones the submodule produces | |
| run: | | |
| cargo xtask generate-protos | |
| git diff --exit-code -- crates/ytsaurus-proto/src/generated | |
| # `include_str!`/`include_bytes!` resolve at compile time, so a published | |
| # file reaching outside its own crate builds here and cannot build from a | |
| # tarball. `cargo package` does not catch it — it verifies by building the | |
| # library, not the tests — and 0.3.0 shipped two such files because the | |
| # check for them was a line-based grep and the macros had newlines in | |
| # them. This parses instead. | |
| - name: No published file reaches outside its own crate | |
| run: ./scripts/check-package-includes.sh | |
| - name: cargo fmt --check | |
| run: cargo fmt --all -- --check | |
| - name: cargo clippy | |
| run: cargo clippy --workspace --all-targets -- -D warnings | |
| # The client without TLS is what a worker binary links against, and the | |
| # `https://` refusal only exists in that build. Nothing else compiles it. | |
| - name: cargo clippy (client without TLS) | |
| run: cargo clippy -p ytsaurus-client --no-default-features --all-targets -- -D warnings | |
| # `derive` and `tracing` are both off by default, so the workspace build | |
| # compiles neither the macro against the client's own types nor the spans | |
| # and the `tracing`-shaped retry reporting. Clippy as well as the tests: | |
| # the two spellings of `observe` are separate code, and only one of them | |
| # is linted above. | |
| - name: cargo clippy (client with every feature) | |
| run: cargo clippy -p ytsaurus-client --all-features --all-targets -- -D warnings | |
| - name: cargo test (client with every feature) | |
| run: cargo test -p ytsaurus-client --all-features | |
| # The workers are examples of `ytsaurus-job`, and the end-to-end tests | |
| # below exec them. `--all-targets` does not build a runnable one — there | |
| # `--examples` means *test* the examples, so each is compiled as a libtest | |
| # harness and no plain binary is produced — and `tests/common::example` | |
| # answers that by building what it needs. Doing it here as well is not | |
| # redundant: it builds the nine once, before any test runs, instead of | |
| # leaving several test binaries to discover the gap at the same moment and | |
| # queue behind each other on cargo's lock. | |
| - name: Build the worker examples the e2e tests run | |
| run: cargo build -p ytsaurus-job --examples | |
| - name: cargo test | |
| run: cargo test --workspace --all-targets | |
| # `--all-targets` skips doctests, and the mapper example in the | |
| # ytsaurus-job docs must keep compiling. | |
| - name: cargo test --doc | |
| run: cargo test --workspace --doc | |
| # `--all-targets` also skips `#[ignore]`d tests, so the 2 GB streaming | |
| # test needs its own step or it never runs. It is the only guard against | |
| # the reader silently starting to accumulate input: ~10 s in debug, and | |
| # it asserts peak RSS stays far below the budget. | |
| - name: cargo test (2 GB streaming memory test) | |
| run: cargo test -p ytsaurus-job --test memory_tests -- --ignored --nocapture | |
| musl: | |
| name: static musl worker build | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| # No `init-protos.sh` here: the worker graph does not reach | |
| # `ytsaurus-proto`, and since its bindings are committed nothing in this | |
| # workspace needs the submodule to *build* at all. | |
| - name: Install toolchain | |
| run: rustup show active-toolchain || rustup toolchain install | |
| - uses: Swatinem/rust-cache@v2 | |
| # `tls` and `tracing` are both off in a worker build, and both would | |
| # break or bloat it: `rustls` reaches `ring`, which wants a C | |
| # cross-compiler, and a worker should carry only what it runs on. Neither | |
| # is off by accident — `ytsaurus-job` takes the client as a | |
| # `default-features = false` dev-dependency, for the `selfrun` example — | |
| # so this asserts the invariant rather than trusting it. | |
| # | |
| # `tokio` and `prost` are here for the same reason and a newer one: the | |
| # client's `rpc` feature reaches both, and that feature is off by default | |
| # *and required to stay off* precisely because this graph is what a musl | |
| # worker links. `ytsaurus-client`'s changelog promises this check exists, | |
| # so it does. | |
| # | |
| # Read **with** dev-dependencies, which is the whole point: cargo compiles | |
| # a package's dev-dependencies whenever it builds that package's examples, | |
| # and the workers are examples. That is also why criterion is pinned | |
| # below 0.8: 0.8 reaches `alloca`, whose build script wants the C | |
| # cross-compiler this build is meant not to need. `rustls-platform-verifier` is the third name for the same | |
| # reason: the `platform-verifier` feature is gated on `tls`, and this is | |
| # what says so out loud. | |
| # | |
| # Listed once and searched, rather than three `cargo tree -i` calls whose | |
| # *failure* was the passing signal. `-i` exits 101 both when the crate is | |
| # absent and when cargo itself could not run — a typo'd `-p`, a manifest | |
| # or lockfile error, an unreachable registry — so reading the exit code | |
| # turned every one of those into a silent pass. The message does not | |
| # separate them either: `-i` is resolved before `-p`, so a misspelled | |
| # package prints the same "did not match any packages" as an absent | |
| # crate. One invocation that must succeed puts all of that on the failing | |
| # side of `set -e` and leaves a plain membership test. | |
| - name: Assert the worker graph has no tracing and no TLS | |
| run: | | |
| set -euo pipefail | |
| graph=$(cargo tree -p ytsaurus-job \ | |
| --target x86_64-unknown-linux-musl \ | |
| --prefix none --no-dedupe | awk 'NF {print $1}' | sort -u) | |
| # A graph that lost the client is a graph this step is not reading, | |
| # and every absence below would be vacuously true. | |
| echo "$graph" | grep -qx ytsaurus-client || { | |
| echo "ERROR: the worker graph does not contain ytsaurus-client" | |
| echo "$graph"; exit 1; } | |
| for crate in tracing rustls ring rustls-platform-verifier tokio prost; do | |
| if echo "$graph" | grep -qx "$crate"; then | |
| echo "ERROR: $crate reached the worker build" | |
| cargo tree -p ytsaurus-job \ | |
| --target x86_64-unknown-linux-musl -i "$crate" | |
| exit 1 | |
| fi | |
| echo "OK: no $crate in the worker graph" | |
| done | |
| # Through the script rather than a bare cargo call: the script is what | |
| # stages each example from `<profile>/examples/<name>` into | |
| # `<profile>/<name>`, which is the layout the assertion below and every | |
| # document in the repository expect. Running it here also means the thing | |
| # contributors run is the thing CI exercises. | |
| - name: Build worker binaries | |
| run: ./scripts/build-worker.sh | |
| - name: Assert binaries are statically linked | |
| run: | | |
| set -euo pipefail | |
| shopt -s nullglob | |
| bins=(target/x86_64-unknown-linux-musl/release-worker/*) | |
| found=0 | |
| for f in "${bins[@]}"; do | |
| [ -f "$f" ] && [ -x "$f" ] || continue | |
| case "$f" in *.d|*.rlib) continue;; esac | |
| echo "--- $f" | |
| file "$f" | |
| # rustc emits static-pie for musl; both spellings mean "no libc.so". | |
| file "$f" | grep -Eq 'statically linked|static-pie linked' | |
| # A dynamically linked binary would list shared objects here. | |
| ! ldd "$f" 2>&1 | grep -q '=> /' || { | |
| echo "ERROR: $f has dynamic dependencies"; exit 1; } | |
| found=$((found + 1)) | |
| done | |
| if [ "$found" -eq 0 ]; then | |
| echo "ERROR: no worker binaries were produced"; exit 1 | |
| fi | |
| echo "OK: $found statically linked worker binaries" |