From b5a9c89c6639d7df794f1e239e44520b2d6d89c0 Mon Sep 17 00:00:00 2001 From: Kfir Strikovsky Date: Wed, 11 Mar 2026 11:37:51 +0200 Subject: [PATCH 1/2] update brew tap --- .github/workflows/manual-publish.yml | 41 ++++++++++++++++++++++---- docs/binary-distribution.md | 17 +++++++++-- packages/cli/infra/package-binaries.ts | 20 +------------ 3 files changed, 51 insertions(+), 27 deletions(-) diff --git a/.github/workflows/manual-publish.yml b/.github/workflows/manual-publish.yml index a8b14a33..96c5a3e3 100644 --- a/.github/workflows/manual-publish.yml +++ b/.github/workflows/manual-publish.yml @@ -18,11 +18,6 @@ on: required: false default: false type: boolean - update_changelog: - description: "Update CHANGELOG.md with release notes" - required: false - default: false - type: boolean notify_skills_repo: description: "Notify the skills repo about the release" required: false @@ -215,6 +210,42 @@ jobs: gh release upload "v${{ env.NEW_VERSION }}" "$file" --clobber done + - name: Update Homebrew Tap + if: github.event.inputs.dry_run == 'false' && github.event.inputs.npm_tag == 'latest' + env: + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + run: | + VERSION="${{ env.NEW_VERSION }}" + BINARIES_DIR="${{ env.CLI_PACKAGE_DIR }}/dist/binaries" + + SHA_DARWIN_ARM64=$(shasum -a 256 "$BINARIES_DIR/base44-darwin-arm64.tar.gz" | awk '{print $1}') + SHA_DARWIN_X64=$(shasum -a 256 "$BINARIES_DIR/base44-darwin-x64.tar.gz" | awk '{print $1}') + SHA_LINUX_ARM64=$(shasum -a 256 "$BINARIES_DIR/base44-linux-arm64.tar.gz" | awk '{print $1}') + SHA_LINUX_X64=$(shasum -a 256 "$BINARIES_DIR/base44-linux-x64.tar.gz" | awk '{print $1}') + + cp "${{ env.CLI_PACKAGE_DIR }}/infra/homebrew/base44.rb" /tmp/base44.rb + sed -i 's/version ".*"/version "'"$VERSION"'"/' /tmp/base44.rb + sed -i "s/PLACEHOLDER_DARWIN_ARM64/$SHA_DARWIN_ARM64/" /tmp/base44.rb + sed -i "s/PLACEHOLDER_DARWIN_X64/$SHA_DARWIN_X64/" /tmp/base44.rb + sed -i "s/PLACEHOLDER_LINUX_ARM64/$SHA_LINUX_ARM64/" /tmp/base44.rb + sed -i "s/PLACEHOLDER_LINUX_X64/$SHA_LINUX_X64/" /tmp/base44.rb + + rm -rf /tmp/homebrew-tap + git clone "https://x-access-token:${GH_TOKEN}@github.com/base44/homebrew-tap.git" /tmp/homebrew-tap + mkdir -p /tmp/homebrew-tap/Formula + cp /tmp/base44.rb /tmp/homebrew-tap/Formula/base44.rb + + cd /tmp/homebrew-tap + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add Formula/base44.rb + if git diff --cached --quiet; then + echo "Homebrew formula already up to date" + exit 0 + fi + git commit -m "Update base44 to ${VERSION}" + git push origin master + - name: Release summary if: steps.prev-tag.outputs.tag != '' run: | diff --git a/docs/binary-distribution.md b/docs/binary-distribution.md index 04d72b0e..fa7527f1 100644 --- a/docs/binary-distribution.md +++ b/docs/binary-distribution.md @@ -15,7 +15,6 @@ The binary release pipeline has two steps: 2. **`infra/package-binaries.ts`** — packages each binary for release: - Wraps each binary (renamed to `base44` / `base44.exe`) and `README.md` in a `.tar.gz` archive - Deletes the raw binary - - Generates SHA256 checksums for each archive ```bash bun run build # Must run first — produces dist/cli/ and dist/assets/ @@ -49,11 +48,23 @@ No `assetsDir` parameter is passed through CLIContext or function signatures. Ad ## Homebrew Formula -`infra/homebrew/base44.rb` is a reference template for the Homebrew tap. It downloads the `.tar.gz` archive for the user's platform from GitHub Releases. Homebrew auto-extracts the tarball, so the install block simply does `bin.install "base44"`. Copy it to the `homebrew-tap` repo and update version + SHA256 values on each release. +`infra/homebrew/base44.rb` is a template for the Homebrew tap formula. It downloads the `.tar.gz` archive for the user's platform from GitHub Releases. Homebrew auto-extracts the tarball, so the install block simply does `bin.install "base44"`. + +The template uses `PLACEHOLDER_*` SHA256 values that are replaced automatically by CI on each release. The rendered formula is pushed to the [base44/homebrew-tap](https://github.com/base44/homebrew-tap) repository at `Formula/base44.rb`. + +Users install with: +```bash +brew install base44/tap/base44 +``` ## CI Integration -The `manual-publish.yml` workflow runs `build:binaries` then `package:binaries` after `bun run build`, and uploads the resulting `.tar.gz` and `.sha256` files to the GitHub Release. Binaries are excluded from the npm package via `.npmignore`. +The `manual-publish.yml` workflow runs `build:binaries` then `package:binaries` after `bun run build`, and uploads the resulting `.tar.gz` files to the GitHub Release. Binaries are excluded from the npm package via `.npmignore`. + +For `latest` tag releases (not beta/alpha), the workflow also updates the Homebrew tap automatically: +1. Computes SHA256 checksums for each platform archive +2. Renders the formula template with the new version and checksums +3. Pushes the updated formula to `base44/homebrew-tap` ## Rules diff --git a/packages/cli/infra/package-binaries.ts b/packages/cli/infra/package-binaries.ts index a2dffe1a..0215eb8f 100644 --- a/packages/cli/infra/package-binaries.ts +++ b/packages/cli/infra/package-binaries.ts @@ -6,9 +6,8 @@ * Steps: * 1. Wrap each binary + README.md in a .tar.gz archive * 2. Delete the raw binary - * 3. Generate SHA256 checksums for each archive */ -import { readFileSync, existsSync, unlinkSync, writeFileSync } from "node:fs"; +import { readFileSync, existsSync, unlinkSync } from "node:fs"; import { join } from "node:path"; import chalk from "chalk"; @@ -60,23 +59,6 @@ for (const { output } of TARGETS) { unlinkSync(binaryPath); } -// --------------------------------------------------------------------------- -// 2. Generate SHA256 checksums -// --------------------------------------------------------------------------- -console.log(chalk.dim(" Generating checksums...")); - -for (const { output } of TARGETS) { - const archiveName = `${output.replace(/\.exe$/, "")}.tar.gz`; - const archivePath = join(BINARIES_DIR, archiveName); - const hasher = new Bun.CryptoHasher("sha256"); - hasher.update(readFileSync(archivePath)); - const hash = hasher.digest("hex"); - writeFileSync( - join(BINARIES_DIR, `${archiveName}.sha256`), - `${hash} ${archiveName}\n`, - ); -} - // --------------------------------------------------------------------------- // Done // --------------------------------------------------------------------------- From 69e4b4214476ea40a7176832b757d3e9c441140f Mon Sep 17 00:00:00 2001 From: Kfir Strikovsky Date: Wed, 11 Mar 2026 11:50:42 +0200 Subject: [PATCH 2/2] refresh manual publish action --- .github/workflows/manual-publish.yml | 154 ++++------------------ packages/cli/infra/homebrew/base44.rb | 8 +- packages/cli/infra/homebrew/update-tap.sh | 44 +++++++ 3 files changed, 71 insertions(+), 135 deletions(-) create mode 100755 packages/cli/infra/homebrew/update-tap.sh diff --git a/.github/workflows/manual-publish.yml b/.github/workflows/manual-publish.yml index 96c5a3e3..51da1f2f 100644 --- a/.github/workflows/manual-publish.yml +++ b/.github/workflows/manual-publish.yml @@ -71,44 +71,12 @@ jobs: - name: Install dependencies run: bun install --frozen-lockfile - - name: Check if version needs to be bumped - id: check-version - run: | - if [[ "${{ github.event.inputs.version }}" =~ ^(patch|minor|major)$ ]]; then - echo "bump_version=true" >> $GITHUB_OUTPUT - echo "version_type=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT - else - echo "bump_version=false" >> $GITHUB_OUTPUT - echo "version_type=" >> $GITHUB_OUTPUT - fi - - - name: Bump version - if: steps.check-version.outputs.bump_version == 'true' - working-directory: ${{ env.CLI_PACKAGE_DIR }} - run: | - npm version ${{ steps.check-version.outputs.version_type }} --no-git-tag-version - echo "NEW_VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_ENV - - - name: Set version manually - if: steps.check-version.outputs.bump_version == 'false' + - name: Set version working-directory: ${{ env.CLI_PACKAGE_DIR }} run: | npm version ${{ github.event.inputs.version }} --no-git-tag-version echo "NEW_VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_ENV - - name: Get previous release tag - id: prev-tag - run: | - PREV_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") - echo "tag=$PREV_TAG" >> $GITHUB_OUTPUT - echo "Previous tag: $PREV_TAG" - if [[ -n "$PREV_TAG" ]]; then - # Get the date of the previous tag in ISO format for filtering PRs - PREV_TAG_DATE=$(git log -1 --format=%aI "$PREV_TAG") - echo "date=$PREV_TAG_DATE" >> $GITHUB_OUTPUT - echo "Previous tag date: $PREV_TAG_DATE" - fi - - name: Build package run: bun run build working-directory: ${{ env.CLI_PACKAGE_DIR }} @@ -139,16 +107,9 @@ jobs: echo "Dry run: ${{ github.event.inputs.dry_run }}" - name: Publish to NPM - if: github.event.inputs.dry_run == 'false' working-directory: ${{ env.CLI_PACKAGE_DIR }} run: | - npm publish --tag ${{ github.event.inputs.npm_tag }} - - - name: Dry run publish - if: github.event.inputs.dry_run == 'true' - working-directory: ${{ env.CLI_PACKAGE_DIR }} - run: | - npm publish --dry-run --tag ${{ github.event.inputs.npm_tag }} + npm publish --tag ${{ github.event.inputs.npm_tag }} ${{ github.event.inputs.dry_run == 'true' && '--dry-run' || '' }} - name: Create Git tag if: github.event.inputs.dry_run == 'false' @@ -157,123 +118,54 @@ jobs: run: | git config --local user.email "action@github.com" git config --local user.name "GitHub Action" - # Re-configure git remote to use the App token for push git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git" git add ${{ env.CLI_PACKAGE_DIR }}/package.json - # Add CHANGELOG.md only if changelog update was requested - if [[ "${{ github.event.inputs.update_changelog }}" == "true" ]]; then - git add CHANGELOG.md - fi git commit -m "chore: release v${{ env.NEW_VERSION }}" git tag v${{ env.NEW_VERSION }} git push origin HEAD:${{ github.ref }} git push origin v${{ env.NEW_VERSION }} - - name: Create Release + - name: Create GitHub Release and upload binaries if: github.event.inputs.dry_run == 'false' - id: create-release - uses: actions/create-release@v1 env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: v${{ env.NEW_VERSION }} - release_name: Release v${{ env.NEW_VERSION }} - body: | - ## What's Changed - - This release includes the latest updates to the Base44 CLI. - - ### Installation - - **npm:** - ```bash - npm install -g base44@${{ github.event.inputs.npm_tag }} - ``` + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + run: | + RELEASE_URL=$(gh release create "v${{ env.NEW_VERSION }}" \ + --title "Release v${{ env.NEW_VERSION }}" \ + --notes "## Installation - **Homebrew:** - ```bash - brew install base44/tap/base44 - ``` + **npm:** + \`\`\`bash + npm install -g base44@${{ github.event.inputs.npm_tag }} + \`\`\` - ### Version: ${{ env.NEW_VERSION }} - ### NPM Tag: ${{ github.event.inputs.npm_tag }} - draft: false - prerelease: false + **Homebrew:** + \`\`\`bash + brew install base44/tap/base44 + \`\`\` - - name: Upload binaries to GitHub Release - if: github.event.inputs.dry_run == 'false' - env: - GH_TOKEN: ${{ steps.generate-token.outputs.token }} - run: | - for file in ${{ env.CLI_PACKAGE_DIR }}/dist/binaries/base44-*; do - echo "Uploading $file..." - gh release upload "v${{ env.NEW_VERSION }}" "$file" --clobber - done + **Version:** ${{ env.NEW_VERSION }} + **NPM Tag:** ${{ github.event.inputs.npm_tag }}" \ + ${{ env.CLI_PACKAGE_DIR }}/dist/binaries/base44-*.tar.gz) + echo "RELEASE_URL=$RELEASE_URL" >> $GITHUB_ENV - name: Update Homebrew Tap if: github.event.inputs.dry_run == 'false' && github.event.inputs.npm_tag == 'latest' env: GH_TOKEN: ${{ steps.generate-token.outputs.token }} - run: | - VERSION="${{ env.NEW_VERSION }}" - BINARIES_DIR="${{ env.CLI_PACKAGE_DIR }}/dist/binaries" - - SHA_DARWIN_ARM64=$(shasum -a 256 "$BINARIES_DIR/base44-darwin-arm64.tar.gz" | awk '{print $1}') - SHA_DARWIN_X64=$(shasum -a 256 "$BINARIES_DIR/base44-darwin-x64.tar.gz" | awk '{print $1}') - SHA_LINUX_ARM64=$(shasum -a 256 "$BINARIES_DIR/base44-linux-arm64.tar.gz" | awk '{print $1}') - SHA_LINUX_X64=$(shasum -a 256 "$BINARIES_DIR/base44-linux-x64.tar.gz" | awk '{print $1}') - - cp "${{ env.CLI_PACKAGE_DIR }}/infra/homebrew/base44.rb" /tmp/base44.rb - sed -i 's/version ".*"/version "'"$VERSION"'"/' /tmp/base44.rb - sed -i "s/PLACEHOLDER_DARWIN_ARM64/$SHA_DARWIN_ARM64/" /tmp/base44.rb - sed -i "s/PLACEHOLDER_DARWIN_X64/$SHA_DARWIN_X64/" /tmp/base44.rb - sed -i "s/PLACEHOLDER_LINUX_ARM64/$SHA_LINUX_ARM64/" /tmp/base44.rb - sed -i "s/PLACEHOLDER_LINUX_X64/$SHA_LINUX_X64/" /tmp/base44.rb - - rm -rf /tmp/homebrew-tap - git clone "https://x-access-token:${GH_TOKEN}@github.com/base44/homebrew-tap.git" /tmp/homebrew-tap - mkdir -p /tmp/homebrew-tap/Formula - cp /tmp/base44.rb /tmp/homebrew-tap/Formula/base44.rb - - cd /tmp/homebrew-tap - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git add Formula/base44.rb - if git diff --cached --quiet; then - echo "Homebrew formula already up to date" - exit 0 - fi - git commit -m "Update base44 to ${VERSION}" - git push origin master - - - name: Release summary - if: steps.prev-tag.outputs.tag != '' - run: | - if [ -f release-summary.md ]; then - cat release-summary.md | tee -a "$GITHUB_STEP_SUMMARY" - fi - - - name: Generate token for skills repo - if: github.event.inputs.dry_run == 'false' && github.event.inputs.notify_skills_repo == 'true' - id: skills-token - uses: actions/create-github-app-token@v2 - with: - app-id: ${{ vars.BASE44_GITHUB_ACTIONS_APP_ID }} - private-key: ${{ secrets.BASE44_GITHUB_ACTIONS_APP_PRIVATE_KEY }} - owner: base44 - repositories: skills + run: bash ${{ env.CLI_PACKAGE_DIR }}/infra/homebrew/update-tap.sh "${{ env.NEW_VERSION }}" "${{ env.CLI_PACKAGE_DIR }}/dist/binaries" - name: Notify skills repo if: github.event.inputs.dry_run == 'false' && github.event.inputs.notify_skills_repo == 'true' uses: peter-evans/repository-dispatch@v4 with: - token: ${{ steps.skills-token.outputs.token }} + token: ${{ steps.generate-token.outputs.token }} repository: base44/skills event-type: cli-release client-payload: | { "version": "v${{ env.NEW_VERSION }}", - "release_url": "${{ steps.create-release.outputs.html_url }}", + "release_url": "${{ env.RELEASE_URL }}", "release_name": "Release v${{ env.NEW_VERSION }}" } diff --git a/packages/cli/infra/homebrew/base44.rb b/packages/cli/infra/homebrew/base44.rb index f186e273..74cc987e 100644 --- a/packages/cli/infra/homebrew/base44.rb +++ b/packages/cli/infra/homebrew/base44.rb @@ -1,10 +1,10 @@ -# Homebrew formula for the Base44 CLI. +# Homebrew formula template for the Base44 CLI. # -# This is a reference template. Copy it to your homebrew-tap repository -# at Formula/base44.rb and update the version + SHA256 values on each release. +# CI renders this template with real version + SHA256 values and pushes it +# to base44/homebrew-tap via infra/homebrew/update-tap.sh. # # Users install with: -# brew install /tap/base44 +# brew install base44/tap/base44 # class Base44 < Formula desc "CLI for creating, managing, and deploying Base44 applications" diff --git a/packages/cli/infra/homebrew/update-tap.sh b/packages/cli/infra/homebrew/update-tap.sh new file mode 100755 index 00000000..07d21837 --- /dev/null +++ b/packages/cli/infra/homebrew/update-tap.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# +# Update the Homebrew tap formula with a new version and SHA256 checksums. +# +# Usage: GH_TOKEN= bash update-tap.sh +# +# The script: +# 1. Computes SHA256 for each platform archive +# 2. Renders the formula template (base44.rb) with the real values +# 3. Clones base44/homebrew-tap, commits, and pushes +# +set -euo pipefail + +VERSION="$1" +BINARIES_DIR="$2" +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" + +SHA_DARWIN_ARM64=$(shasum -a 256 "$BINARIES_DIR/base44-darwin-arm64.tar.gz" | awk '{print $1}') +SHA_DARWIN_X64=$(shasum -a 256 "$BINARIES_DIR/base44-darwin-x64.tar.gz" | awk '{print $1}') +SHA_LINUX_ARM64=$(shasum -a 256 "$BINARIES_DIR/base44-linux-arm64.tar.gz" | awk '{print $1}') +SHA_LINUX_X64=$(shasum -a 256 "$BINARIES_DIR/base44-linux-x64.tar.gz" | awk '{print $1}') + +cp "$SCRIPT_DIR/base44.rb" /tmp/base44.rb +sed -i "s/version \".*\"/version \"$VERSION\"/" /tmp/base44.rb +sed -i "s/PLACEHOLDER_DARWIN_ARM64/$SHA_DARWIN_ARM64/" /tmp/base44.rb +sed -i "s/PLACEHOLDER_DARWIN_X64/$SHA_DARWIN_X64/" /tmp/base44.rb +sed -i "s/PLACEHOLDER_LINUX_ARM64/$SHA_LINUX_ARM64/" /tmp/base44.rb +sed -i "s/PLACEHOLDER_LINUX_X64/$SHA_LINUX_X64/" /tmp/base44.rb + +rm -rf /tmp/homebrew-tap +git clone "https://x-access-token:${GH_TOKEN}@github.com/base44/homebrew-tap.git" /tmp/homebrew-tap +mkdir -p /tmp/homebrew-tap/Formula +cp /tmp/base44.rb /tmp/homebrew-tap/Formula/base44.rb + +cd /tmp/homebrew-tap +git config user.name "github-actions[bot]" +git config user.email "github-actions[bot]@users.noreply.github.com" +git add Formula/base44.rb +if git diff --cached --quiet; then + echo "Homebrew formula already up to date" + exit 0 +fi +git commit -m "Update base44 to ${VERSION}" +git push origin master