Skip to content

docs(readme): document squeez's compression scope and architectural l… #103

docs(readme): document squeez's compression scope and architectural l…

docs(readme): document squeez's compression scope and architectural l… #103

Workflow file for this run

name: Auto Release on Merge to Main
on:
push:
branches: [main]
permissions:
contents: write
jobs:
tag-and-release:
# Recursion guards:
# 1. Subject-prefix match: the bot's own bump commits always begin with
# "chore(release): bump version to". Using startsWith here (not
# contains) means prose in PR bodies that mentions the phrase cannot
# trip the guard — only the actual commit subject can.
# 2. Fallback: match by the bot's author email.
if: |
!startsWith(github.event.head_commit.message, 'chore(release): bump version to') &&
github.event.head_commit.author.email != 'github-actions[bot]@users.noreply.github.com'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
# PAT (fine-grained w/ Contents: read+write or classic w/ `repo` scope)
# lets the bump commit bypass branch protection AND ensures the pushed
# tag triggers release.yml (GITHUB_TOKEN-pushed tags do not).
token: ${{ secrets.RELEASE_PAT }}
- uses: dtolnay/rust-toolchain@stable
- name: Determine bump type from conventional commits
id: bump
run: |
set -e
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [ -z "$LAST_TAG" ]; then
RANGE="HEAD"
else
RANGE="${LAST_TAG}..HEAD"
fi
# SUBJECTS = one subject line per non-merge commit (first line only).
# BODIES = full bodies, used strictly for the `BREAKING CHANGE:`
# trailer match (must be line-start + colon).
SUBJECTS=$(git log "$RANGE" --format='%s' --no-merges)
BODIES=$(git log "$RANGE" --format='%b' --no-merges)
if [ -z "$SUBJECTS" ]; then
echo "No commits since $LAST_TAG."
echo "type=none" >> "$GITHUB_OUTPUT"
exit 0
fi
# Type detection. `BREAKING CHANGE:` trailer is checked at line
# start with a required colon — avoids matching prose like
# "- BREAKING CHANGE or !: -> major" inside a body.
# Header prefixes are matched against SUBJECTS only, so a body
# containing "feat: xyz" as documentation does not trigger a bump.
if echo "$SUBJECTS" | grep -qE '^[a-zA-Z]+(\([^)]*\))?!:' \
|| echo "$BODIES" | grep -qE '^BREAKING CHANGE:'; then
TYPE=major
elif echo "$SUBJECTS" | grep -qE '^feat(\([^)]*\))?:'; then
TYPE=minor
elif echo "$SUBJECTS" | grep -qE '^(fix|perf)(\([^)]*\))?:'; then
TYPE=patch
else
echo "Only chore/docs/ci/test/refactor commits — no release."
TYPE=none
fi
echo "type=$TYPE" >> "$GITHUB_OUTPUT"
echo "Detected bump: $TYPE (since ${LAST_TAG:-<initial>})"
- name: Compute next version
if: steps.bump.outputs.type != 'none'
id: version
run: |
set -e
CUR=$(grep -E '^version\s*=' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
IFS='.' read -r MA MI PA <<< "$CUR"
case "${{ steps.bump.outputs.type }}" in
major) MA=$((MA+1)); MI=0; PA=0 ;;
minor) MI=$((MI+1)); PA=0 ;;
patch) PA=$((PA+1)) ;;
esac
NEW="${MA}.${MI}.${PA}"
echo "current=$CUR" >> "$GITHUB_OUTPUT"
echo "next=$NEW" >> "$GITHUB_OUTPUT"
echo "Bumping $CUR -> $NEW"
- name: Fail fast if tag already exists
if: steps.bump.outputs.type != 'none'
run: |
# Check both the local and remote tag namespaces. A tag may exist
# locally but not remotely (e.g. a failed push from a prior run),
# so we also consult origin explicitly.
if git rev-parse "v${{ steps.version.outputs.next }}" >/dev/null 2>&1 \
|| git ls-remote --tags origin "v${{ steps.version.outputs.next }}" | grep -q "v${{ steps.version.outputs.next }}"; then
echo "Tag v${{ steps.version.outputs.next }} already exists — manual intervention needed."
exit 1
fi
- name: Bump Cargo.toml
if: steps.bump.outputs.type != 'none'
run: |
sed -i.bak -E "s/^version = \".*\"/version = \"${{ steps.version.outputs.next }}\"/" Cargo.toml
rm Cargo.toml.bak
grep -E '^version\s*=' Cargo.toml | head -1
- name: Refresh Cargo.lock
if: steps.bump.outputs.type != 'none'
run: cargo check --quiet
- name: Commit, tag, push
if: steps.bump.outputs.type != 'none'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add Cargo.toml Cargo.lock
# Using the namespaced [squeez-release-bot] marker so the recursion
# guard cannot be tripped by prose in user commit messages.
git commit -m "chore(release): bump version to ${{ steps.version.outputs.next }} [squeez-release-bot]"
# Annotated tag so `git push --tags` propagates it (lightweight tags
# are not pushed by `--follow-tags`, which silently broke the prior
# release pipeline when v1.0.0 was cut but never published).
git tag -a "v${{ steps.version.outputs.next }}" -m "Release v${{ steps.version.outputs.next }}"
git push origin main
git push origin "v${{ steps.version.outputs.next }}"
echo "Released v${{ steps.version.outputs.next }} — release.yml will take it from here."