shelly-cli 0.1.11

CLI for managing and controlling Shelly devices
name: Release

on:
  push:
    tags:
      - "v*"

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt, clippy
      - uses: Swatinem/rust-cache@v2
      - run: make fmt-check
      - run: make lint
      - run: make test

  build:
    needs: check
    # Guard: self-hosted runners only execute on trusted events (tag push,
    # workflow_dispatch). Fork PRs must never dispatch jobs to self-hosted.
    if: github.event_name != 'pull_request'
    strategy:
      fail-fast: false
      matrix:
        include:
          - target: x86_64-unknown-linux-gnu
            os: ubuntu-latest
            maturin_args: --compatibility manylinux_2_28 --zig
          - target: aarch64-unknown-linux-gnu
            os: ubuntu-latest
            maturin_args: --compatibility manylinux_2_28 --zig
          - target: x86_64-apple-darwin
            os: [self-hosted, macOS, ARM64]
            maturin_args: ""
          - target: aarch64-apple-darwin
            os: [self-hosted, macOS, ARM64]
            maturin_args: ""
          - target: x86_64-pc-windows-msvc
            os: windows-latest
            maturin_args: ""
    runs-on: ${{ matrix.os }}
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@v6

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

      - uses: astral-sh/setup-uv@v6

      - name: Install maturin and zig
        shell: bash
        run: |
          uv venv "${RUNNER_TEMP}/build-venv"
          VENV_BIN="${RUNNER_TEMP}/build-venv/bin"
          [ -d "$VENV_BIN" ] || VENV_BIN="${RUNNER_TEMP}/build-venv/Scripts"
          VIRTUAL_ENV="${RUNNER_TEMP}/build-venv" uv pip install maturin ziglang
          echo "$VENV_BIN" >> "$GITHUB_PATH"

      - name: Build wheel and binary
        run: maturin build --release --target ${{ matrix.target }} ${{ matrix.maturin_args }}
        shell: bash

      - name: Package binary (unix)
        if: matrix.os != 'windows-latest'
        run: |
          cd target/${{ matrix.target }}/release
          tar czf ../../../shelly-${{ github.ref_name }}-${{ matrix.target }}.tar.gz shelly
        shell: bash

      - name: Package binary (windows)
        if: matrix.os == 'windows-latest'
        run: |
          cd target/${{ matrix.target }}/release
          7z a ../../../shelly-${{ github.ref_name }}-${{ matrix.target }}.zip shelly.exe
        shell: bash

      - name: Upload binary artifact
        uses: actions/upload-artifact@v6
        with:
          name: binary-${{ matrix.target }}
          path: shelly-${{ github.ref_name }}-${{ matrix.target }}.*

      - name: Upload wheel artifact
        uses: actions/upload-artifact@v6
        with:
          name: wheel-${{ matrix.target }}
          path: target/wheels/*.whl

  sdist:
    needs: check
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: astral-sh/setup-uv@v6
      - name: Install maturin
        shell: bash
        run: |
          uv venv "${RUNNER_TEMP}/build-venv"
          VENV_BIN="${RUNNER_TEMP}/build-venv/bin"
          [ -d "$VENV_BIN" ] || VENV_BIN="${RUNNER_TEMP}/build-venv/Scripts"
          VIRTUAL_ENV="${RUNNER_TEMP}/build-venv" uv pip install maturin
          echo "$VENV_BIN" >> "$GITHUB_PATH"
      - run: maturin sdist
      - uses: actions/upload-artifact@v6
        with:
          name: sdist
          path: target/wheels/*.tar.gz

  release:
    needs: build
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - uses: actions/download-artifact@v6
        with:
          pattern: binary-*
          merge-multiple: true

      - name: Create GitHub Release
        uses: softprops/action-gh-release@v2
        with:
          generate_release_notes: true
          files: |
            shelly-*.tar.gz
            shelly-*.zip

  publish-crates:
    needs: release
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@stable
      - run: cargo publish --locked
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

  publish-pypi:
    needs: [build, sdist]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/download-artifact@v6
        with:
          pattern: wheel-*
          path: artifacts/wheels
      - uses: actions/download-artifact@v6
        with:
          name: sdist
          path: artifacts/sdist
      - uses: astral-sh/setup-uv@v6
      - name: Publish to PyPI
        env:
          TWINE_USERNAME: __token__
          TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
        run: uv tool run twine upload artifacts/wheels/**/*.whl artifacts/sdist/*.tar.gz

  update-homebrew:
    needs: release
    runs-on: ubuntu-latest
    env:
      HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
    steps:
      - name: Check for tap token
        id: check-token
        run: |
          if [ -z "$HOMEBREW_TAP_TOKEN" ]; then
            echo "skip=true" >> "$GITHUB_OUTPUT"
            echo "HOMEBREW_TAP_TOKEN not set, skipping Homebrew formula update"
          else
            echo "skip=false" >> "$GITHUB_OUTPUT"
          fi

      - name: Download release assets and compute SHA256 hashes
        if: steps.check-token.outputs.skip == 'false'
        run: |
          TAG="${{ github.ref_name }}"
          BASE_URL="https://github.com/rvben/shelly-cli/releases/download/${TAG}"
          for target in aarch64-apple-darwin x86_64-apple-darwin aarch64-unknown-linux-gnu x86_64-unknown-linux-gnu; do
            curl -fsSL -o "shelly-${TAG}-${target}.tar.gz" "${BASE_URL}/shelly-${TAG}-${target}.tar.gz"
          done
          echo "SHA_MACOS_ARM64=$(sha256sum shelly-${TAG}-aarch64-apple-darwin.tar.gz | cut -d' ' -f1)" >> "$GITHUB_ENV"
          echo "SHA_MACOS_X86=$(sha256sum shelly-${TAG}-x86_64-apple-darwin.tar.gz | cut -d' ' -f1)" >> "$GITHUB_ENV"
          echo "SHA_LINUX_ARM64=$(sha256sum shelly-${TAG}-aarch64-unknown-linux-gnu.tar.gz | cut -d' ' -f1)" >> "$GITHUB_ENV"
          echo "SHA_LINUX_X86=$(sha256sum shelly-${TAG}-x86_64-unknown-linux-gnu.tar.gz | cut -d' ' -f1)" >> "$GITHUB_ENV"

      - name: Update Homebrew formula
        if: steps.check-token.outputs.skip == 'false'
        run: |
          TAG="${{ github.ref_name }}"
          VERSION="${TAG#v}"

          git clone "https://x-access-token:${HOMEBREW_TAP_TOKEN}@github.com/rvben/homebrew-tap.git" homebrew-tap
          cd homebrew-tap

          cat > Formula/shelly-cli.rb << 'FORMULA'
          class ShellyCli < Formula
            desc "Fast CLI for discovering, monitoring, and controlling Shelly devices"
            homepage "https://github.com/rvben/shelly-cli"
            version "VERSION_PLACEHOLDER"
            license "MIT"

            on_macos do
              if Hardware::CPU.arm?
                url "https://github.com/rvben/shelly-cli/releases/download/v#{version}/shelly-v#{version}-aarch64-apple-darwin.tar.gz"
                sha256 "SHA_MACOS_ARM64_PLACEHOLDER"
              else
                url "https://github.com/rvben/shelly-cli/releases/download/v#{version}/shelly-v#{version}-x86_64-apple-darwin.tar.gz"
                sha256 "SHA_MACOS_X86_PLACEHOLDER"
              end
            end

            on_linux do
              if Hardware::CPU.arm?
                url "https://github.com/rvben/shelly-cli/releases/download/v#{version}/shelly-v#{version}-aarch64-unknown-linux-gnu.tar.gz"
                sha256 "SHA_LINUX_ARM64_PLACEHOLDER"
              else
                url "https://github.com/rvben/shelly-cli/releases/download/v#{version}/shelly-v#{version}-x86_64-unknown-linux-gnu.tar.gz"
                sha256 "SHA_LINUX_X86_PLACEHOLDER"
              end
            end

            def install
              bin.install "shelly"
              bin.install_symlink "shelly" => "shelly-cli"
            end

            test do
              assert_match "shelly #{version}", shell_output("#{bin}/shelly --version")
            end
          end
          FORMULA

          # Remove leading whitespace from heredoc and replace placeholders
          sed -i 's/^          //' Formula/shelly-cli.rb
          sed -i "s/VERSION_PLACEHOLDER/${VERSION}/" Formula/shelly-cli.rb
          sed -i "s/SHA_MACOS_ARM64_PLACEHOLDER/${SHA_MACOS_ARM64}/" Formula/shelly-cli.rb
          sed -i "s/SHA_MACOS_X86_PLACEHOLDER/${SHA_MACOS_X86}/" Formula/shelly-cli.rb
          sed -i "s/SHA_LINUX_ARM64_PLACEHOLDER/${SHA_LINUX_ARM64}/" Formula/shelly-cli.rb
          sed -i "s/SHA_LINUX_X86_PLACEHOLDER/${SHA_LINUX_X86}/" Formula/shelly-cli.rb

          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add Formula/shelly-cli.rb
          git commit -m "Update shelly-cli to ${VERSION}"
          git push