Skip to content

docs(admin): document account exit codes; ci: narrow the protected-files marker #827

docs(admin): document account exit codes; ci: narrow the protected-files marker

docs(admin): document account exit codes; ci: narrow the protected-files marker #827

Workflow file for this run

name: CI
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
permissions:
contents: read
jobs:
advisories:
name: Dependency Advisories
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- uses: EmbarkStudios/cargo-deny-action@bb137d7af7e4fb67e5f82a49c4fce4fad40782fe # v2
with:
command: check advisories
fmt:
name: Format Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable
with:
components: rustfmt
- name: Check formatting
run: cargo fmt --all --check
clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable
with:
components: clippy
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
- name: Run Clippy
run: cargo clippy --workspace --all-targets -- -D warnings
test:
name: Test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, macos-latest, windows-latest ]
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
- name: Run tests
# Don't use --all-features as integration/golden require external services
# See integration.yml for those tests
run: cargo test --workspace
build:
name: Build (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, macos-latest, windows-latest ]
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
- name: Build
run: cargo build --workspace --release
doc:
name: Documentation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
- name: Build documentation
run: cargo doc --workspace --no-deps
env:
RUSTDOCFLAGS: -D warnings
# Ensure protected files are not modified without proper process
protected-files:
name: Protected Files Check
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
fetch-depth: 0
- name: Check protected files
env:
PR_BODY: ${{ github.event.pull_request.body }}
run: |
# Any change to these needs the marker: a new exit code, a new config
# field or a new schema property extends a contract even when nothing
# existing moves.
PROTECTED_FILES=(
"schemas/output_v1.json"
"crates/cli/src/exit_code.rs"
"crates/core/src/config.rs"
)
# The command reference is a contract too, but adding a section to it
# is how a new command gets documented — required by AGENTS.md § 3 of
# the Breaking Change process, in fact. Demanding the marker for that
# makes every additive PR claim to be breaking, so these paths need it
# only when existing lines move: a rewritten sentence, a removed flag,
# a deleted or renamed page.
ADDITIVE_OK_FILES=(
"docs/reference/rc/"
)
BASE="origin/${{ github.base_ref }}"
CHANGED_FILES=$(git diff --name-only "$BASE"...HEAD)
# Paths under a protected prefix, one per line.
matched_paths() {
local protected_path="${1%/}"
printf '%s\n' "$CHANGED_FILES" \
| grep -E "^$(printf '%s' "$protected_path" | sed 's/[.[\*^$]/\\&/g')(/|$)" || true
}
require_marker() {
local subject="$1"
echo "::warning::Protected file modified: $subject"
echo "This change requires the Breaking Change process. See AGENTS.md."
if ! grep -q "BREAKING" <<< "$PR_BODY"; then
echo "::error::Protected file $subject modified without BREAKING marker in PR description"
return 1
fi
}
status=0
for file in "${PROTECTED_FILES[@]}"; do
if [ -n "$(matched_paths "$file")" ]; then
require_marker "$file" || status=1
fi
done
for file in "${ADDITIVE_OK_FILES[@]}"; do
paths=$(matched_paths "$file")
[ -n "$paths" ] || continue
# Rename detection off on purpose: moving a reference page changes
# where readers and links land, so it should count as a rewrite
# rather than as a no-op.
removed=0
count=0
while IFS= read -r path; do
[ -n "$path" ] || continue
count=$((count + 1))
deleted=$(
git diff --numstat --no-renames "$BASE"...HEAD -- "$path" \
| awk '{ total += $2 } END { print total + 0 }'
)
removed=$((removed + deleted))
done <<< "$paths"
if [ "$removed" -gt 0 ]; then
require_marker "$file ($removed line(s) changed or removed)" || status=1
else
echo "$file changed by addition only ($count file(s)); no marker required"
fi
done
if [ "$status" -ne 0 ]; then
exit 1
fi
echo "Protected files check passed"
msrv:
name: Minimum Supported Rust Version
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- uses: dtolnay/rust-toolchain@fa04a1451ff1842e2626ccb99004d0195b455a88 # master
with:
toolchain: "1.92"
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
- name: Build with MSRV
run: cargo build --workspace