plwr 0.21.0

Playwright CLI for browser automation using CSS selectors.
name: CI

on:
  push:
    branches:
      - main
  pull_request:

permissions:
  contents: write

env:
  CARGO_TERM_COLOR: always

jobs:
  fmt:
    name: Format
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt
      - run: cargo fmt --all -- --check

  clippy:
    name: Clippy
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: clippy
      - uses: Swatinem/rust-cache@v2
      - run: cargo clippy --all-targets --all-features -- -D warnings

  test:
    name: Test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2
      - run: cargo test --all-features

  e2e:
    name: E2E Tests (${{ matrix.os }})
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, macos-latest]
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2
      - name: Install cctr
        uses: taiki-e/install-action@v2
        with:
          tool: cctr
      - name: Build
        run: cargo build --release
      - name: Install Playwright
        run: npm install -g playwright@1.56.1 ws && npx playwright install --with-deps chromium
      - name: Add to PATH
        run: echo "$PWD/target/release" >> $GITHUB_PATH
      - name: Run e2e tests
        run: cctr test/e2e

  check-release:
    name: Check Release
    runs-on: ubuntu-latest
    needs: [fmt, clippy, test, e2e]
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
    outputs:
      should_release: ${{ steps.check.outputs.should_release }}
      version: ${{ steps.check.outputs.version }}
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Check if release needed
        id: check
        run: |
          VERSION=$(grep '^version = ' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/')
          echo "version=$VERSION" >> $GITHUB_OUTPUT
          if git rev-parse "v$VERSION" >/dev/null 2>&1; then
            echo "Tag v$VERSION already exists"
            echo "should_release=false" >> $GITHUB_OUTPUT
          else
            echo "Tag v$VERSION does not exist, will release"
            echo "should_release=true" >> $GITHUB_OUTPUT
          fi

  create-release:
    name: Create Release
    runs-on: ubuntu-latest
    needs: check-release
    if: needs.check-release.outputs.should_release == 'true'
    steps:
      - uses: actions/checkout@v4
      - name: Create and push tag
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git tag -a "v${{ needs.check-release.outputs.version }}" -m "Release v${{ needs.check-release.outputs.version }}"
          git push origin "v${{ needs.check-release.outputs.version }}"
      - name: Create GitHub Release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          gh release create "v${{ needs.check-release.outputs.version }}" \
            --title "v${{ needs.check-release.outputs.version }}" \
            --notes "Release v${{ needs.check-release.outputs.version }}" \
            --draft

  build:
    name: Build ${{ matrix.target }}
    runs-on: ${{ matrix.os }}
    needs: [check-release, create-release]
    if: needs.check-release.outputs.should_release == 'true'
    strategy:
      fail-fast: false
      matrix:
        include:
          - target: x86_64-unknown-linux-gnu
            os: ubuntu-latest
            features: vendored-openssl
          - target: x86_64-unknown-linux-musl
            os: ubuntu-latest
            features: vendored-openssl
          - target: aarch64-unknown-linux-gnu
            os: ubuntu-latest
            features: vendored-openssl
          - target: aarch64-unknown-linux-musl
            os: ubuntu-latest
            features: vendored-openssl
          - target: x86_64-apple-darwin
            os: macos-latest
          - target: aarch64-apple-darwin
            os: macos-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: v${{ needs.check-release.outputs.version }}
      - uses: taiki-e/upload-rust-binary-action@v1
        env:
          PLAYWRIGHT_DRIVER_VERSION: "1.56.1"
        with:
          bin: plwr
          target: ${{ matrix.target }}
          features: ${{ matrix.features || '' }}
          archive: plwr-v${{ needs.check-release.outputs.version }}-${{ matrix.target }}
          ref: refs/tags/v${{ needs.check-release.outputs.version }}
          token: ${{ secrets.GITHUB_TOKEN }}

  publish:
    name: Publish to crates.io
    runs-on: ubuntu-latest
    needs: [check-release, create-release]
    if: needs.check-release.outputs.should_release == 'true'
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - name: Publish to crates.io
        run: |
          cargo generate-lockfile
          cargo publish --no-verify --allow-dirty
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

  release:
    name: Update GitHub Release
    runs-on: ubuntu-latest
    needs: [check-release, build, publish]
    if: needs.check-release.outputs.should_release == 'true'
    steps:
      - uses: actions/checkout@v4
      - name: Publish Release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          cat > release_notes.md << 'EOF'
          ## Installation

          ```bash
          # Via Homebrew (macOS/Linux)
          brew install andreasjansson/tap/plwr
          ```

          Requires Playwright: `npm install -g playwright && npx playwright install chromium`

          ## Binaries

          Pre-built binaries are available for Linux and macOS (x86_64 and ARM64).
          EOF

          gh release edit "v${{ needs.check-release.outputs.version }}" \
            --notes-file release_notes.md \
            --latest \
            --draft=false

  homebrew:
    name: Update Homebrew
    runs-on: ubuntu-latest
    needs: [check-release, release]
    if: needs.check-release.outputs.should_release == 'true'
    steps:
      - name: Download and hash binaries
        id: hashes
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          VERSION="${{ needs.check-release.outputs.version }}"
          BASE="https://github.com/andreasjansson/plwr/releases/download/v${VERSION}"

          for target in x86_64-apple-darwin aarch64-apple-darwin x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu; do
            FILE="plwr-v${VERSION}-${target}.tar.gz"
            curl -sL "${BASE}/${FILE}" -o "${FILE}"
            SHA=$(sha256sum "${FILE}" | cut -d' ' -f1)
            NAME=$(echo "$target" | tr '-' '_')
            echo "${NAME}=${SHA}" >> $GITHUB_OUTPUT
          done

      - name: Update Homebrew formula
        env:
          GH_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
        run: |
          VERSION="${{ needs.check-release.outputs.version }}"

          cat > plwr.rb << EOF
          class Plwr < Formula
            desc "Clean CLI for Playwright browser automation with CSS selectors"
            homepage "https://github.com/andreasjansson/plwr"
            version "${VERSION}"
            license "MIT"

            on_macos do
              on_intel do
                url "https://github.com/andreasjansson/plwr/releases/download/v${VERSION}/plwr-v${VERSION}-x86_64-apple-darwin.tar.gz"
                sha256 "${{ steps.hashes.outputs.x86_64_apple_darwin }}"
              end
              on_arm do
                url "https://github.com/andreasjansson/plwr/releases/download/v${VERSION}/plwr-v${VERSION}-aarch64-apple-darwin.tar.gz"
                sha256 "${{ steps.hashes.outputs.aarch64_apple_darwin }}"
              end
            end

            on_linux do
              on_intel do
                url "https://github.com/andreasjansson/plwr/releases/download/v${VERSION}/plwr-v${VERSION}-x86_64-unknown-linux-gnu.tar.gz"
                sha256 "${{ steps.hashes.outputs.x86_64_unknown_linux_gnu }}"
              end
              on_arm do
                url "https://github.com/andreasjansson/plwr/releases/download/v${VERSION}/plwr-v${VERSION}-aarch64-unknown-linux-gnu.tar.gz"
                sha256 "${{ steps.hashes.outputs.aarch64_unknown_linux_gnu }}"
              end
            end

            def install
              bin.install "plwr"
            end

            test do
              assert_match version.to_s, shell_output("#{bin}/plwr --version")
            end
          end
          EOF

          git clone https://x-access-token:${GH_TOKEN}@github.com/andreasjansson/homebrew-tap.git
          cp plwr.rb homebrew-tap/Formula/plwr.rb
          cd homebrew-tap
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add Formula/plwr.rb
          git commit -m "Update plwr to ${VERSION}"
          git push

  smoke-test-macos:
    name: Smoke Test (macOS/Homebrew)
    runs-on: macos-latest
    needs: [check-release, homebrew]
    if: needs.check-release.outputs.should_release == 'true'
    steps:
      - uses: actions/checkout@v4
      - name: Install plwr via Homebrew
        run: brew install andreasjansson/tap/plwr
      - name: Verify version
        run: |
          plwr --version
          plwr --version | grep -q "${{ needs.check-release.outputs.version }}"
      - name: Install cctr
        uses: taiki-e/install-action@v2
        with:
          tool: cctr
      - name: Install Playwright
        run: npm install -g playwright@1.56.1 && npx playwright install --with-deps chromium
      - name: Run e2e tests
        run: cctr test/e2e

  smoke-test-linux:
    name: Smoke Test (Linux/GitHub Release)
    runs-on: ubuntu-latest
    needs: [check-release, homebrew]
    if: needs.check-release.outputs.should_release == 'true'
    steps:
      - uses: actions/checkout@v4
      - name: Install plwr from GitHub Release
        run: |
          curl -L "https://github.com/andreasjansson/plwr/releases/download/v${{ needs.check-release.outputs.version }}/plwr-v${{ needs.check-release.outputs.version }}-x86_64-unknown-linux-gnu.tar.gz" | tar xz
          sudo mv plwr /usr/local/bin/
      - name: Verify version
        run: |
          plwr --version
          plwr --version | grep -q "${{ needs.check-release.outputs.version }}"
      - name: Install cctr
        uses: taiki-e/install-action@v2
        with:
          tool: cctr
      - name: Install Playwright
        run: npm install -g playwright@1.56.1 && npx playwright install --with-deps chromium
      - name: Run e2e tests
        run: cctr test/e2e