Release workflow (release/2025.10.2) #35
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 | |
| run-name: Release workflow (${{ github.ref_name }}) | |
| on: | |
| push: | |
| branches: | |
| - 'release/**' | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| packages: write | |
| pull-requests: write | |
| env: | |
| CARGO_TERM_COLOR: always | |
| RUST_BACKTRACE: 1 | |
| jobs: | |
| semantic-version: | |
| name: Compute Version | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ steps.semver.outputs.version }} | |
| version_tag: ${{ steps.semver.outputs.version_tag }} | |
| changed: ${{ steps.semver.outputs.changed }} | |
| changelog: ${{ steps.semver.outputs.changelog }} | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| - id: semver | |
| uses: PaulHatch/semantic-version@v5.4.0 | |
| with: | |
| tag_prefix: "v" | |
| major_pattern: "BREAKING CHANGE:" | |
| minor_pattern: "feat:" | |
| bump_each_commit: false | |
| search_commit_body: true | |
| user_format_type: "csv" | |
| enable_prerelease_mode: true | |
| - name: Fail if no semantic changes | |
| if: steps.semver.outputs.changed != 'true' | |
| run: | | |
| echo "No semantic changes since last tag. Skipping release." | |
| exit 1 | |
| test: | |
| name: Test & Lint | |
| runs-on: ubuntu-latest | |
| needs: semantic-version | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Format check | |
| run: cargo fmt --all -- --check | |
| - name: Clippy | |
| run: cargo clippy --all-targets --all-features -- -D warnings | |
| - name: Tests | |
| run: cargo test --all --locked | |
| update-version: | |
| name: Sync Cargo Version | |
| runs-on: ubuntu-latest | |
| needs: [semantic-version, test] | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| - name: Update Cargo.toml | |
| run: | | |
| sed -i.bak 's/^version = ".*"/version = "${{ needs.semantic-version.outputs.version }}"/' Cargo.toml && rm Cargo.toml.bak | |
| git config user.email "action@github.com" | |
| git config user.name "GitHub Action" | |
| git add Cargo.toml | |
| git commit -m "chore: sync version ${{ needs.semantic-version.outputs.version }}" || echo "No change" | |
| git push || true | |
| create-release: | |
| name: Create GitHub Release | |
| runs-on: ubuntu-latest | |
| needs: [semantic-version, test, update-version] | |
| outputs: | |
| upload_url: ${{ steps.rel.outputs.upload_url }} | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Configure git | |
| run: | | |
| git config user.email "action@github.com" | |
| git config user.name "GitHub Action" | |
| - name: Get previous tag | |
| id: previous-tag | |
| run: | | |
| git fetch --tags | |
| PREVIOUS_TAG=$(git tag --sort=-version:refname | head -2 | tail -1) | |
| echo "tag=${PREVIOUS_TAG:-$(git rev-list --max-parents=0 HEAD)}" >> $GITHUB_OUTPUT | |
| - name: Create tag | |
| run: | | |
| git fetch --tags | |
| if git rev-parse "v${{ needs.semantic-version.outputs.version }}" >/dev/null 2>&1; then | |
| echo "Tag already exists. Skipping." | |
| else | |
| git tag -a "v${{ needs.semantic-version.outputs.version }}" -m "Release ${{ needs.semantic-version.outputs.version }}" | |
| git push origin "v${{ needs.semantic-version.outputs.version }}" | |
| fi | |
| - name: Create Release | |
| id: rel | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ needs.semantic-version.outputs.version_tag }} | |
| name: Release ${{ needs.semantic-version.outputs.version }} | |
| generate_release_notes: true | |
| body: | | |
| ## What's Changed | |
| ${{ needs.semantic-version.outputs.changelog }} | |
| **Full Changelog**: https://github.com/${{ github.repository }}/compare/${{ steps.previous-tag.outputs.tag }}...v${{ needs.semantic-version.outputs.version }} | |
| build-matrix: | |
| name: Build Targets | |
| needs: [semantic-version, update-version] | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| include: | |
| - os: ubuntu-latest | |
| target: x86_64-unknown-linux-gnu | |
| - os: macos-latest | |
| target: x86_64-apple-darwin | |
| - os: macos-latest | |
| target: aarch64-apple-darwin | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| ref: ${{ github.ref_name }} | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| key: ${{ matrix.target }} | |
| - name: Build | |
| run: cargo build --release --target ${{ matrix.target }} | |
| - name: Strip (Linux) | |
| if: startsWith(matrix.target, 'x86_64-unknown-linux') | |
| run: strip target/${{ matrix.target }}/release/repos | |
| - name: Strip (macOS) | |
| if: contains(matrix.target, 'apple-darwin') | |
| run: strip -x target/${{ matrix.target }}/release/repos || true | |
| - name: Package | |
| run: | | |
| staging="repos-${{ needs.semantic-version.outputs.version }}-${{ matrix.target }}" | |
| mkdir "$staging" | |
| cp target/${{ matrix.target }}/release/repos "$staging/" | |
| tar czf "$staging.tar.gz" "$staging" | |
| echo "ASSET=$staging.tar.gz" >> $GITHUB_ENV | |
| - name: Upload Asset | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ needs.semantic-version.outputs.version_tag }} | |
| files: ${{ env.ASSET }} | |
| build-universal-macos: | |
| name: Universal macOS | |
| runs-on: macos-latest | |
| needs: [semantic-version, update-version, build-matrix] | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| ref: ${{ github.ref_name }} | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: x86_64-apple-darwin,aarch64-apple-darwin | |
| - uses: Swatinem/rust-cache@v2 | |
| - run: cargo build --release --target x86_64-apple-darwin | |
| - run: cargo build --release --target aarch64-apple-darwin | |
| - run: | | |
| lipo -create \ | |
| target/x86_64-apple-darwin/release/repos \ | |
| target/aarch64-apple-darwin/release/repos \ | |
| -output repos | |
| strip -x repos || true | |
| staging="repos-${{ needs.semantic-version.outputs.version }}-universal-apple-darwin" | |
| mkdir "$staging" | |
| mv repos "$staging/" | |
| tar czf "$staging.tar.gz" "$staging" | |
| echo "UNIVERSAL=$staging.tar.gz" >> $GITHUB_ENV | |
| - uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ needs.semantic-version.outputs.version_tag }} | |
| files: ${{ env.UNIVERSAL }} | |
| sync-main: | |
| name: Sync version back to main | |
| runs-on: ubuntu-latest | |
| needs: [semantic-version, create-release] | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| - name: Fast-forward main | |
| run: | | |
| RELEASE_BRANCH="${GITHUB_REF_NAME}" | |
| git fetch origin main | |
| git fetch origin "$RELEASE_BRANCH" | |
| git checkout main | |
| if git merge --ff-only "origin/$RELEASE_BRANCH"; then | |
| git config user.name "GitHub Action" | |
| git config user.email "action@github.com" | |
| git push origin main | |
| echo "FAST_FORWARD=1" >> $GITHUB_ENV | |
| else | |
| echo "FAST_FORWARD=0" >> $GITHUB_ENV | |
| fi | |
| - name: Create PR (non fast-forward) | |
| if: env.FAST_FORWARD == '0' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| gh pr create \ | |
| --base main \ | |
| --head "${GITHUB_REF_NAME}" \ | |
| --title "chore: sync version ${{ needs.semantic-version.outputs.version }}" \ | |
| --body "Automatic version sync after release v${{ needs.semantic-version.outputs.version }}." |