From 8b08ad0e46e16fa7fe0ec170e2abbc13e06e87ba Mon Sep 17 00:00:00 2001 From: "Adrian Alfred C. Bonpin" Date: Thu, 24 Sep 2026 04:14:11 +0800 Subject: [PATCH] chore(release): point the macOS fallback script and docs at GitHub (#39) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `scripts/release-mac.sh` still targeted the retired Gitea release flow: it looked for `.gitea/workflows/release.yml`, keyed off GITEA_SERVER/REPO_OWNER, and created/uploaded assets with `tea`. Releases are GitHub-only now, so the script uploads with `gh release upload --clobber` (a locally signed DMG pair supersedes the CI-built ones, which the next draft publish then ships). Also corrects the release docs, which contradicted each other: AGENTS.md said macOS is built manually and never in CI, while README said CI signs it. In reality the `release.yml` macOS jobs sign + notarize when the APPLE_* secrets are present and log a `notice` when they are not — so the checklist now says to read the run output before publishing a draft (verified on v0.8.1: stapler validate + spctl report `source=Notarized Developer ID`), lists the local `scripts/release-mac.sh` as the fallback, and documents the cask bump that the `release: published` event triggers. The "keep versions in sync" checklist was also incomplete and had already been the source of drift: it missed `desktop/src-tauri/Cargo.lock` (only the `gridline` entry — the sqlx family shares 0.8.x), `www/public/landing.js`, the site changelog, `bundle-config.test.ts`, the two README banners and the MAINTENANCE comment. --- AGENTS.md | 10 +++++--- README.md | 2 +- scripts/release-mac.sh | 56 +++++++++++++++++++++--------------------- 3 files changed, 35 insertions(+), 33 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index f907235..5f63d7b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -189,11 +189,13 @@ Direct pushes to `prod` will be bypassed only in emergencies; prefer the PR path **Releases are GitHub-only.** Tag `prod` and push the tag to the `github` remote — `git tag vN.M.N && git push github vN.M.N`. GitHub Actions (`release.yml`) builds installers for macOS (Apple Silicon + Intel), Windows, and Linux and opens a **draft** release (review + publish on GitHub). The Gitea tag arrives automatically via the `pre-push` hook (or `scripts/mirror-gitea.sh`) — never `git push origin vN.M.N` expecting a build, and never publish a release on Gitea. **Before tagging**, keep everything in sync: -- Version number across `desktop/package.json`, `desktop/src-tauri/Cargo.toml`, `desktop/src-tauri/tauri.conf.json`, and `www/src/pages/index.astro` (the landing page version string) -- `desktop/src/lib/version.test.ts` and `desktop/src/lib/docs-coverage.test.ts` if they assert the version -- **README download links are static (versioned)** — both download tables (top **Download** section + **Which file should I download?**) link directly to the release-tag assets (`releases/download/v0.7.9/`). tauri-action uses default versioned asset names (`Gridline__aarch64.dmg`, `Gridline--1.x86_64.rpm`, etc.) — update BOTH tables to the new names on every release (see the MAINTENANCE comment in README.md). +- Version number across `desktop/package.json`, `desktop/src-tauri/Cargo.toml` (+ the `gridline` entry in `desktop/src-tauri/Cargo.lock` — run any `cargo metadata`/`cargo build` to sync it; do NOT blanket-replace `0.8.x` in the lock, the sqlx family shares that version), `desktop/src-tauri/tauri.conf.json` +- Landing page version strings: `www/src/pages/index.astro` and `www/public/landing.js` (both carry a `const version`), plus the new entry at the top of `www/src/data/changelog.ts` +- Tests that assert the version: `desktop/src/lib/version.test.ts`, `desktop/src/lib/bundle-config.test.ts`, `desktop/src/lib/docs-coverage.test.ts` (this one also asserts the README's asset names and the landing `const version`) +- **README download links are static (versioned)** — both download tables (top **Download** section + **Which file should I download?**) link directly to the release-tag assets (`releases/download/v0.8.1/`). tauri-action uses default versioned asset names (`Gridline__aarch64.dmg`, `Gridline--1.x86_64.rpm`, etc.) — update BOTH tables, the two "current release (**vX.Y.Z**)" banners, and the MAINTENANCE comment on every release. - **Bundled pg tools:** `tauri.conf.json` `bundle.resources` lists `resources/pg_tools/*`; the `release.yml` matrix builds/downloads + checksum-verifies the static binaries before the Tauri build step. -- **macOS is Developer-ID signed + notarized** via `scripts/release-mac.sh` (built manually on Adrian's machine; not in CI). The script auto-detects the Developer ID identity from the login keychain, reads notarization credentials from `~/.config/gridline/notarize.env` (App Store Connect API key), and verifies codesign + stapled notarization before uploading. If the cert or credentials are missing it fails with setup instructions (see the README's "macOS signing & notarization" section). +- **macOS is Developer-ID signed + notarized in CI** from the repository secrets (`APPLE_CERTIFICATE`, `APPLE_CERTIFICATE_PASSWORD`, `APPLE_SIGNING_IDENTITY`, `APPLE_API_KEY`, `APPLE_API_ISSUER`, `APPLE_API_KEY_CONTENT`, `KEYCHAIN_PASSWORD`) — the workflow logs a `notice` when they are absent and falls back to ad-hoc, so **check the run output before publishing a draft**. Verify a published DMG with `xcrun stapler validate ` plus `spctl --assess --type execute` on the `.app` inside (`source=Notarized Developer ID`). `scripts/release-mac.sh` is the **local fallback**: it auto-detects the Developer ID identity from the login keychain, reads notarization credentials from `~/.config/gridline/notarize.env`, signs + notarizes + staples both architectures, verifies the result, then uploads to the **GitHub** release with `gh release upload --clobber`. +- **After publishing the draft**, the `release: published` event runs the cask bump (`HOMEBREW_TAP_DEPLOY_KEY` pushes `Casks/gridline.rb` to `AdrianBonpin/homebrew-gridline`). Verify the cask `version` + `sha256` match the published DMGs. ### Adding a Tauri Command diff --git a/README.md b/README.md index d2fe4f2..0ee9e64 100644 --- a/README.md +++ b/README.md @@ -340,7 +340,7 @@ Gridline's macOS builds are **Developer-ID signed and notarized by GitHub Action When these secrets are absent the macOS jobs still build, but the DMGs are ad-hoc signed and **not** notarized (users get the “Open Anyway” prompt). The CI re-signs the bundled PostgreSQL/MariaDB client binaries with the same Developer ID identity, because Apple rejects ad-hoc-signed nested executables during notarization. -`scripts/release-mac.sh` is the **local fallback** path (used before GitHub Actions took over macOS builds, and still handy for a signed build without burning CI minutes). It auto-detects the Developer ID identity from your keychain, reads notarization credentials from `~/.config/gridline/notarize.env` (`APPLE_API_KEY`, `APPLE_API_ISSUER`, `APPLE_API_KEY_PATH`), signs both architectures, notarizes + staples them, and verifies the result before uploading. If the certificate or credentials are missing it fails with instructions (set `GRIDLINE_SKIP_NOTARIZE=1` to build signed-but-unnotarized for testing only). +`scripts/release-mac.sh` is the **local fallback** path (handy for a signed build without burning CI minutes, or when Actions is unavailable). It auto-detects the Developer ID identity from your keychain, reads notarization credentials from `~/.config/gridline/notarize.env` (`APPLE_API_KEY`, `APPLE_API_ISSUER`, `APPLE_API_KEY_PATH`), signs both architectures, notarizes + staples them, verifies the result, then uploads the DMGs to the **GitHub** release for the tag (`gh release upload --clobber`, so a locally signed pair supersedes the CI-built ones — publish the draft afterwards). If the certificate or credentials are missing it fails with instructions (set `GRIDLINE_SKIP_NOTARIZE=1` to build signed-but-unnotarized for testing only). **Windows** still shows a SmartScreen prompt (no Windows signing cert yet); **Linux** installs without a warning. diff --git a/scripts/release-mac.sh b/scripts/release-mac.sh index c7aba78..340b8ec 100755 --- a/scripts/release-mac.sh +++ b/scripts/release-mac.sh @@ -1,25 +1,29 @@ #!/usr/bin/env bash # -# Build Gridline for macOS on this machine and upload the DMGs to the Gitea -# release for a given tag. macOS is built manually (NOT auto-built on tag); -# the Linux and Windows installers are built by the Gitea Actions workflow -# (.gitea/workflows/release.yml) and already uploaded to the same release. +# LOCAL FALLBACK: build Gridline for macOS on this machine and upload the signed +# + notarized DMGs to the GitHub release for a given tag. +# +# macOS is normally built, Developer-ID signed and notarized by GitHub Actions +# (.github/workflows/release.yml) using the APPLE_* repository secrets, together +# with the Windows and Linux installers. Reach for this script when you want a +# signed build without spending CI minutes, or when Actions is unavailable. # # Usage: -# TAG=v0.7.11 ./scripts/release-mac.sh +# TAG=v0.8.1 ./scripts/release-mac.sh # -# The release is keyed by tag. The Linux/Windows job creates it on the first -# tag push; this script finds it (creating it only if it somehow doesn't exist) -# and attaches the two DMGs: Gridline__aarch64.dmg and Gridline__x64.dmg +# The release is keyed by tag: the Actions job creates the draft on a tag push, +# and this script finds it (creating it only if it somehow doesn't exist) and +# attaches/replaces the two DMGs — Gridline__aarch64.dmg and +# Gridline__x64.dmg. Uploads use --clobber, so a locally signed DMG +# supersedes the CI one; publish the draft afterwards on GitHub. # -# Auth: uses the `tea` CLI (OAuth token, auto-refreshed). +# Auth: the `gh` CLI (GitHub is the only release target; the Gitea mirror is +# code-only). set -euo pipefail # ---- config --------------------------------------------------------------- -GITEA_SERVER="${GITEA_SERVER:-https://git.ranio.xyz}" -REPO_OWNER="${REPO_OWNER:-adrianbonpin}" -REPO_NAME="${REPO_NAME:-gridline}" +GH_REPO="${GH_REPO:-AdrianBonpin/gridline}" TAG="${TAG:-${1:-}}" if [ -z "$TAG" ]; then @@ -27,13 +31,10 @@ if [ -z "$TAG" ]; then exit 1 fi -# ---- resolve auth (tea CLI) ------------------------------------------------ -# The `tea` CLI carries the OAuth token and refreshes it automatically, so the -# release upload below uses `tea` rather than a raw curl + token. (The git -# credential store can hold a stale access token and 401.) -if ! command -v tea >/dev/null 2>&1; then - echo "error: tea CLI not found (needed to upload release assets)" >&2 - echo " install it: https://gitea.com/gitea/tea" >&2 +# ---- resolve auth (gh CLI) ------------------------------------------------- +if ! command -v gh >/dev/null 2>&1; then + echo "error: gh CLI not found (needed to upload release assets)" >&2 + echo " install it: https://cli.github.com" >&2 exit 1 fi @@ -229,21 +230,20 @@ else fi # ---- create/ensure release + upload DMGs ----------------------------------- -# Use `tea` for release management — it handles OAuth token refresh, unlike a -# raw curl with a token from the git credential store (which can 401). cd "${WORKSPACE}" -echo ">> Ensuring release ${TAG} exists..." -if ! tea release list -o json 2>/dev/null | grep -q "\"${TAG}\""; then - tea release create --tag "${TAG}" --title "Gridline ${VERSION}" \ - --note "Gridline ${VERSION} — macOS (built manually)." --draft +echo ">> Ensuring release ${TAG} exists on ${GH_REPO}..." +if ! gh release view "${TAG}" --repo "${GH_REPO}" >/dev/null 2>&1; then + gh release create "${TAG}" --repo "${GH_REPO}" --title "Gridline ${VERSION}" \ + --notes "Gridline ${VERSION} — macOS (built locally, signed + notarized)." --draft else echo ">> Release ${TAG} already exists." fi -echo ">> Uploading macOS DMGs..." -tea releases assets create "${TAG}" \ +# --clobber replaces the CI-built (ad-hoc) DMGs with this signed + notarized pair. +echo ">> Uploading macOS DMGs (replacing any existing ones)..." +gh release upload "${TAG}" --repo "${GH_REPO}" --clobber \ "${BUNDLE_ARM}/dmg/Gridline_${VERSION}_aarch64.dmg" \ "${BUNDLE_INTEL}/dmg/Gridline_${VERSION}_x64.dmg" -echo "Done. Release: ${GITEA_SERVER}/${REPO_OWNER}/${REPO_NAME}/releases/tag/${TAG}" +echo "Done. Review + publish the draft: https://github.com/${GH_REPO}/releases/tag/${TAG}"