docs(readme): document squeez's compression scope and architectural l… #103
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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." |