Release #65
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: "Tag to release (e.g. v2.10.3). Must already exist." | |
| required: true | |
| type: string | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_NAME: ${{ github.repository }} | |
| permissions: | |
| contents: write | |
| packages: write | |
| jobs: | |
| # Run tests once before building | |
| test: | |
| runs-on: ubuntu-latest | |
| name: Test | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ inputs.tag }} | |
| - name: Setup Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version-file: go.mod | |
| - name: Test with race detection | |
| run: go test -race ./... | |
| build-standard: | |
| needs: test | |
| strategy: | |
| matrix: | |
| include: | |
| - goos: linux | |
| goarch: amd64 | |
| binary: onwatch-linux-amd64 | |
| - goos: linux | |
| goarch: arm64 | |
| binary: onwatch-linux-arm64 | |
| - goos: windows | |
| goarch: amd64 | |
| binary: onwatch-windows-amd64.exe | |
| runs-on: ubuntu-latest | |
| name: Build ${{ matrix.goos }}/${{ matrix.goarch }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ inputs.tag }} | |
| - name: Setup Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version-file: go.mod | |
| - name: Read version | |
| id: version | |
| run: echo "version=$(cat VERSION)" >> "$GITHUB_OUTPUT" | |
| - name: Build | |
| env: | |
| CGO_ENABLED: "0" | |
| GOOS: ${{ matrix.goos }} | |
| GOARCH: ${{ matrix.goarch }} | |
| run: | | |
| go build -ldflags="-s -w -X main.version=${{ steps.version.outputs.version }}" \ | |
| -o ${{ matrix.binary }} . | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.binary }} | |
| path: ${{ matrix.binary }} | |
| build-macos-amd64: | |
| needs: test | |
| runs-on: macos-15 | |
| name: Build macOS amd64 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ inputs.tag }} | |
| - name: Setup Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version-file: go.mod | |
| - name: Read version | |
| id: version | |
| run: echo "version=$(cat VERSION)" >> "$GITHUB_OUTPUT" | |
| - name: Build macOS artifact | |
| run: | | |
| CGO_ENABLED=1 GOOS=darwin GOARCH=amd64 go build \ | |
| -tags menubar,desktop,production \ | |
| -ldflags="-s -w -X main.version=${{ steps.version.outputs.version }}" \ | |
| -o onwatch-darwin-amd64 . | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: onwatch-darwin-amd64 | |
| path: onwatch-darwin-amd64 | |
| build-macos-arm64: | |
| needs: test | |
| runs-on: macos-15 | |
| name: Build macOS arm64 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ inputs.tag }} | |
| - name: Setup Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version-file: go.mod | |
| - name: Read version | |
| id: version | |
| run: echo "version=$(cat VERSION)" >> "$GITHUB_OUTPUT" | |
| - name: Build macOS artifact | |
| run: | | |
| CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 go build \ | |
| -tags menubar,desktop,production \ | |
| -ldflags="-s -w -X main.version=${{ steps.version.outputs.version }}" \ | |
| -o onwatch-darwin-arm64 . | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: onwatch-darwin-arm64 | |
| path: onwatch-darwin-arm64 | |
| # Create GitHub release with all binaries | |
| release: | |
| needs: [build-standard, build-macos-amd64, build-macos-arm64] | |
| runs-on: ubuntu-latest | |
| name: Release | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ inputs.tag }} | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: dist | |
| merge-multiple: true | |
| - name: List binaries | |
| run: ls -lh dist/ | |
| - name: Copy additional release files | |
| run: | | |
| cp install.bat dist/ | |
| cp Dockerfile dist/ | |
| cp docker-compose.yml dist/ | |
| cp .env.docker.example dist/ | |
| - name: Create GitHub Release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| # Delete existing release if present (allows re-running workflow) | |
| gh release delete "${{ inputs.tag }}" --yes 2>/dev/null || true | |
| gh release create "${{ inputs.tag }}" dist/* \ | |
| --title "onWatch ${{ inputs.tag }}" \ | |
| --generate-notes | |
| # Build and push Docker image (after release is created) | |
| docker: | |
| needs: release | |
| runs-on: ubuntu-latest | |
| name: Docker | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ inputs.tag }} | |
| persist-credentials: false | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@v3 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Read version | |
| id: version | |
| run: | | |
| if [ ! -f VERSION ] || [ ! -s VERSION ]; then | |
| echo "ERROR: VERSION file is missing or empty" | |
| exit 1 | |
| fi | |
| echo "version=$(cat VERSION)" >> "$GITHUB_OUTPUT" | |
| # Build Alpine variant first (issue #34) | |
| - name: Extract metadata for Alpine variant | |
| id: meta-alpine | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| tags: | | |
| type=semver,pattern={{version}}-alpine,value=${{ inputs.tag }} | |
| type=semver,pattern={{major}}.{{minor}}-alpine,value=${{ inputs.tag }} | |
| type=raw,value=alpine | |
| - name: Build and push Docker image (Alpine with shell) | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| target: runtime-shell | |
| platforms: linux/arm64,linux/amd64 | |
| push: true | |
| tags: ${{ steps.meta-alpine.outputs.tags }} | |
| labels: ${{ steps.meta-alpine.outputs.labels }} | |
| build-args: | | |
| VERSION=${{ steps.version.outputs.version }} | |
| BUILD_TIME=${{ github.event.head_commit.timestamp }} | |
| cache-from: type=gha,scope=alpine | |
| cache-to: type=gha,mode=max,scope=alpine | |
| # Build distroless last so its `latest` tag is the final push | |
| - name: Extract metadata (tags, labels) for Docker | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| tags: | | |
| type=semver,pattern={{version}},value=${{ inputs.tag }} | |
| type=semver,pattern={{major}}.{{minor}},value=${{ inputs.tag }} | |
| type=semver,pattern={{major}},value=${{ inputs.tag }} | |
| type=raw,value=latest | |
| - name: Build and push Docker image (distroless) | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| target: runtime | |
| platforms: linux/arm64,linux/amd64 | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| build-args: | | |
| VERSION=${{ steps.version.outputs.version }} | |
| BUILD_TIME=${{ github.event.head_commit.timestamp }} | |
| cache-from: type=gha,scope=distroless | |
| cache-to: type=gha,mode=max,scope=distroless | |
| # Update Homebrew formula with new version and checksums | |
| homebrew: | |
| needs: [release, docker] | |
| runs-on: ubuntu-latest | |
| name: Update Homebrew Formula | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ inputs.tag }} | |
| - name: Read version | |
| id: version | |
| run: echo "version=$(cat VERSION)" >> "$GITHUB_OUTPUT" | |
| - name: Download release binaries | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| mkdir -p /tmp/bins | |
| TAG="${{ inputs.tag }}" | |
| for bin in darwin-arm64 darwin-amd64 linux-arm64 linux-amd64; do | |
| gh release download "$TAG" -p "onwatch-${bin}" -D /tmp/bins/ | |
| done | |
| - name: Compute checksums and update formula | |
| env: | |
| TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} | |
| run: | | |
| VERSION="${{ steps.version.outputs.version }}" | |
| SHA_DARWIN_ARM64=$(sha256sum /tmp/bins/onwatch-darwin-arm64 | cut -d' ' -f1) | |
| SHA_DARWIN_AMD64=$(sha256sum /tmp/bins/onwatch-darwin-amd64 | cut -d' ' -f1) | |
| SHA_LINUX_ARM64=$(sha256sum /tmp/bins/onwatch-linux-arm64 | cut -d' ' -f1) | |
| SHA_LINUX_AMD64=$(sha256sum /tmp/bins/onwatch-linux-amd64 | cut -d' ' -f1) | |
| git clone "https://x-access-token:${TAP_TOKEN}@github.com/onllm-dev/homebrew-tap.git" /tmp/tap | |
| cd /tmp/tap | |
| mkdir -p Formula | |
| cat > Formula/onwatch.rb << 'FORMULA' | |
| class Onwatch < Formula | |
| desc "CLI tool for tracking AI API quotas across multiple providers" | |
| homepage "https://github.com/onllm-dev/onwatch" | |
| version "VERSION_PLACEHOLDER" | |
| license "GPL-3.0-only" | |
| on_macos do | |
| if Hardware::CPU.arm? | |
| url "https://github.com/onllm-dev/onwatch/releases/download/vVERSION_PLACEHOLDER/onwatch-darwin-arm64" | |
| sha256 "SHA_DARWIN_ARM64_PLACEHOLDER" | |
| else | |
| url "https://github.com/onllm-dev/onwatch/releases/download/vVERSION_PLACEHOLDER/onwatch-darwin-amd64" | |
| sha256 "SHA_DARWIN_AMD64_PLACEHOLDER" | |
| end | |
| end | |
| on_linux do | |
| if Hardware::CPU.arm? | |
| url "https://github.com/onllm-dev/onwatch/releases/download/vVERSION_PLACEHOLDER/onwatch-linux-arm64" | |
| sha256 "SHA_LINUX_ARM64_PLACEHOLDER" | |
| else | |
| url "https://github.com/onllm-dev/onwatch/releases/download/vVERSION_PLACEHOLDER/onwatch-linux-amd64" | |
| sha256 "SHA_LINUX_AMD64_PLACEHOLDER" | |
| end | |
| end | |
| def install | |
| bin.install Dir["onwatch-*"].first => "onwatch" | |
| end | |
| def caveats | |
| <<~EOS | |
| To configure onWatch, run the interactive setup wizard: | |
| onwatch setup | |
| This will guide you through configuring API keys, dashboard | |
| credentials, and polling settings. Configuration is stored | |
| in ~/.onwatch/.env | |
| After setup, start onWatch with: | |
| onwatch | |
| EOS | |
| end | |
| test do | |
| assert_match version.to_s, shell_output("#{bin}/onwatch --version") | |
| end | |
| end | |
| FORMULA | |
| # Replace placeholders with actual values | |
| sed -i "s/VERSION_PLACEHOLDER/${VERSION}/g" Formula/onwatch.rb | |
| sed -i "s/SHA_DARWIN_ARM64_PLACEHOLDER/${SHA_DARWIN_ARM64}/g" Formula/onwatch.rb | |
| sed -i "s/SHA_DARWIN_AMD64_PLACEHOLDER/${SHA_DARWIN_AMD64}/g" Formula/onwatch.rb | |
| sed -i "s/SHA_LINUX_ARM64_PLACEHOLDER/${SHA_LINUX_ARM64}/g" Formula/onwatch.rb | |
| sed -i "s/SHA_LINUX_AMD64_PLACEHOLDER/${SHA_LINUX_AMD64}/g" Formula/onwatch.rb | |
| # Remove leading whitespace from heredoc (cat << 'FORMULA' adds indentation) | |
| sed -i 's/^ //' Formula/onwatch.rb | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add Formula/onwatch.rb | |
| git commit -m "onwatch ${VERSION}" | |
| git push |