Release #48
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: 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 | |
| build-release: | |
| name: Build Release | |
| needs: check-version | |
| if: needs.check-version.outputs.should_release == 'true' | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| include: | |
| - os: ubuntu-latest | |
| target: x86_64-unknown-linux-gnu | |
| artifact_name: undoc | |
| archive_name: undoc-linux-x86_64 | |
| archive_ext: tar.gz | |
| - os: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| artifact_name: undoc.exe | |
| archive_name: undoc-windows-x86_64 | |
| archive_ext: zip | |
| - os: macos-latest | |
| target: x86_64-apple-darwin | |
| artifact_name: undoc | |
| archive_name: undoc-macos-x86_64 | |
| archive_ext: tar.gz | |
| - os: macos-latest | |
| target: aarch64-apple-darwin | |
| artifact_name: undoc | |
| archive_name: undoc-macos-aarch64 | |
| archive_ext: tar.gz | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - name: Build | |
| run: cargo build --release --target ${{ matrix.target }} -p undoc-cli | |
| - name: Create archive (Unix) | |
| if: matrix.archive_ext == 'tar.gz' | |
| run: | | |
| cd target/${{ matrix.target }}/release | |
| tar -czvf ${{ matrix.archive_name }}-${{ needs.check-version.outputs.version }}.tar.gz ${{ matrix.artifact_name }} | |
| - name: Create archive (Windows) | |
| if: matrix.archive_ext == 'zip' | |
| shell: pwsh | |
| run: | | |
| cd target/${{ matrix.target }}/release | |
| Compress-Archive -Path ${{ matrix.artifact_name }} -DestinationPath "${{ matrix.archive_name }}-${{ needs.check-version.outputs.version }}.zip" | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.archive_name }} | |
| path: target/${{ matrix.target }}/release/${{ matrix.archive_name }}-${{ needs.check-version.outputs.version }}.${{ matrix.archive_ext }} | |
| retention-days: 1 | |
| create-release: | |
| name: Create Release | |
| needs: [check-version, build-release] | |
| if: needs.check-version.outputs.should_release == 'true' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| - name: List artifacts | |
| run: find artifacts -type f | |
| - name: Create Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ needs.check-version.outputs.version }} | |
| name: Release ${{ needs.check-version.outputs.version }} | |
| files: | | |
| artifacts/**/* | |
| 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') }} | |
| - name: Delete artifacts after release | |
| uses: geekyeggo/delete-artifact@v5 | |
| with: | |
| name: | | |
| undoc-* | |
| 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 (undoc) | |
| run: cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }} | |
| continue-on-error: true | |
| - name: Wait for crates.io index update | |
| run: sleep 30 | |
| - name: Publish CLI (undoc-cli) | |
| run: cargo publish -p undoc-cli --token ${{ secrets.CARGO_REGISTRY_TOKEN }} | |
| continue-on-error: true | |
| cleanup-old-releases: | |
| name: Cleanup Old Releases | |
| # Run after the new release is published. We only need create-release | |
| # to have succeeded — cleanup is independent of crates.io publish. | |
| 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 |