garbage-code-hunter 0.2.0

A humorous Rust code quality detector that roasts your garbage code
Documentation
name: Release

on:
  push:
    tags:
      - 'v*'
    branches:
      - 'master'  # Trigger on master branch push
  workflow_dispatch:  # Allow manual trigger

env:
  CARGO_TERM_COLOR: always

permissions:
  contents: write

jobs:
  # Job 1: Run full CI pipeline first (only on tags)
  ci:
    name: Run CI Pipeline
    if: startsWith(github.ref, 'refs/tags/v')
    uses: ./.github/workflows/ci.yml
    secrets: inherit

  # Job 1b: Run CI pipeline for master branch push
  ci-master:
    name: Run CI Pipeline (Master)
    if: github.ref == 'refs/heads/master'
    uses: ./.github/workflows/ci.yml
    secrets: inherit

  # Job 1c: Run CI pipeline for manual trigger
  ci-manual:
    name: Run CI Pipeline (Manual)
    if: github.event_name == 'workflow_dispatch'
    uses: ./.github/workflows/ci.yml
    secrets: inherit

  # Job 2: Create GitHub Release (only on tags)
  create-release:
    name: Create Release
    runs-on: ubuntu-latest
    needs: ci
    if: startsWith(github.ref, 'refs/tags/v')
    outputs:
      upload_url: ${{ steps.create_release.outputs.upload_url }}
      release_id: ${{ steps.create_release.outputs.id }}
    steps:
      - uses: actions/checkout@v4

  # Job 2b: Create GitHub Release (master branch)
  create-release-master:
    name: Create Release (Master)
    runs-on: ubuntu-latest
    needs: ci-master
    if: github.ref == 'refs/heads/master'
    outputs:
      upload_url: ${{ steps.create_release.outputs.upload_url }}
      release_id: ${{ steps.create_release.outputs.id }}
      tag_name: ${{ steps.tag_version.outputs.tag }}
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Create and push tag
        id: tag_version
        run: |
          if [ -f RELEASE_NOTE.md ]; then
            TAG=$(head -1 RELEASE_NOTE.md | grep -oP 'v[\d.]+' | head -1)
            echo "🏷️ Found version in RELEASE_NOTE.md: $TAG"
          else
            TAG="v0.3.$(date +%Y%m%d%H%M)"
            echo "⚠️ No RELEASE_NOTE.md, using fallback: $TAG"
          fi

          echo "🔧 Configuring git..."
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"

          echo "🏷️ Creating local tag: $TAG"
          git tag -f "$TAG"

          REMOTE_URL=$(git remote get-url origin)
          echo "📡 Remote URL: $REMOTE_URL"

          echo "🚀 Pushing tag to remote..."
          git push origin "$TAG" --force

          VERIFY_TAG=$(git ls-remote --tags origin "$TAG" | head -1)
          echo "✅ Tag verified on remote: $VERIFY_TAG"

          echo "tag=$TAG" >> $GITHUB_OUTPUT

      - name: Read RELEASE_NOTE.md
        id: release_notes
        run: |
          echo "📋 Looking for RELEASE_NOTE.md..."
          if [ -f RELEASE_NOTE.md ]; then
            echo "✅ Found RELEASE_NOTE.md"
            NOTES=$(cat RELEASE_NOTE.md)
            NOTES="${NOTES//'%'/'%25'}"
            NOTES="${NOTES//$'\n'/'%0A'}"
            NOTES="${NOTES//$'\r'/'%0D'}"
            echo "notes=$NOTES" >> $GITHUB_OUTPUT
          else
            echo "⚠️ No RELEASE_NOTE.md found, using default message"
            echo "notes=Release ${{ steps.tag_version.outputs.tag }}" >> $GITHUB_OUTPUT
          fi

      - name: Create Release
        id: create_release
        uses: softprops/action-gh-release@v1
        with:
          tag_name: ${{ steps.tag_version.outputs.tag }}
          name: "Release ${{ steps.tag_version.outputs.tag }}"
          body: ${{ steps.release_notes.outputs.notes }}
          draft: false
          prerelease: false
          generate_release_notes: false

  # Job 3: Build and upload release binaries (Linux + Mac only)
  build-release:
    name: Build Release Binary (${{ matrix.os }})
    runs-on: ${{ matrix.os }}
    needs: create-release
    if: startsWith(github.ref, 'refs/tags/v')
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-latest
            asset_name: garbage-code-hunter-linux-x86_64.tar.gz
          - os: macos-latest
            asset_name: garbage-code-hunter-macos-x86_64.tar.gz

    steps:
      - uses: actions/checkout@v4

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable

      - name: Cache cargo registry
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-release-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: ${{ runner.os }}-cargo-release-

      - name: Build release binary
        run: cargo build --release

      - name: Show binary info
        run: |
          BINARY="target/release/garbage-code-hunter"
          if [ -f "$BINARY" ] || [ -f "${BINARY}.exe" ]; then
            echo "📦 Binary built successfully:"
            ls -lh target/release/garbage-code-hunter* 2>/dev/null || true
            file target/release/garbage-code-hunter* 2>/dev/null || true
          else
            echo "❌ Binary not found at $BINARY"
            exit 1
          fi

      - name: Package binary
        run: |
          cd target/release

          ASSET="${{ matrix.asset_name }}"
          tar -czf "$ASSET" garbage-code-hunter

          echo "📦 Package created:"
          ls -lh "$ASSET"

          echo "ASSET_PATH=target/release/$ASSET" >> $GITHUB_ENV
          echo "ASSET_NAME=$ASSET" >> $GITHUB_ENV

      - name: Upload Release Asset
        uses: softprops/action-gh-release@v1
        if: success()
        with:
          files: ${{ env.ASSET_PATH }}
          tag_name: ${{ needs.create-release-master.outputs.tag_name }}

  # Job 3b: Build and upload release binaries (master branch)
  build-release-master:
    name: Build Release Binary (${{ matrix.os }})
    runs-on: ${{ matrix.os }}
    needs: create-release-master
    if: github.ref == 'refs/heads/master'
    strategy:
      fail-fast: false
      matrix:
        include:
          # Linux x86_64
          - os: ubuntu-latest
            asset_name: garbage-code-hunter-linux-x86_64.tar.gz
          # macOS x86_64
          - os: macos-latest

          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-release-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: ${{ runner.os }}-cargo-release-

      - name: Build release binary
        run: cargo build --release

      - name: Show binary info
        run: |
          BINARY="target/release/garbage-code-hunter"
          if [ -f "$BINARY" ] || [ -f "${BINARY}.exe" ]; then
            echo "📦 Binary built successfully:"
            ls -lh target/release/garbage-code-hunter* 2>/dev/null || true
            file target/release/garbage-code-hunter* 2>/dev/null || true
          else
            echo "❌ Binary not found at $BINARY"
            exit 1
          fi

      - name: Package binary
        run: |
          cd target/release

          ASSET="${{ matrix.asset_name }}"
          tar -czf "$ASSET" garbage-code-hunter

          echo "📦 Package created:"
          ls -lh "$ASSET"

          echo "ASSET_PATH=target/release/$ASSET" >> $GITHUB_ENV
          echo "ASSET_NAME=$ASSET" >> $GITHUB_ENV

      - name: Upload Release Asset
        uses: softprops/action-gh-release@v1
        if: success()
        with:
          files: ${{ env.ASSET_PATH }}
          tag_name: ${{ needs.create-release-master.outputs.tag_name }}

  # Job 4: Publish to crates.io (optional, manual trigger)
  publish-crate:
    name: Publish to crates.io
    runs-on: ubuntu-latest
    needs: create-release
    if: startsWith(github.ref, 'refs/tags/v') && contains(fromJSON('["publish", "all"]'), 'publish')
    steps:
      - uses: actions/checkout@v4

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable

      - name: Cache cargo registry
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-publish-${{ hashFiles('**/Cargo.lock') }}

      - name: Verify package
        run: cargo publish --dry-run --allow-dirty

      - name: Publish to crates.io
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
        run: cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }}

  # Final status check
  release-success:
    name: ✅ Release Status Summary
    runs-on: ubuntu-latest
    needs: [create-release, build-release]
    if: always() && startsWith(github.ref, 'refs/tags/v')
    steps:
      - name: Generate summary
        run: |
          echo "========================================="
          echo "🎉 Release Summary: ${{ github.ref_name }}"
          echo "========================================="
          echo ""
          echo "📅 Time: $(date '+%Y-%m-%d %H:%M:%S UTC')"
          echo "🏷️  Tag: ${{ github.ref }}"
          echo "🔗 Commit: ${{ github.sha }}"
          echo ""
          echo "Jobs Status:"
          echo "  📝 Create Release: ${{ needs.create-release.result }}"
          echo "  🔨 Build Binaries: ${{ needs.build-release.result }}"
          echo ""
          
          if [ "${{ needs.create-release.result }}" == "success" ] && \
             [ "${{ needs.build-release.result }}" == "success" ]; then
            echo "========================================="
            echo "✅ Release completed successfully!"
            echo "========================================="
            
            # List all uploaded assets
            echo ""
            echo "📦 Uploaded Assets:"
            echo "  • garbage-code-hunter-linux-x86_64.tar.gz"
            echo "  • garbage-code-hunter-macos-x86_64.tar.gz"
            exit 0
          else
            echo "========================================="
            echo "❌ Release failed!"
            echo "========================================="
            exit 1
          fi