Skip to content

chore: release v6.1.0 #6705

chore: release v6.1.0

chore: release v6.1.0 #6705

Workflow file for this run

name: test
on:
push:
branches: ["main"]
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions: {}
env:
MISE_EXPERIMENTAL: 1
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
test:
runs-on: ubuntu-latest
# Without this, a hung step sits until GitHub's 6-hour job limit.
timeout-minutes: 30
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
submodules: recursive
persist-credentials: false
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
shared-key: test
- uses: jdx/mise-action@7e36c90d9ab29c415a2384db3006f3ec8a8cc654 # v4.2.4
# Retries and a longer wait, rather than being allowed to fail. `cli`'s completion
# tests refuse to skip a missing shell when `CI` is set — see
# `skip_if_shell_missing` — which is a deliberate policy this step exists to keep:
# a run that quietly tested one shell instead of four is worse than a run that
# stopped. So the flakiness is what gets fixed, not the consequence of it.
#
# The failure mode, seen three times in an afternoon, is the azure mirror that
# GitHub's runners list first *stalling* rather than refusing. Retries alone did not
# help — an eight-minute attempt with them timed out the same way — because retrying
# a connection that hangs just hangs again. What was missing is a per-connection
# timeout: with one, apt gives up on the stalled mirror in seconds and moves to the
# next entry in `/etc/apt/apt-mirrors.txt`, which is the archive.ubuntu.com that was
# answering fine throughout.
#
# `bash-completion` is in the list for the same reason: usage no longer embeds a copy of
# it, so the generated bash completion needs the system one loaded, and
# `bash_completion_or_skip` panics under CI rather than skipping without it. The image
# already ships it; naming it here is what keeps that true if a future one stops.
#
# Deliberately the distro package rather than a newer build from source: `ubuntu-latest`
# is 24.04, whose 2.11 is the oldest version the generated script supports. Testing
# against the floor is the point — 26.04 ships 2.16, which would pass either way.
- name: Install shells and bash-completion for completion integration tests
timeout-minutes: 5
run: |
sudo sed -i 's|http://azure.archive.ubuntu.com/ubuntu|https://archive.ubuntu.com/ubuntu|g' /etc/apt/apt-mirrors.txt
sudo apt-get -o Acquire::Retries=3 -o Acquire::http::Timeout=15 -o Acquire::https::Timeout=15 update
sudo apt-get -o Acquire::Retries=3 -o Acquire::http::Timeout=15 -o Acquire::https::Timeout=15 install -y zsh fish bash-completion
# pwsh is pre-installed on GitHub ubuntu-latest images. Self-heal
# if a future image drops it so the integration test still runs
# (rather than panicking under CI=1).
if ! command -v pwsh >/dev/null 2>&1; then
sudo snap install powershell --classic
fi
# A step of its own, and `always()`, because the interesting time to hear which
# shells are present is the run where the one above did not finish — and a `set -e`
# script says nothing after the command that failed it.
- name: Report which shells are available
if: always()
run: |
probe_dir=$(mktemp -d)
trap 'rm -rf "$probe_dir"' EXIT
for shell in bash zsh fish pwsh; do
if [[ "$shell" == pwsh ]]; then
probe="$probe_dir/$shell.ps1"
else
probe="$probe_dir/$shell"
fi
printf 'echo ok\n' > "$probe"
if [[ "$shell" == pwsh ]]; then
output=$(pwsh -NoProfile -NonInteractive -File "$probe" 2>/dev/null) && usable=true || usable=false
else
output=$("$shell" "$probe" 2>/dev/null) && usable=true || usable=false
fi
if [[ "$usable" == true && "$output" == ok ]]; then
echo "$shell: $(command -v "$shell") (script probe passed)"
else
echo "::warning::$shell cannot run a script, so its completion tests cannot run"
fi
done
- run: mise r build
- run: mise r test
# Run here rather than in a job of its own: the corpus vectors carry KDL
# specs, and lowering them needs the `usage` CLI this job has already built.
- run: mise r test:go
# `os_string_from_bytes` has a `cfg` branch per platform, and every test of it is
# `#[cfg(unix)]` — so the Windows one is not compiled anywhere else in this pipeline.
# A compile check is not coverage, but it is what keeps that branch from rotting
# unseen.
- name: check the Windows-only conversion still compiles
run: |
rustup target add x86_64-pc-windows-msvc
cargo check -p usage-argv --all-features --target x86_64-pc-windows-msvc
# Everything else in this pipeline builds with `--all-features`, and resolver-v2 unification
# means a workspace build turns a feature on for every member as soon as one member wants it.
# So the shapes an adopter actually gets — usage-lib without `docs`, usage-rs without its
# defaults — are compiled nowhere else, and rotted unnoticed until they were measured.
- name: check the trimmed feature shapes still compile
run: |
cargo clippy -p usage-lib --no-default-features -- -D warnings
cargo clippy -p usage-rs --no-default-features -- -D warnings
cargo clippy -p usage-config --no-default-features -- -D warnings
- run: mise r render
# Same reasoning as `render`: the shadow is checked in, so a change to the derive's
# vocabulary that would alter it has to be committed rather than discovered later.
- run: mise r gen-shadow
# And the Go tables, for the same reason: they are checked in, so a change to
# the emitter that nobody meant has to show up as a diff here.
- run: mise r gen-go
- name: assert render, gen-shadow and gen-go produce no diff
run: |
if [ -n "$(git status --porcelain)" ]; then
echo "::error::'mise run render', 'mise run gen-shadow' or 'mise run gen-go' produced changes. Run them locally and commit."
git status
git diff
exit 1
fi
- run: mise r lint
# The declared `rust-version` is a promise to anyone depending on these crates, and nothing
# was checking it. It said 1.80 — set in 2024 when `LazyLock` landed and never revisited —
# and usage-argv had not built at 1.80 for a long time. A promise nobody checks is a guess.
#
# Two floors, because the crates genuinely differ: usage-argv, usage-derive, usage-config and
# usage-validation take no dependency on KDL and hold mise's own 1.91, which is the floor that
# matters for the fleet. usage-lib and everything that reads a spec through it need 1.95,
# because `kdl` says so. Each crate is checked at the version *it* declares rather than at one
# shared guess, which is how a lower floor stays real instead of aspirational.
#
# `cargo check` rather than `cargo test`: dev-dependencies are not part of what an adopter
# compiles, and holding them to the MSRV would pin the toolchain past what the library needs.
msrv:
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
strategy:
fail-fast: false
matrix:
include:
- version: "1.91"
crates: usage-argv usage-derive usage-config usage-validation usage-rs usage-test
- version: "1.95"
crates: usage-lib clap_usage usage-cli
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
submodules: recursive
persist-credentials: false
- name: the matrix and the manifests agree
run: |
# Both directions, because one of them alone is how a false floor survives.
#
# Every crate this row checks declares this row's version. Or the job checks a version
# nobody promised: a crate that raises its floor without touching this file would
# otherwise be tested at the old one and pass.
for crate in ${{ matrix.crates }}; do
manifest="$(git ls-files '*Cargo.toml' | xargs grep -l "^name = \"$crate\"$" | head -1)"
declared="$(sed -n 's/^rust-version *= *"\(.*\)".*/\1/p' "$manifest" | head -1)"
if [ "$declared" != "${{ matrix.version }}" ]; then
echo "::error::$crate declares $declared, checked here at ${{ matrix.version }}"
exit 1
fi
done
# And every published crate declaring this row's version is in this row. Without this
# half, a new crate — or one that was simply never listed — makes a floor promise that
# no toolchain ever tries. `usage-conformance` and `xtask` promised 1.91 for as long as
# this job existed while depending on a crate that needs 1.95; nothing noticed, because
# nothing looked from the manifests back to the matrix.
#
# Published only: a floor is a promise to whoever depends on the crate, so a
# `publish = false` member has nobody to make one to and should not declare one.
for manifest in $(git ls-files '*Cargo.toml'); do
declared="$(sed -n 's/^rust-version *= *"\(.*\)".*/\1/p' "$manifest" | head -1)"
[ "$declared" = "${{ matrix.version }}" ] || continue
grep -q '^publish *= *false' "$manifest" && continue
name="$(sed -n 's/^name *= *"\(.*\)".*/\1/p' "$manifest" | head -1)"
case " ${{ matrix.crates }} " in
*" $name "*) ;;
*)
echo "::error::$name declares $declared and is published, but no row checks it"
exit 1
;;
esac
done
# `rustup` rather than an action: it is already on the runner, and this needs one
# toolchain and no other behaviour — a pinned third-party action would be one more
# thing to keep current for no gain.
- name: install the toolchain under test
run: rustup toolchain install ${{ matrix.version }} --profile minimal
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
shared-key: msrv-${{ matrix.version }}
- name: they build at the version they claim
run: |
for crate in ${{ matrix.crates }}; do
cargo +${{ matrix.version }} check --locked -p "$crate" --all-features
done