Release release/2026.02.1 #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: Release | |
| run-name: Release ${{ github.ref_name }} | |
| on: | |
| # Trigger when pushing to release branches | |
| push: | |
| branches: | |
| - 'release/**' | |
| # Allow manual triggering | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| env: | |
| CARGO_TERM_COLOR: always | |
| RUST_BACKTRACE: 1 | |
| jobs: | |
| # 1. Determine version first before any other jobs | |
| version: | |
| name: Determine Version | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ steps.set-version.outputs.version }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Determine Version | |
| id: semver | |
| uses: PaulHatch/semantic-version@v6.0.1 | |
| with: | |
| tag_prefix: "v" | |
| major_pattern: "BREAKING CHANGE:" | |
| minor_pattern: "feat:" | |
| version_format: "${major}.${minor}.${patch}" | |
| search_commit_body: true | |
| debug: true | |
| - name: Set VERSION output | |
| id: set-version | |
| run: | | |
| VERSION="${{ steps.semver.outputs.version }}" | |
| echo "Calculated semantic version: $VERSION" | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| # 2. Run tests and linting as a quality gate. | |
| test: | |
| name: Test & Lint | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - 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: Run tests | |
| run: cargo test --all --locked | |
| # 3. Build all required binaries with the correct version. | |
| # This job runs only after tests have passed and version is determined. | |
| build: | |
| name: Build Binaries | |
| needs: [version, test] | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| include: | |
| - os: ubuntu-latest | |
| target: x86_64-unknown-linux-gnu | |
| asset_name_suffix: linux-x86_64 | |
| - os: macos-latest | |
| target: x86_64-apple-darwin | |
| asset_name_suffix: macos-x86_64 | |
| - os: macos-latest | |
| target: aarch64-apple-darwin | |
| asset_name_suffix: macos-arm64 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| key: ${{ matrix.target }} | |
| - name: Update Cargo.toml version before build | |
| run: | | |
| VERSION="${{ needs.version.outputs.version }}" | |
| echo "Building with version: $VERSION" | |
| # Update version in main Cargo.toml | |
| if [[ "$OSTYPE" == "darwin"* ]]; then | |
| sed -i '' "s/^version = \".*\"/version = \"$VERSION\"/" Cargo.toml | |
| else | |
| sed -i "s/^version = \".*\"/version = \"$VERSION\"/" Cargo.toml | |
| fi | |
| - name: Build main binary and plugins | |
| run: cargo build --release --target ${{ matrix.target }} --workspace | |
| - name: Strip binaries for size | |
| run: | | |
| if [[ "${{ runner.os }}" == "Linux" ]]; then | |
| strip target/${{ matrix.target }}/release/repos | |
| strip target/${{ matrix.target }}/release/repos-health | |
| strip target/${{ matrix.target }}/release/repos-review | |
| strip target/${{ matrix.target }}/release/repos-fix | |
| else | |
| strip -x target/${{ matrix.target }}/release/repos | |
| strip -x target/${{ matrix.target }}/release/repos-health | |
| strip -x target/${{ matrix.target }}/release/repos-review | |
| strip -x target/${{ matrix.target }}/release/repos-fix | |
| fi | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: build-artifacts-${{ matrix.asset_name_suffix }} | |
| path: | | |
| target/${{ matrix.target }}/release/repos | |
| target/${{ matrix.target }}/release/repos-health | |
| target/${{ matrix.target }}/release/repos-validate | |
| target/${{ matrix.target }}/release/repos-review | |
| target/${{ matrix.target }}/release/repos-fix | |
| # 4. Create the universal macOS binary from the previously built artifacts. | |
| # This job is very fast as it does not re-compile anything. | |
| package-universal: | |
| name: Package Universal macOS | |
| needs: [version, build] | |
| runs-on: macos-latest | |
| steps: | |
| - name: Download macOS arm64 artifacts | |
| uses: actions/download-artifact@v7 | |
| with: | |
| name: build-artifacts-macos-arm64 | |
| path: arm64 | |
| - name: Download macOS x86_64 artifacts | |
| uses: actions/download-artifact@v7 | |
| with: | |
| name: build-artifacts-macos-x86_64 | |
| path: x86_64 | |
| - name: Create universal binaries | |
| run: | | |
| lipo -create -output repos arm64/repos x86_64/repos | |
| lipo -create -output repos-health arm64/repos-health x86_64/repos-health | |
| lipo -create -output repos-validate arm64/repos-validate x86_64/repos-validate | |
| lipo -create -output repos-review arm64/repos-review x86_64/repos-review | |
| lipo -create -output repos-fix arm64/repos-fix x86_64/repos-fix | |
| strip -x repos repos-health repos-validate repos-review repos-fix | |
| - name: Upload universal artifact | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: build-artifacts-macos-universal | |
| path: | | |
| repos | |
| repos-health | |
| repos-validate | |
| repos-review | |
| repos-fix | |
| # 5. Create the GitHub Release and upload all artifacts. | |
| # This is the final publishing step. | |
| publish: | |
| name: Publish Release | |
| needs: [version, build, package-universal] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set VERSION from version job | |
| run: | | |
| VERSION="${{ needs.version.outputs.version }}" | |
| echo "Publishing version: $VERSION" | |
| echo "VERSION=$VERSION" >> $GITHUB_ENV | |
| - name: Download all build artifacts | |
| uses: actions/download-artifact@v7 | |
| with: | |
| path: dist | |
| - name: Package artifacts for release | |
| id: package | |
| run: | | |
| VERSION=${{ env.VERSION }} | |
| # Package platform-specific artifacts (excludes universal which is handled separately) | |
| for dir in dist/build-artifacts-linux-* dist/build-artifacts-macos-x86_64 dist/build-artifacts-macos-arm64; do | |
| if [ -d "$dir" ]; then | |
| suffix=$(basename "$dir" | sed 's/build-artifacts-//') | |
| tar -czf "repos-${VERSION}-${suffix}.tar.gz" -C "$dir" repos | |
| tar -czf "repos-health-${VERSION}-${suffix}.tar.gz" -C "$dir" repos-health | |
| tar -czf "repos-validate-${VERSION}-${suffix}.tar.gz" -C "$dir" repos-validate | |
| tar -czf "repos-review-${VERSION}-${suffix}.tar.gz" -C "$dir" repos-review | |
| tar -czf "repos-fix-${VERSION}-${suffix}.tar.gz" -C "$dir" repos-fix | |
| fi | |
| done | |
| # Package universal macOS artifacts separately | |
| if [ -d "dist/build-artifacts-macos-universal" ]; then | |
| tar -czf "repos-${VERSION}-macos-universal.tar.gz" -C "dist/build-artifacts-macos-universal" repos | |
| tar -czf "repos-health-${VERSION}-macos-universal.tar.gz" -C "dist/build-artifacts-macos-universal" repos-health | |
| tar -czf "repos-validate-${VERSION}-macos-universal.tar.gz" -C "dist/build-artifacts-macos-universal" repos-validate | |
| tar -czf "repos-review-${VERSION}-macos-universal.tar.gz" -C "dist/build-artifacts-macos-universal" repos-review | |
| tar -czf "repos-fix-${VERSION}-macos-universal.tar.gz" -C "dist/build-artifacts-macos-universal" repos-fix | |
| fi | |
| # List final assets | |
| ls -lh *.tar.gz | |
| # Create space-separated list of all archives for upload | |
| ASSETS=$(ls *.tar.gz | tr '\n' ' ') | |
| echo "ASSETS<<EOF" >> $GITHUB_ENV | |
| echo "$ASSETS" >> $GITHUB_ENV | |
| echo "EOF" >> $GITHUB_ENV | |
| - name: Create GitHub Release and Upload Assets | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| token: ${{ secrets.PAT_TOKEN }} | |
| tag_name: v${{ env.VERSION }} | |
| name: Release v${{ env.VERSION }} | |
| generate_release_notes: true | |
| draft: true | |
| files: | | |
| *.tar.gz | |
| # 6. After a successful release, create a PR to bump version in main | |
| sync-main: | |
| name: Sync Back to Main | |
| needs: [version, publish] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.PAT_TOKEN }} # Use PAT for creating PR | |
| - name: Configure Git | |
| run: | | |
| git config user.name "GitHub Action" | |
| git config user.email "action@github.com" | |
| - name: Create version bump branch from main | |
| id: versioning | |
| run: | | |
| RELEASE_VERSION=${{ needs.version.outputs.version }} | |
| # Calculate next version (e.g., 0.2.1 -> 0.3.0-rc) | |
| MAJOR=$(echo "$RELEASE_VERSION" | cut -d. -f1) | |
| MINOR=$(echo "$RELEASE_VERSION" | cut -d. -f2) | |
| NEXT_MINOR=$((MINOR + 1)) | |
| NEXT_VERSION="${MAJOR}.${NEXT_MINOR}.0-rc" | |
| echo "NEXT_VERSION=${NEXT_VERSION}" >> $GITHUB_ENV | |
| BUMP_BRANCH="chore/version-bump-${NEXT_VERSION}" | |
| echo "BUMP_BRANCH=${BUMP_BRANCH}" >> $GITHUB_ENV | |
| # Create the new branch from the main branch | |
| git fetch origin main | |
| git checkout -b "$BUMP_BRANCH" origin/main | |
| - name: Update Cargo.toml and push branch | |
| run: | | |
| # Update version in Cargo.toml | |
| sed -i "s/^version = \".*\"/version = \"${{ env.NEXT_VERSION }}\"/" Cargo.toml | |
| # Commit changes | |
| git add Cargo.toml | |
| if git diff --cached --quiet; then | |
| echo "No changes to commit" | |
| else | |
| git commit -m "chore: bump version to ${{ env.NEXT_VERSION }}" | |
| fi | |
| # Delete remote branch if exists, then force push | |
| git push origin --delete "${{ env.BUMP_BRANCH }}" 2>/dev/null || true | |
| git push origin "${{ env.BUMP_BRANCH }}" | |
| - name: Create Pull Request | |
| env: | |
| GH_TOKEN: ${{ secrets.PAT_TOKEN }} | |
| run: | | |
| # Check if there are commits to PR | |
| git fetch origin main | |
| COMMITS_AHEAD=$(git rev-list --count origin/main.."${{ env.BUMP_BRANCH }}") | |
| if [ "$COMMITS_AHEAD" -eq "0" ]; then | |
| echo "No commits to create PR for - branch is up to date with main" | |
| exit 0 | |
| fi | |
| # Check if PR already exists | |
| EXISTING_PR=$(gh pr list --head "${{ env.BUMP_BRANCH }}" --base main --json number --jq '.[0].number' 2>/dev/null || echo "") | |
| if [ -n "$EXISTING_PR" ]; then | |
| echo "PR #$EXISTING_PR already exists, skipping creation" | |
| else | |
| gh pr create \ | |
| --base main \ | |
| --head "${{ env.BUMP_BRANCH }}" \ | |
| --title "chore: Post-release version bump to ${{ env.NEXT_VERSION }}" \ | |
| --body "This PR merges the changes from release \`${{ github.ref_name }}\` back into main and prepares for the next development cycle by bumping the version to \`${{ env.NEXT_VERSION }}\`." | |
| fi |