feat: seed Homebrew formula + auto-update workflow
Mirror of installer/homebrew/fai.rb in fai/platform. Source of truth is the platform repo; this is a passive distribution mirror. Auto-update workflow at .forgejo/workflows/update.yml runs every 4 hours, diffs the latest platform release against Formula/fai.rb, and rewrites version + sha256 when a new version ships. Manual trigger via workflow_dispatch. Users install with: brew tap fai/tap https://git.flemming.ai/fai/homebrew-tap brew install fai End-state matches Phase 1 of docs/releases/go-live-checklist.md.
This commit is contained in:
commit
1c0eb6c668
3 changed files with 236 additions and 0 deletions
133
.forgejo/workflows/update.yml
Normal file
133
.forgejo/workflows/update.yml
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
# Auto-update workflow for the fai/homebrew-tap repo.
|
||||
#
|
||||
# Lives here as the canonical source of truth. The bootstrap
|
||||
# script (scripts/bootstrap-distribution-repos.sh in
|
||||
# fai/platform) seeds this file into the tap repo at
|
||||
# .forgejo/workflows/update.yml. Edit it here, run the
|
||||
# bootstrap script, the tap repo picks up the new version.
|
||||
#
|
||||
# What it does:
|
||||
# * Every 4 hours, fetches the latest release manifest for
|
||||
# fai/platform.
|
||||
# * If the version differs from the one currently in
|
||||
# Formula/fai.rb, rewrites the formula's version + sha256
|
||||
# entries (macos-aarch64 + macos-x86_64) and commits.
|
||||
# * Workflow_dispatch trigger lets you force an update from
|
||||
# the Forgejo UI without waiting for the cron tick.
|
||||
#
|
||||
# Manifest contract: fai/platform's release.yml writes
|
||||
# .binaries.{macos-aarch64,macos-x86_64}.sha256 — see
|
||||
# crates/fai_hub/src/update.rs::ReleaseManifest for the
|
||||
# authoritative schema.
|
||||
|
||||
name: Update Homebrew formula
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 */4 * * *'
|
||||
workflow_dispatch: {}
|
||||
|
||||
jobs:
|
||||
update:
|
||||
name: Sync formula to latest platform release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout via external URL
|
||||
run: |
|
||||
set -eu
|
||||
mkdir -p "$GITHUB_WORKSPACE"
|
||||
cd "$GITHUB_WORKSPACE"
|
||||
git init -q
|
||||
git remote add origin \
|
||||
"https://x-access-token:${GITHUB_TOKEN}@git.flemming.ai/${GITHUB_REPOSITORY}.git"
|
||||
git fetch --depth=1 origin "$GITHUB_REF_NAME"
|
||||
git checkout -q FETCH_HEAD
|
||||
|
||||
- name: Install jq + curl
|
||||
run: |
|
||||
apt-get update -qq
|
||||
apt-get install -y --no-install-recommends jq curl ca-certificates
|
||||
|
||||
- name: Fetch latest manifest
|
||||
id: manifest
|
||||
run: |
|
||||
set -eu
|
||||
# Forgejo's releases API returns newest-first.
|
||||
REL=$(curl -fsSL \
|
||||
"https://git.flemming.ai/api/v1/repos/fai/platform/releases?limit=1" \
|
||||
| jq -r '.[0]')
|
||||
TAG=$(echo "$REL" | jq -r '.tag_name')
|
||||
VERSION="${TAG#v}"
|
||||
MANIFEST=$(curl -fsSL \
|
||||
"https://git.flemming.ai/fai/platform/releases/download/${TAG}/manifest.json")
|
||||
MAC_ARM=$(echo "$MANIFEST" | jq -r '.binaries["macos-aarch64"].sha256 // empty')
|
||||
MAC_X64=$(echo "$MANIFEST" | jq -r '.binaries["macos-x86_64"].sha256 // empty')
|
||||
if [ -z "$MAC_ARM" ] || [ -z "$MAC_X64" ]; then
|
||||
echo "manifest for $TAG has no macOS entries yet — likely the local"
|
||||
echo "publish step hasn't run. Skipping update."
|
||||
echo "skip=true" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
echo "sha_aarch64=$MAC_ARM" >> "$GITHUB_OUTPUT"
|
||||
echo "sha_x86_64=$MAC_X64" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Detect formula version
|
||||
id: current
|
||||
if: steps.manifest.outputs.skip != 'true'
|
||||
run: |
|
||||
CUR=$(grep -E '^\s*version\s+"' Formula/fai.rb \
|
||||
| head -1 | sed -E 's/.*"([^"]+)".*/\1/')
|
||||
echo "version=$CUR" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Rewrite Formula/fai.rb
|
||||
id: rewrite
|
||||
if: |
|
||||
steps.manifest.outputs.skip != 'true'
|
||||
&& steps.manifest.outputs.version != steps.current.outputs.version
|
||||
env:
|
||||
NEW_VERSION: ${{ steps.manifest.outputs.version }}
|
||||
NEW_SHA_AARCH64: ${{ steps.manifest.outputs.sha_aarch64 }}
|
||||
NEW_SHA_X86_64: ${{ steps.manifest.outputs.sha_x86_64 }}
|
||||
run: |
|
||||
set -eu
|
||||
python3 - <<'PY'
|
||||
import os, re, pathlib
|
||||
p = pathlib.Path("Formula/fai.rb")
|
||||
src = p.read_text()
|
||||
new_version = os.environ["NEW_VERSION"]
|
||||
arm_sha = os.environ["NEW_SHA_AARCH64"]
|
||||
x64_sha = os.environ["NEW_SHA_X86_64"]
|
||||
# version line
|
||||
src = re.sub(r'(\bversion\s+)"[^"]+"',
|
||||
f'\\1"{new_version}"', src, count=1)
|
||||
# find the two sha256 lines, one in the arm branch, one in
|
||||
# the else branch. The formula's structure is fixed —
|
||||
# aarch64 block comes first.
|
||||
lines = src.splitlines()
|
||||
replaced = 0
|
||||
for i, line in enumerate(lines):
|
||||
m = re.match(r'(\s*sha256\s+)"[^"]+"', line)
|
||||
if not m:
|
||||
continue
|
||||
sha = arm_sha if replaced == 0 else x64_sha
|
||||
lines[i] = f'{m.group(1)}"{sha}"'
|
||||
replaced += 1
|
||||
if replaced == 2:
|
||||
break
|
||||
if replaced != 2:
|
||||
raise SystemExit(f"expected 2 sha256 lines, rewrote {replaced}")
|
||||
p.write_text("\n".join(lines) + "\n")
|
||||
PY
|
||||
echo "rewritten=true" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Commit + push
|
||||
if: steps.rewrite.outputs.rewritten == 'true'
|
||||
env:
|
||||
NEW_VERSION: ${{ steps.manifest.outputs.version }}
|
||||
run: |
|
||||
set -eu
|
||||
git config user.email "platform@flemming.ai"
|
||||
git config user.name "fai-tap-bot"
|
||||
git add Formula/fai.rb
|
||||
git commit -s -m "chore: formula -> v${NEW_VERSION}"
|
||||
git push origin "HEAD:${GITHUB_REF_NAME}"
|
||||
78
Formula/fai.rb
Normal file
78
Formula/fai.rb
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
# Homebrew formula skeleton for the F∆I Platform CLI.
|
||||
#
|
||||
# Lives in this repo as the canonical source — the actual
|
||||
# distribution is a checkout of `fai/homebrew-tap` (a separate
|
||||
# Forgejo repo, seeded by
|
||||
# `scripts/bootstrap-distribution-repos.sh`) that carries a copy
|
||||
# of this file at `Formula/fai.rb`. The tap repo's
|
||||
# `.forgejo/workflows/update.yml` (sourced from
|
||||
# `installer/homebrew/forgejo-workflow-update.yml` in this repo)
|
||||
# auto-bumps the version + sha256 entries against each new
|
||||
# platform release on a 4-hourly cron.
|
||||
#
|
||||
# To install a release from the tap:
|
||||
#
|
||||
# brew tap fai/tap https://git.flemming.ai/fai/homebrew-tap
|
||||
# brew install fai
|
||||
#
|
||||
# To install from this checkout for testing:
|
||||
#
|
||||
# brew install --build-from-source ./installer/homebrew/fai.rb
|
||||
#
|
||||
# This file is a *skeleton*. The :url / :sha256 placeholders are
|
||||
# populated by the release pipeline once macOS builds land on the
|
||||
# Forgejo Release page. The class name (`Fai`) is what Homebrew
|
||||
# uses to address the formula; lowercase `fai` is the binary on
|
||||
# disk after install.
|
||||
|
||||
class Fai < Formula
|
||||
desc "Deterministic workflow engine for AI-assisted data " \
|
||||
"processing in regulated environments"
|
||||
homepage "https://flemming.ai"
|
||||
version "0.12.1"
|
||||
license "Apache-2.0"
|
||||
|
||||
# Platform-specific binary URLs + sha256 are filled in per
|
||||
# release. cargo-zigbuild-built linux artefacts come from the
|
||||
# same release; the formula consumes them on Apple Silicon and
|
||||
# Intel macs via stanza selectors.
|
||||
if Hardware::CPU.arm?
|
||||
url "https://git.flemming.ai/fai/platform/releases/download/" \
|
||||
"v#{version}/fai-macos-aarch64"
|
||||
sha256 "REPLACE_WITH_AARCH64_SHA256_FROM_MANIFEST"
|
||||
else
|
||||
url "https://git.flemming.ai/fai/platform/releases/download/" \
|
||||
"v#{version}/fai-macos-x86_64"
|
||||
sha256 "REPLACE_WITH_X86_64_SHA256_FROM_MANIFEST"
|
||||
end
|
||||
|
||||
# Plain binary — no source build needed. We rely on the upstream
|
||||
# CI to have produced + signed it. Notarization is a separate
|
||||
# follow-up.
|
||||
def install
|
||||
bin.install Dir["*"].first => "fai"
|
||||
end
|
||||
|
||||
# `brew test fai` runs this — keeps the formula honest. We don't
|
||||
# start the daemon; we only verify the binary is callable.
|
||||
test do
|
||||
assert_match version.to_s, shell_output("#{bin}/fai --version")
|
||||
end
|
||||
|
||||
def caveats
|
||||
<<~EOS
|
||||
The F∆I daemon is not started automatically. After install:
|
||||
|
||||
fai bootstrap # writes ~/.fai/ layout + PATH marker
|
||||
fai daemon start # starts the local hub
|
||||
fai install debug.echo # smoke-test the install path
|
||||
|
||||
For Studio, install separately from
|
||||
https://flemming.ai/get.
|
||||
|
||||
Note: this binary is not yet notarized. macOS Gatekeeper will
|
||||
ask for confirmation on first launch. The notarization step
|
||||
is tracked as the remaining half of system-gap S-16.
|
||||
EOS
|
||||
end
|
||||
end
|
||||
25
README.md
Normal file
25
README.md
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# homebrew-tap
|
||||
|
||||
Distribution mirror for the [F∆I Platform](https://git.flemming.ai/fai/platform).
|
||||
|
||||
This repo holds one file — `Formula/fai.rb` — which is a copy of
|
||||
[`installer/homebrew/fai.rb`](https://git.flemming.ai/fai/platform/src/branch/main/installer/homebrew/fai.rb)
|
||||
in the platform repo. The platform repo is the source of
|
||||
truth; this repo exists as a separate target so end users can
|
||||
add it as a tap / bucket / channel without subscribing to
|
||||
the whole platform tree.
|
||||
|
||||
Updates land here automatically via
|
||||
`.forgejo/workflows/update.yml` — a 4-hourly cron that
|
||||
diffs the latest platform release against this repo's
|
||||
manifest and rewrites it when a new version ships. To force
|
||||
an immediate update, trigger the **Workflow_dispatch** action
|
||||
in the Forgejo UI.
|
||||
|
||||
When the workflow itself or the underlying manifest format
|
||||
changes, re-seed from the platform repo by running
|
||||
`scripts/bootstrap-distribution-repos.sh`.
|
||||
|
||||
Issues, PRs, and ad-hoc questions belong at
|
||||
`https://git.flemming.ai/fai/platform` — this repo is intentionally
|
||||
quiet.
|
||||
Loading…
Add table
Add a link
Reference in a new issue