opencode-ralph-loop-cli 0.1.0

Scaffolder CLI for OpenCode Ralph Loop plugin — one command setup
Documentation
name: Release

on:
  push:
    tags:
      - "v*"

env:
  CARGO_TERM_COLOR: always
  RUST_BACKTRACE: 1
  BINARY_NAME: opencode-ralph-loop-cli

jobs:
  validate:
    name: Validate
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt, clippy
      - uses: Swatinem/rust-cache@v2
      - run: cargo fmt --all --check
      - run: cargo clippy --all-targets --all-features -- -D warnings
      - run: cargo test --all-features
      - run: RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --all-features
      - run: cargo publish --dry-run --allow-dirty

  build-matrix:
    name: Build (${{ matrix.target }})
    needs: validate
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - target: x86_64-unknown-linux-gnu
            os: ubuntu-latest
            archive: tar.gz
          - target: x86_64-unknown-linux-musl
            os: ubuntu-latest
            archive: tar.gz
          - target: aarch64-unknown-linux-gnu
            os: ubuntu-latest
            archive: tar.gz
            use_cross: true
          - target: x86_64-apple-darwin
            os: macos-latest
            archive: tar.gz
          - target: aarch64-apple-darwin
            os: macos-latest
            archive: tar.gz
          - target: x86_64-pc-windows-msvc
            os: windows-latest
            archive: zip

    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}
      - uses: Swatinem/rust-cache@v2
        with:
          key: ${{ matrix.target }}

      - name: Install musl-tools
        if: matrix.target == 'x86_64-unknown-linux-musl'
        run: sudo apt-get install -y musl-tools

      - name: Install cross
        if: matrix.use_cross
        run: cargo install cross --locked

      - name: Build with cross
        if: matrix.use_cross
        run: cross build --release --target ${{ matrix.target }}

      - name: Build
        if: "!matrix.use_cross"
        run: cargo build --release --target ${{ matrix.target }}

      - name: Package (Unix)
        if: matrix.archive == 'tar.gz'
        shell: bash
        run: |
          BINARY="target/${{ matrix.target }}/release/${{ env.BINARY_NAME }}"
          ARCHIVE="${{ env.BINARY_NAME }}-${{ matrix.target }}.tar.gz"
          tar -czf "$ARCHIVE" -C "$(dirname "$BINARY")" "$(basename "$BINARY")"
          sha256sum "$ARCHIVE" > "$ARCHIVE.sha256"
          echo "ARCHIVE=$ARCHIVE" >> "$GITHUB_ENV"

      - name: Package (Windows)
        if: matrix.archive == 'zip'
        shell: pwsh
        run: |
          $Binary = "target\${{ matrix.target }}\release\${{ env.BINARY_NAME }}.exe"
          $Archive = "${{ env.BINARY_NAME }}-${{ matrix.target }}.zip"
          Compress-Archive -Path $Binary -DestinationPath $Archive
          $Hash = (Get-FileHash $Archive -Algorithm SHA256).Hash.ToLower()
          "$Hash  $Archive" | Out-File -FilePath "$Archive.sha256" -Encoding utf8
          "ARCHIVE=$Archive" | Add-Content -Path $env:GITHUB_ENV

      - uses: actions/upload-artifact@v4
        with:
          name: binary-${{ matrix.target }}
          path: |
            ${{ env.ARCHIVE }}
            ${{ env.ARCHIVE }}.sha256

  macos-universal:
    name: macOS Universal Binary
    needs: build-matrix
    runs-on: macos-latest
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: binary-x86_64-apple-darwin
          path: dist/x86_64
      - uses: actions/download-artifact@v4
        with:
          name: binary-aarch64-apple-darwin
          path: dist/aarch64

      - name: Create universal binary
        run: |
          tar -xzf "dist/x86_64/${{ env.BINARY_NAME }}-x86_64-apple-darwin.tar.gz" -C dist/x86_64
          tar -xzf "dist/aarch64/${{ env.BINARY_NAME }}-aarch64-apple-darwin.tar.gz" -C dist/aarch64
          lipo -create \
            "dist/x86_64/${{ env.BINARY_NAME }}" \
            "dist/aarch64/${{ env.BINARY_NAME }}" \
            -output "${{ env.BINARY_NAME }}-universal"
          ARCHIVE="${{ env.BINARY_NAME }}-universal-apple-darwin.tar.gz"
          tar -czf "$ARCHIVE" "${{ env.BINARY_NAME }}-universal"
          shasum -a 256 "$ARCHIVE" > "$ARCHIVE.sha256"
          echo "ARCHIVE=$ARCHIVE" >> "$GITHUB_ENV"

      - uses: actions/upload-artifact@v4
        with:
          name: binary-universal-apple-darwin
          path: |
            ${{ env.ARCHIVE }}
            ${{ env.ARCHIVE }}.sha256

  publish-github-release:
    name: GitHub Release
    needs: macos-universal
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@v4
      - uses: actions/download-artifact@v4
        with:
          pattern: binary-*
          path: dist
          merge-multiple: true

      - name: Generate SHA256SUMS
        run: |
          cd dist
          cat *.sha256 > SHA256SUMS.txt

      - name: Extract release notes from CHANGELOG
        run: |
          TAG="${GITHUB_REF#refs/tags/}"
          VERSION="${TAG#v}"
          python3 - "$VERSION" << 'EOF'
          import sys, re
          version = sys.argv[1]
          content = open("CHANGELOG.md").read()
          pattern = rf"## \[{re.escape(version)}\][^\n]*\n(.*?)(?=\n## \[|\Z)"
          m = re.search(pattern, content, re.DOTALL)
          print(m.group(1).strip() if m else "See CHANGELOG.md for details.")
          EOF
          > RELEASE_NOTES.md
          echo "TAG=$TAG" >> "$GITHUB_ENV"

      - uses: softprops/action-gh-release@v2
        with:
          name: "${{ env.TAG }}"
          body_path: RELEASE_NOTES.md
          files: |
            dist/*.tar.gz
            dist/*.zip
            dist/SHA256SUMS.txt

  publish-crates-io:
    name: Publish to crates.io
    needs: publish-github-release
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2
      - run: cargo publish --allow-dirty
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}