Release pipeline should skip binary builds for non-code changes
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 81.1k
- Forks
- 5.1k
- Avg merge
- 4d 21h
- Merged PRs (30d)
- 35
Description
Problem
The release pipeline currently triggers full multi-platform binary builds for every release, even when no Rust source code changed. This wastes CI resources and pollutes the release history with identical binaries.
Example: v0.20.1 (2026-02-17)
PR #161 (fix: install to ~/.local/bin) changed only install.sh + README.md — zero Rust code changes. Yet it triggered:
- 5 platform builds (macOS Intel/ARM, Linux Intel/ARM, Windows)
- DEB package build
- RPM package build
- Homebrew formula update
- Version bump in
Cargo.toml+Cargo.lock
The resulting binaries are functionally identical to v0.20.0 (only the embedded version string differs).
Impact
On Feb 17 alone, 4 releases were created (v0.19.0 → v0.21.1). At ~35 CI minutes per release (7 build jobs), that's over 2 hours of CI time. At least one release (v0.20.1) was entirely unnecessary.
Root Cause
release-please determines version bumps based on conventional commit prefixes only (fix: → patch, feat: → minor). It has no awareness of which files changed. So fix: install to ~/.local/bin triggers a patch release even though no compiled code was affected.
The build-release job in release-please.yml runs unconditionally whenever release_created == 'true':
build-release:
needs: release-please
if: ${{ needs.release-please.outputs.release_created == 'true' }}
uses: ./.github/workflows/release.yml
Proposed Solution
Add a source-code change detection step between release-please and the build job:
check-source-changes:
name: Check if source code changed
needs: release-please
if: ${{ needs.release-please.outputs.release_created == 'true' }}
runs-on: ubuntu-latest
outputs:
code_changed: ${{ steps.check.outputs.code_changed }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check for Rust source changes since last release
id: check
run: |
# Get the previous release tag
CURRENT_TAG="${{ needs.release-please.outputs.tag_name }}"
PREV_TAG=$(git tag --sort=-v:refname | grep -v "$CURRENT_TAG" | head -1)
# Check if any Rust source files changed
CHANGED=$(git diff --name-only "$PREV_TAG"..HEAD -- '*.rs' 'Cargo.toml' 'Cargo.lock' 'build.rs' | head -1)
if [ -n "$CHANGED" ]; then
echo "code_changed=true" >> $GITHUB_OUTPUT
echo "Source code changed since $PREV_TAG"
else
echo "code_changed=false" >> $GITHUB_OUTPUT
echo "No source code changes since $PREV_TAG — skipping binary build"
fi
build-release:
needs: [release-please, check-source-changes]
if: ${{ needs.check-source-changes.outputs.code_changed == 'true' }}
uses: ./.github/workflows/release.yml
This way:
- Code changes (
*.rs,Cargo.toml,build.rs) → full build + release artifacts - Non-code changes (README, install.sh, docs, CI config) → release-please still creates the version tag and changelog entry, but no binary build runs
Alternatives Considered
- Enforce commit prefix discipline (
chore:/docs:for non-code changes) — fragile, relies on contributor discipline - release-please path filtering — not natively supported in v4
- Separate release tracks (code vs docs) — over-engineered for this use case
Additional Improvement
Consider also gating the Homebrew formula update behind the same code_changed check, since there's no point updating the tap when binaries haven't changed.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read .github/workflows/release-please.yml and the reusable .github/workflows/release.yml, then trace the release-please outputs and the current build-release condition. Validate the workflow with a release containing Rust or Cargo changes and one changing only README.md or install.sh. Done means non-code releases keep their tag and changelog but skip binary builds, while code releases still build artifacts.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- github-actions, rust
- Domain
- build-system, ci-cd, release
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 55/100