From fe9c00a9a5c4f7615d9372d3f505f99dccf59219 Mon Sep 17 00:00:00 2001 From: Jeongkyu Shin Date: Sat, 15 Aug 2026 00:35:05 +0900 Subject: [PATCH] chore: skip CI Rust build on non-Rust-only changes `.github/workflows/ci.yml` had no path filter on either trigger, so every pull request ran the full Rust toolchain even when the diff contained no Rust. Both jobs are pure Rust (`cargo fmt`, `cargo clippy`, `cargo test`, and `cargo check --workspace` on the declared MSRV), so on a documentation-only or release-YAML-only PR they compiled the entire tree to prove nothing. PR #264 is the motivating case: it changed only `release.yml`, two composite actions, and `ARCHITECTURE.md`, and the `ci` job was still pending roughly ten minutes later, at which point the PR was merged without it. A check that cannot say anything about the diff still gates attention, and in practice gets ignored, which erodes the signal for the PRs where it does matter. Add a `paths-ignore` blocklist to both the `push` and `pull_request` triggers. A blocklist rather than a `paths` allowlist: an allowlist fails unsafe, because a new crate or workspace member nobody remembered to add would silently stop being built, while a blocklist fails safe, because anything unrecognized still runs the full build and the worst case is a wasted run rather than an unvalidated merge. Both triggers get the same list so the merge commit on `main` does not run the very build its PR had just skipped. GitHub Actions has no YAML anchors, so the list is duplicated with a comment saying to keep the copies in sync. Every entry was verified against the current tree rather than assumed: no file in the workspace uses `include_str!`, `include_bytes!`, or `#[doc = include_str!(...)]`, so no Markdown or `docs/` asset reaches the compiler, and no Rust source reads `docs/`, `LICENSE`, or `NOTICE` at test time. `debian_build.yml` and `launchpad_ppa.yml` trigger only on `workflow_run` and `workflow_dispatch`, so they never had PR-time coverage from this workflow to lose. `debian/**`, `.githooks/**`, and `tools/**` were deliberately left off the list, keeping the blocklist to paths that both change often and are provably inert. `ci.yml` itself is deliberately absent from the list, so a change to the CI definition still validates itself; the sibling workflows are enumerated one by one for the same reason, so a workflow added later is not ignored by default. The header comment records the branch-protection constraint: `main` has no protection today (`gh api repos/lablup/bssh/branches/main/protection` returns 404), so neither job is a required status check, but GitHub does not treat "not run" as "passed", so enabling required checks later means migrating to an always-reporting gate job or to per-step `if:` conditions first. Validated by parsing the workflow with `yaml.safe_load` and by replaying the ignore globs over all 428 tracked files: no `.rs`, `.toml`, `.lock`, or `ci.yml` path matches the filter, every pattern matches something that actually exists, and scenario checks confirm doc-only and release-YAML-only diffs skip while Rust sources, manifests, `benches/`, `tests/`, `crates/`, unlisted new workflows, and mixed diffs all still run both jobs. Refs #265 --- .github/workflows/ci.yml | 59 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dbd1b729..e5cbcd04 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,10 +1,69 @@ name: CI +# Both jobs below are pure Rust (`cargo fmt`, `cargo clippy`, `cargo test`, +# `cargo check --workspace`). They can say nothing useful about a diff that +# contains no Rust, so the paths below skip the workflow entirely for those. +# +# The list is a blocklist (`paths-ignore`), never an allowlist (`paths`). +# An allowlist fails unsafe: a new crate, workspace member, or build script +# that nobody remembered to add would silently stop being built. A blocklist +# fails safe: anything unrecognized still runs the full build, and the worst +# case is a wasted run rather than an unvalidated merge. +# +# Two rules for anyone editing this list: +# +# 1. `.github/workflows/ci.yml` must never appear below. A change to the CI +# definition has to validate itself, otherwise a broken edit merges green +# because the workflow declined to run on its own change. The sibling +# workflows are listed individually for the same reason: a new workflow +# added later is NOT ignored by default. +# 2. `'**.md'` is only safe while no Markdown is compiled into the binary. +# Nothing in the workspace uses `include_str!`, `include_bytes!`, or +# `#[doc = include_str!(...)]` today. If that changes, narrow this entry +# so the embedded file is no longer ignored. +# +# GitHub applies these per file across the whole diff: the workflow is skipped +# only when EVERY changed file matches. A PR touching a doc and a `.rs` file +# still runs both jobs. +# +# NOTE ON BRANCH PROTECTION: `main` currently has no branch protection, so +# neither `ci` nor `msrv` is a required status check and a skipped run blocks +# nothing. If required status checks are ever enabled, this workflow-level +# `paths-ignore` must be migrated first: GitHub does not treat "not run" as +# "passed", so a doc-only PR would sit un-mergeable forever. The migration is +# either an always-reporting gate job that carries the required-check name and +# depends on the conditional Rust jobs, or per-step `if:` conditions driven by +# a cheap path-detection job. See issue #265. +# +# The two lists below are duplicated on purpose: GitHub Actions does not +# support YAML anchors and aliases, so they cannot be shared. Keep them in +# sync. Filtering only `pull_request` would leave the merge commit running on +# `main` the very build its PR had just skipped. on: push: branches: [ main, develop ] + paths-ignore: + - '**.md' + - 'docs/**' + - 'LICENSE' + - 'NOTICE' + - '.github/actions/**' + - '.github/workflows/release.yml' + - '.github/workflows/update_homebrew_formula.yml' + - '.github/workflows/debian_build.yml' + - '.github/workflows/launchpad_ppa.yml' pull_request: branches: [ main ] + paths-ignore: + - '**.md' + - 'docs/**' + - 'LICENSE' + - 'NOTICE' + - '.github/actions/**' + - '.github/workflows/release.yml' + - '.github/workflows/update_homebrew_formula.yml' + - '.github/workflows/debian_build.yml' + - '.github/workflows/launchpad_ppa.yml' env: CARGO_TERM_COLOR: always