name: Release
on:
workflow_run:
workflows: ["CI"]
types: [completed]
branches: [main]
workflow_dispatch:
inputs:
version:
description: 'Version to release (leave empty to use Cargo.toml version)'
required: false
type: string
env:
CARGO_TERM_COLOR: always
jobs:
check-version:
name: Check Version
runs-on: ubuntu-latest
if: |
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success')
outputs:
version: ${{ steps.get_version.outputs.version }}
version_num: ${{ steps.get_version.outputs.version_num }}
should_release: ${{ steps.check_release.outputs.should_release }}
steps:
- uses: actions/checkout@v4
- name: Get version from Cargo.toml
id: get_version
run: |
if [ -n "${{ inputs.version }}" ]; then
VERSION_NUM="${{ inputs.version }}"
else
VERSION_NUM=$(grep -m1 '^version = ' Cargo.toml | sed 's/.*"\(.*\)".*/\1/')
fi
echo "version=v${VERSION_NUM}" >> $GITHUB_OUTPUT
echo "version_num=${VERSION_NUM}" >> $GITHUB_OUTPUT
echo "Version: v${VERSION_NUM}"
- name: Check if release exists
id: check_release
env:
GH_TOKEN: ${{ github.token }}
run: |
VERSION=${{ steps.get_version.outputs.version }}
if gh release view "$VERSION" > /dev/null 2>&1; then
echo "Release $VERSION already exists, skipping"
echo "should_release=false" >> $GITHUB_OUTPUT
else
echo "Release $VERSION does not exist, proceeding"
echo "should_release=true" >> $GITHUB_OUTPUT
fi
create-release:
name: Create Release
needs: check-version
if: needs.check-version.outputs.should_release == 'true'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Create Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.check-version.outputs.version }}
name: Release ${{ needs.check-version.outputs.version }}
generate_release_notes: true
draft: false
prerelease: ${{ contains(needs.check-version.outputs.version, 'alpha') || contains(needs.check-version.outputs.version, 'beta') || contains(needs.check-version.outputs.version, 'rc') }}
publish-crates:
name: Publish to crates.io
needs: [check-version, create-release]
if: needs.check-version.outputs.should_release == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Publish library (unparser-shared)
run: cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }}
cleanup-old-releases:
name: Cleanup Old Releases
needs: [check-version, create-release]
if: needs.check-version.outputs.should_release == 'true'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Delete releases and tags beyond the 10 most recent
env:
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
shell: bash
run: |
set -euo pipefail
# Fetch up to 100 recent releases. Sort by creation time desc and
# take everything AFTER index 10 — keep 10 newest, delete the rest.
# --cleanup-tag removes the underlying git tag too, so the repo's
# release list AND tag list stay bounded. Aligns with CLAUDE.md's
# GitHub Actions 리소스 관리 정책 (reduce storage use).
mapfile -t OLD < <(
gh release list -R "$REPO" --limit 100 --json tagName,createdAt \
| jq -r 'sort_by(.createdAt) | reverse | .[10:] | .[].tagName'
)
if [ ${#OLD[@]} -eq 0 ]; then
echo "Nothing to clean up (<=10 releases exist)."
exit 0
fi
echo "Deleting ${#OLD[@]} old release(s):"
printf ' %s\n' "${OLD[@]}"
for tag in "${OLD[@]}"; do
# --cleanup-tag deletes the git tag alongside the release.
# --yes skips the interactive confirmation.
gh release delete "$tag" --yes --cleanup-tag -R "$REPO"
done