ralph-coder 0.2.1

An agentic code generation CLI powered by multiple LLM backends
Documentation
name: Release

on:
  push:
    tags:
      - 'v*'

permissions:
  contents: write   # needed to create releases and upload assets

env:
  CARGO_TERM_COLOR: always
  BINARY_NAME: ralph

jobs:
  # Run tests once before building all platforms
  test:
    name: Pre-release tests
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - name: Cache
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: test-cargo-${{ hashFiles('**/Cargo.lock') }}
      - run: cargo test --all

  # Create the release on ralph-releases before any build jobs run
  create-release:
    name: Create release on ralph-releases
    needs: test
    runs-on: ubuntu-latest
    steps:
      - name: Create release
        uses: softprops/action-gh-release@v2
        with:
          repository: akkeshavan/ralph-releases
          token: ${{ secrets.RELEASES_TOKEN }}
          tag_name: ${{ github.ref_name }}
          name: ${{ github.ref_name }}
          generate_release_notes: false
          draft: false

  build:
    name: Build ${{ matrix.target }}
    needs: create-release
    runs-on: ${{ matrix.runner }}
    strategy:
      fail-fast: false
      matrix:
        include:
          # ── Linux x86-64 ───────────────────────────────────────────────────
          - target: x86_64-unknown-linux-gnu
            runner: ubuntu-latest
            archive: tar.gz
            use_cross: false

          # ── Linux ARM64 (for Graviton, Raspberry Pi 5, etc.) ──────────────
          - target: aarch64-unknown-linux-gnu
            runner: ubuntu-24.04-arm
            archive: tar.gz
            use_cross: false

          # ── macOS Apple Silicon ────────────────────────────────────────────
          - target: aarch64-apple-darwin
            runner: macos-latest
            archive: tar.gz
            use_cross: false

          # ── macOS Intel ────────────────────────────────────────────────────
          - target: x86_64-apple-darwin
            runner: macos-latest
            archive: tar.gz
            use_cross: false

          # ── Windows x86-64 ─────────────────────────────────────────────────
          - target: x86_64-pc-windows-msvc
            runner: windows-latest
            archive: zip
            use_cross: false

    steps:
      - uses: actions/checkout@v4

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}

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

      # Install `cross` for Linux ARM64 builds (Docker-based cross-compilation)
      - name: Install cross
        if: matrix.use_cross
        run: cargo install cross --git https://github.com/cross-rs/cross

      # ── Build ──────────────────────────────────────────────────────────────
      - name: Build (native)
        if: "!matrix.use_cross"
        run: cargo build --release --target ${{ matrix.target }}

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

      # ── Package ───────────────────────────────────────────────────────────
      - name: Get version from tag
        id: version
        shell: bash
        run: echo "VERSION=${GITHUB_REF_NAME}" >> $GITHUB_OUTPUT

      - name: Package (Unix tar.gz)
        if: matrix.archive == 'tar.gz'
        shell: bash
        run: |
          ASSET_NAME="${{ env.BINARY_NAME }}-${{ steps.version.outputs.VERSION }}-${{ matrix.target }}"
          BINARY="target/${{ matrix.target }}/release/${{ env.BINARY_NAME }}"
          mkdir -p "dist/${ASSET_NAME}"
          cp "${BINARY}" "dist/${ASSET_NAME}/"
          cp README.md LICENSE "dist/${ASSET_NAME}/" 2>/dev/null || true
          cd dist
          tar czf "${ASSET_NAME}.tar.gz" "${ASSET_NAME}"
          sha256sum "${ASSET_NAME}.tar.gz" > "checksums-${{ matrix.target }}.txt"
          echo "ASSET=dist/${ASSET_NAME}.tar.gz" >> $GITHUB_ENV
          echo "CHECKSUM_FILE=dist/checksums-${{ matrix.target }}.txt" >> $GITHUB_ENV

      - name: Package (Windows zip)
        if: matrix.archive == 'zip'
        shell: pwsh
        run: |
          $version = "${{ steps.version.outputs.VERSION }}"
          $assetName = "${{ env.BINARY_NAME }}-${version}-${{ matrix.target }}"
          $binary = "target/${{ matrix.target }}/release/${{ env.BINARY_NAME }}.exe"
          New-Item -ItemType Directory -Force -Path "dist/$assetName"
          Copy-Item $binary "dist/$assetName/"
          if (Test-Path "README.md") { Copy-Item "README.md" "dist/$assetName/" }
          if (Test-Path "LICENSE") { Copy-Item "LICENSE" "dist/$assetName/" }
          Compress-Archive -Path "dist/$assetName" -DestinationPath "dist/$assetName.zip"
          $hash = (Get-FileHash "dist/$assetName.zip" -Algorithm SHA256).Hash.ToLower()
          "$hash  $assetName.zip" | Out-File -FilePath "dist/checksums-${{ matrix.target }}.txt"
          echo "ASSET=dist/$assetName.zip" >> $env:GITHUB_ENV
          echo "CHECKSUM_FILE=dist/checksums-${{ matrix.target }}.txt" >> $env:GITHUB_ENV

      # ── Upload checksum fragment as artifact ──────────────────────────────
      - name: Upload checksum fragment
        uses: actions/upload-artifact@v4
        with:
          name: checksums-${{ matrix.target }}
          path: ${{ env.CHECKSUM_FILE }}

      # ── Upload asset to public ralph-releases repo ───────────────────────
      - name: Upload asset to ralph-releases
        uses: softprops/action-gh-release@v2
        with:
          repository: akkeshavan/ralph-releases
          token: ${{ secrets.RELEASES_TOKEN }}
          tag_name: ${{ steps.version.outputs.VERSION }}
          files: ${{ env.ASSET }}
          generate_release_notes: false

  # Collect all checksums into one file and attach it to the release
  checksums:
    name: Publish checksums
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Download all checksum fragments
        uses: actions/download-artifact@v4
        with:
          pattern: checksums-*
          merge-multiple: true

      - name: Combine checksums
        run: |
          cat checksums-*.txt | sort > checksums.txt
          cat checksums.txt

      - name: Upload combined checksums to ralph-releases
        uses: softprops/action-gh-release@v2
        with:
          repository: akkeshavan/ralph-releases
          token: ${{ secrets.RELEASES_TOKEN }}
          tag_name: ${{ github.ref_name }}
          files: checksums.txt
          generate_release_notes: true