waterui 0.3.0

A modern UI framework for Rust
name: Build CLI

on:
  workflow_call:
    inputs:
      tag:
        description: "Tag to build (e.g., waterui-cli-v0.1.0)"
        required: true
        type: string
    secrets:
      HOMEBREW_PAT:
        required: true
  workflow_dispatch:
    inputs:
      tag:
        description: "Tag to build (e.g., waterui-cli-v0.1.0)"
        required: true
        type: string

permissions:
  contents: write

env:
  CARGO_TERM_COLOR: always
  BINARY_NAME: water
  DIST_VERSION: 0.30.2

jobs:
  check:
    name: Check if CLI release
    runs-on: ubuntu-latest
    outputs:
      should_build: ${{ steps.check.outputs.should_build }}
      version: ${{ steps.check.outputs.version }}
      tag: ${{ steps.check.outputs.tag }}
    steps:
      - name: Check release tag
        id: check
        run: |
          TAG="${{ inputs.tag }}"
          if [[ "$TAG" == waterui-cli-v* ]]; then
            echo "should_build=true" >> "$GITHUB_OUTPUT"
            VERSION="${TAG#waterui-cli-v}"
            echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
            echo "tag=$TAG" >> "$GITHUB_OUTPUT"
          else
            echo "should_build=false" >> "$GITHUB_OUTPUT"
          fi

  build:
    name: Build ${{ matrix.target }}
    needs: check
    if: needs.check.outputs.should_build == 'true'
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - target: x86_64-unknown-linux-gnu
            os: ubuntu-latest
          - target: aarch64-unknown-linux-gnu
            os: ubuntu-latest
          - target: x86_64-apple-darwin
            os: macos-latest
          - target: aarch64-apple-darwin
            os: macos-latest
          - target: x86_64-pc-windows-msvc
            os: windows-latest
          - target: aarch64-pc-windows-msvc
            os: windows-latest

    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ needs.check.outputs.tag }}
          submodules: recursive

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

      - name: Install zig (for linux aarch64)
        if: runner.os == 'Linux' && matrix.target == 'aarch64-unknown-linux-gnu'
        uses: goto-bus-stop/setup-zig@v2

      - name: Install cargo-zigbuild (for linux aarch64)
        if: runner.os == 'Linux' && matrix.target == 'aarch64-unknown-linux-gnu'
        uses: taiki-e/install-action@v2
        with:
          tool: cargo-zigbuild

      - uses: Swatinem/rust-cache@v2
        with:
          shared-key: dist-${{ matrix.target }}

      - name: Install cargo-dist
        uses: taiki-e/install-action@v2
        with:
          tool: cargo-dist@${{ env.DIST_VERSION }}

      - name: Build artifacts
        shell: bash
        run: |
          dist build \
            --tag "${{ needs.check.outputs.tag }}" \
            --artifacts=local \
            --target "${{ matrix.target }}"

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: artifacts-${{ matrix.target }}
          if-no-files-found: error
          path: |
            target/distrib/*${{ matrix.target }}*.tar.*
            target/distrib/*${{ matrix.target }}*.zip*
            target/distrib/*${{ matrix.target }}*-dist-manifest.json

  browser-runtime-wpe:
    name: Build WPE runtime ${{ matrix.architecture }}
    needs: check
    if: needs.check.outputs.should_build == 'true'
    runs-on: ${{ matrix.runner }}
    timeout-minutes: 360
    env:
      CC: gcc-12
      CXX: g++-12
    strategy:
      fail-fast: false
      matrix:
        include:
          - architecture: x86_64
            runner: ubuntu-22.04
          - architecture: aarch64
            runner: ubuntu-22.04-arm

    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ needs.check.outputs.tag }}
          submodules: recursive

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

      - uses: ./.github/actions/setup-linux-deps
        with:
          gpu: "true"
          gcc-version: "12"

      - uses: Swatinem/rust-cache@v2
        with:
          shared-key: browser-runtime-${{ matrix.architecture }}
          cache-on-failure: true

      - name: Build self-contained WPE runtime
        run: components/platform/browser-wpe/runtime/build-runtime.sh runtime-artifacts

      - name: Upload WPE runtime
        uses: actions/upload-artifact@v4
        with:
          name: browser-runtime-wpe-${{ matrix.architecture }}
          if-no-files-found: error
          path: |
            runtime-artifacts/*.zip
            runtime-artifacts/*.artifact.json

      - name: Upload WPE validation
        uses: actions/upload-artifact@v4
        with:
          name: browser-validation-wpe-${{ matrix.architecture }}
          if-no-files-found: error
          path: |
            runtime-artifacts/wpe-smoke-*.json
            runtime-artifacts/wpe-smoke-*.png

  release:
    name: Upload Release Assets
    needs: [check, build, browser-runtime-wpe]
    if: needs.check.outputs.should_build == 'true'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ needs.check.outputs.tag }}
          submodules: recursive

      - name: Install cargo-dist
        uses: taiki-e/install-action@v2
        with:
          tool: cargo-dist@${{ env.DIST_VERSION }}

      - name: Download CLI artifacts
        uses: actions/download-artifact@v4
        with:
          pattern: artifacts-*
          path: target/distrib
          merge-multiple: true

      - name: Download browser runtime artifacts
        uses: actions/download-artifact@v4
        with:
          pattern: browser-runtime-wpe-*
          path: target/distrib
          merge-multiple: true

      - name: Generate browser runtime manifest
        shell: bash
        env:
          RELEASE_TAG: ${{ needs.check.outputs.tag }}
        run: |
          BASE_URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${RELEASE_TAG}"
          python3 components/platform/browser-wpe/runtime/generate-manifest.py \
            --base-url "$BASE_URL" \
            --output target/distrib/browser-runtime-manifest.json \
            target/distrib/*.artifact.json
          find target/distrib -maxdepth 1 -name '*.artifact.json' -delete

      - name: Build global release artifacts
        run: dist build --tag "${{ needs.check.outputs.tag }}" --artifacts=global

      - name: Upload assets to release
        uses: softprops/action-gh-release@v2
        with:
          tag_name: ${{ needs.check.outputs.tag }}
          files: |
            target/distrib/*.tar.*
            target/distrib/*.zip
            target/distrib/*.sha256
            target/distrib/sha256.sum
            target/distrib/browser-runtime-manifest.json

      - name: Checkout Homebrew tap
        uses: actions/checkout@v4
        with:
          repository: water-rs/homebrew-water
          token: ${{ secrets.HOMEBREW_PAT }}
          path: homebrew-water

      - name: Stage dist-generated Homebrew formula
        run: cp target/distrib/water.rb homebrew-water/Formula/water.rb

      - name: Push Homebrew formula update
        shell: bash
        env:
          VERSION: ${{ needs.check.outputs.version }}
        run: |
          set -euo pipefail
          cd homebrew-water
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git config user.name "github-actions[bot]"
          git add Formula/water.rb
          if git diff --cached --quiet; then
            echo "No Homebrew changes to publish."
            exit 0
          fi
          git commit -m "water ${VERSION}"
          git push