name: Release # Builds Gridline installers for macOS (Apple Silicon + Intel), Windows, and # Linux, then uploads them to a draft GitHub Release. # # Trigger: push a version tag from the `prod` branch (production), e.g. # git checkout prod && git pull # git tag v0.5.0 && git push origin v0.5.0 # # SIGNING STATUS: this is the ACTIVE release path. macOS is Developer-ID # signed + notarized in CI when the Apple secrets below are configured (see # README "macOS signing & notarization"). When the secrets are absent the mac # jobs still build, but ad-hoc signed / unnotarized. Linux/Windows installers # remain unsigned. # # Required secrets for signed + notarized macOS builds: # APPLE_CERTIFICATE base64 of the Developer ID Application .p12 # APPLE_CERTIFICATE_PASSWORD password for that .p12 # APPLE_SIGNING_IDENTITY "Developer ID Application: Name (TEAMID)" # KEYCHAIN_PASSWORD any throwaway password for the temp keychain # APPLE_API_KEY App Store Connect Key ID # APPLE_API_ISSUER App Store Connect Issuer ID # APPLE_API_KEY_CONTENT contents of the AuthKey_.p8 # # The cask bump runs only after the draft release is PUBLISHED (the GitHub # releases/tags API does not serve drafts), so it is wired to the `release: # published` event rather than the tag push. It pushes with a write-enabled # deploy key scoped to ONLY the tap repo (HOMEBREW_TAP_DEPLOY_KEY), so no # broad personal access token is stored — the default GITHUB_TOKEN cannot # push to a different repository. on: push: tags: - 'v*' release: types: [published] # Rebuild an EXISTING tag without moving it — e.g. to re-run a release after # a workflow fix. Dispatch from `prod` and pass the tag to build; the tag # itself is never rewritten, so the release ref stays truthful. workflow_dispatch: inputs: tag: description: 'Tag to build or bump the cask for, e.g. v0.8.0' required: true bump_cask: description: 'Only bump the Homebrew cask for `tag` (skip the build)' type: boolean default: false permissions: contents: write env: # workflow_dispatch passes the tag as an input; push/release events derive it # from the ref. Drives the checkout ref and tauri-action's tagName. RELEASE_TAG: ${{ github.event.inputs.tag || github.ref_name }} jobs: publish: # Build + draft release happen on a tag push or a dispatch that isn't a # cask-only run. The `release: published` event exists only to trigger the # cask bump below. if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.bump_cask != true) env: # Empty when the secret is unset — the tool steps below test for a # non-empty value before re-signing. APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} strategy: fail-fast: false matrix: include: - platform: macos-latest # Apple Silicon (M1/M2/M3+) args: --target aarch64-apple-darwin - platform: macos-15-intel # Intel Macs (last Intel runner; retired ~Aug 2027) args: --target x86_64-apple-darwin - platform: ubuntu-22.04 # Linux x86_64 (.deb / .rpm / .AppImage) args: '' - platform: windows-latest # Windows x86_64 (NSIS .exe + .msi) args: '' runs-on: ${{ matrix.platform }} steps: - name: Checkout uses: actions/checkout@v4 with: ref: ${{ env.RELEASE_TAG }} # ---- Apple signing setup (macOS only, skipped when secrets absent) --- - name: Detect Apple signing secrets id: apple shell: bash run: | if [ -n "${{ secrets.APPLE_CERTIFICATE }}" ]; then echo "enabled=true" >> "$GITHUB_OUTPUT" else echo "enabled=false" >> "$GITHUB_OUTPUT" echo "::notice::APPLE_CERTIFICATE not set — macOS build will be ad-hoc signed and NOT notarized." fi # The bundled pg/mariadb tools are re-signed in their own steps below, so # the identity must be in a keychain BEFORE those steps run. tauri-action # is deliberately NOT given APPLE_CERTIFICATE (only the identity), so it # does not create a second keychain. - name: Import Apple Developer ID certificate if: startsWith(matrix.platform, 'macos') && steps.apple.outputs.enabled == 'true' shell: bash env: APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} run: | set -euo pipefail KEYCHAIN="gridline-signing.keychain-db" echo "$APPLE_CERTIFICATE" | base64 --decode > "$RUNNER_TEMP/cert.p12" security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN" security set-keychain-settings -lut 21600 "$KEYCHAIN" security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN" security import "$RUNNER_TEMP/cert.p12" -k "$KEYCHAIN" \ -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign security set-key-partition-list -S apple-tool:,apple:,codesign: \ -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN" >/dev/null EXISTING="$(security list-keychain -d user | tr -d ' \"')" security list-keychain -d user -s "$KEYCHAIN" $EXISTING rm -f "$RUNNER_TEMP/cert.p12" security find-identity -v -p codesigning - name: Prepare notarization credentials if: startsWith(matrix.platform, 'macos') && steps.apple.outputs.enabled == 'true' shell: bash env: APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }} APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} APPLE_API_KEY_CONTENT: ${{ secrets.APPLE_API_KEY_CONTENT }} run: | set -euo pipefail KEY_PATH="$RUNNER_TEMP/private_keys/AuthKey_${APPLE_API_KEY}.p8" mkdir -p "$(dirname "$KEY_PATH")" # Apple's PEM parser expects a terminating newline, which # `gh secret set` strips from the stored value — so write one # explicitly. A doubled trailing newline is harmless to PEM parsers, # but a missing one can make notarization fail to load the key. printf '%s\n' "$APPLE_API_KEY_CONTENT" > "$KEY_PATH" { echo "APPLE_API_KEY=${APPLE_API_KEY}" echo "APPLE_API_ISSUER=${APPLE_API_ISSUER}" echo "APPLE_API_KEY_PATH=${KEY_PATH}" } >> "$GITHUB_ENV" - name: Install Linux dependencies if: matrix.platform == 'ubuntu-22.04' run: | sudo apt-get update sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf - name: Set up Bun uses: oven-sh/setup-bun@v2 - name: Set up Rust uses: dtolnay/rust-toolchain@stable with: targets: aarch64-apple-darwin, x86_64-apple-darwin - name: Cache Rust build artifacts uses: swatinem/rust-cache@v2 with: workspaces: './desktop/src-tauri -> target' - name: Install frontend dependencies run: bun install --frozen-lockfile - name: Build PostgreSQL client tools (bundled) shell: bash run: | set -euo pipefail PG_VER="16.4" OUT="${GITHUB_WORKSPACE}/desktop/src-tauri/resources/pg_tools" mkdir -p "$OUT" case "${{ matrix.platform }}" in ubuntu-22.04) sudo apt-get update -y sudo apt-get install -y build-essential libreadline-dev zlib1g-dev flex bison patchelf curl -fsSL "https://ftp.postgresql.org/pub/source/v${PG_VER}/postgresql-${PG_VER}.tar.bz2" -o /tmp/pg.tar.bz2 tar -xf /tmp/pg.tar.bz2 -C /tmp cd /tmp/postgresql-${PG_VER} ./configure --prefix=/tmp/pgbuild --without-readline --without-icu CFLAGS="-O2" # Build the shared prerequisites (catalog headers + libpq/common/ # port archives) SERIALLY FIRST. Parallel `make -C` runs recurse # into src/common concurrently and race `rm -f` / `ar crs` on the # same .a — intermittently failing with 'ar: libpgcommon_srv.a: # file format not recognized'. Once the archives exist, the tools' # -j builds find them up to date and those recursions are no-ops. make -C src/backend generated-headers make -C src/interfaces/libpq all make -j"$(nproc)" -C src/bin/pg_dump all make -j"$(nproc)" -C src/bin/psql all cp src/bin/pg_dump/pg_dump src/bin/pg_dump/pg_restore "$OUT"/ cp src/bin/psql/psql "$OUT"/ # pg_dump links shared libpq (PG16 has no --disable-shared for the # client tools); bundle libpq.so alongside and point the loader at # the app's resource dir via $ORIGIN rpath. cp src/interfaces/libpq/libpq.so.5 "$OUT"/libpq.so.5 for b in pg_dump pg_restore psql; do patchelf --set-rpath '$ORIGIN' "$OUT/$b" done ;; macos-latest|macos-15-intel) curl -fsSL "https://ftp.postgresql.org/pub/source/v${PG_VER}/postgresql-${PG_VER}.tar.bz2" -o /tmp/pg.tar.bz2 tar -xf /tmp/pg.tar.bz2 -C /tmp cd /tmp/postgresql-${PG_VER} # ac_cv_func_strchrnul=no: Xcode 16.4's SDK marks strchrnul as # introduced in macOS 15.4, so configure detects it and PG's # snprintf.c calls the system symbol — which fails to compile # (-Werror=unguarded-availability-new) and would crash at runtime # on macOS < 15.4. Forcing the check off makes PG use its own # inline fallback instead. ac_cv_func_strchrnul=no ./configure --prefix=/tmp/pgbuild --without-readline --without-icu CFLAGS="-O2" # macOS SDKs always declare strchrnul in (Xcode 16.4 # marks it 'introduced in macOS 15.4'), so even with HAVE_STRCHRNUL # disabled PG16's static-inline fallback would collide with the # header declaration on newer SDKs. Rename PG's fallback so the # tools compile on any SDK and never touch the (15.4+ only) # system symbol. sed -i '' 's/strchrnul/pg_strchrnul/g' src/port/snprintf.c # Serial shared-prerequisite build first (see the Linux block: the # archives must exist before the -j tool builds recurse into # src/common). make -C src/backend generated-headers make -C src/interfaces/libpq all make -j"$(sysctl -n hw.ncpu)" -C src/bin/pg_dump all make -j"$(sysctl -n hw.ncpu)" -C src/bin/psql all cp src/bin/pg_dump/pg_dump src/bin/pg_dump/pg_restore "$OUT"/ cp src/bin/psql/psql "$OUT"/ cp src/interfaces/libpq/libpq.5.dylib "$OUT"/libpq.5.dylib # Rewrite the absolute /tmp/pgbuild libpq install_name to a # relative @loader_path so the tools find libpq next to themselves. for b in pg_dump pg_restore psql; do libpq=$(otool -L "$OUT/$b" | awk '/libpq/ {print $1; exit}') install_name_tool -change "$libpq" "@loader_path/libpq.5.dylib" "$OUT/$b" done # install_name_tool invalidates the linker signature. Re-sign with # the Developer ID identity + hardened runtime + secure timestamp: # Apple rejects ad-hoc-signed nested executables at notarization. # No-op until the Apple secrets are configured. if [ -n "${APPLE_SIGNING_IDENTITY:-}" ]; then for f in "$OUT"/pg_dump "$OUT"/pg_restore "$OUT"/psql "$OUT"/libpq.5.dylib; do codesign --force --options runtime --timestamp \ --sign "$APPLE_SIGNING_IDENTITY" "$f" done fi ;; windows-latest) URL="https://get.enterprisedb.com/postgresql/postgresql-${PG_VER}-1-windows-x64-binaries.zip" curl -fsSL "$URL" -o /tmp/pg.zip EXPECTED="3508d8f085bc3980f38211a82e3f31e5fcae9952105d3dc2f8be67b64a822baa" echo "$EXPECTED /tmp/pg.zip" | sha256sum -c - sha256sum /tmp/pg.zip unzip -o /tmp/pg.zip -d /tmp/pg cp /tmp/pg/pgsql/bin/pg_dump.exe /tmp/pg/pgsql/bin/pg_restore.exe /tmp/pg/pgsql/bin/psql.exe "$OUT"/ # pg_dump.exe needs far more than libpq.dll (libcrypto-3-x64.dll, # libssl-3-x64.dll, libiconv-2.dll, libintl-9.dll, # libwinpthread-1.dll, liblz4.dll, libzstd.dll, ICU DLLs, ...); # copy every DLL next to the tools. cp /tmp/pg/pgsql/bin/*.dll "$OUT"/ ;; esac (cd "$OUT" && sha256sum * | tee checksums.txt) # Resolve the per-platform binary suffix WITHOUT a command # substitution: `$( [ ... ] && echo .exe )` returns exit 1 when the # test is false, and under `set -e` that aborts the whole step. if [ "${{ matrix.platform }}" = windows-latest ]; then BIN_EXT=".exe" else BIN_EXT="" fi for b in pg_dump pg_restore psql; do f="$OUT/${b}${BIN_EXT}" test -f "$f" || { echo "missing $f"; exit 1; } done # Sanity: every tool must run (loader path is correct) — this catches # a wrong @loader_path / rpath before we ship a broken bundle. for b in pg_dump pg_restore psql; do "$OUT/${b}${BIN_EXT}" --version >/dev/null 2>&1 || { echo "$b failed to run from resource dir"; exit 1; } done - name: Build MariaDB client tools (bundled) shell: bash run: | set -euo pipefail MARIADB_VER="11.4.5" OUT="${GITHUB_WORKSPACE}/desktop/src-tauri/resources/mysql_tools" mkdir -p "$OUT" case "${{ matrix.platform }}" in ubuntu-22.04) sudo apt-get update -y sudo apt-get install -y cmake build-essential libssl-dev libzstd-dev pkg-config libgnutls28-dev patchelf git clone --depth 1 --branch "mariadb-${MARIADB_VER}" https://github.com/MariaDB/server.git /tmp/mariadb-server cd /tmp/mariadb-server # Client-only build: wolfSSL + zlib are vendored. The in-tree # Connector C still probes GnuTLS on Unix regardless of WITH_SSL, # so libgnutls28-dev is required at build time. cmake -DCMAKE_BUILD_TYPE=Release \ -DWITHOUT_SERVER=ON \ -DWITHOUT_TOKUDB=1 \ -DWITHOUT_ROCKSDB=1 \ -DWITHOUT_MROONGA=1 \ -DWITHOUT_SPIDER=1 \ -DWITHOUT_SEQUENCE=1 \ -DWITH_UNIT_TESTS=OFF \ -DWITH_SSL=bundled \ -DWITH_ZLIB=bundled . make -j"$(nproc)" mariadb-dump mariadb # Clients build into client/ (stable across MariaDB 10.x/11.x); # fall back to a broad search if a future version moves them. for b in mariadb-dump mariadb; do src=$(find client -maxdepth 1 -type f -name "$b" -print -quit 2>/dev/null || true) test -n "$src" || src=$(find . -type f -name "$b" -print -quit || true) test -n "$src" || { echo "build produced no $b binary"; exit 1; } cp "$src" "$OUT"/ done # Bundle every non-core shared dependency (GnuTLS + its chain, # libzstd) next to the clients and point the loader at $ORIGIN — # the same pattern the pg_tools step uses for libpq. for b in mariadb-dump mariadb; do ldd "$OUT/$b" | awk '/=> \// {print $3}' | sort -u | while read -r lib; do case "$(basename "$lib")" in ld-linux*|libc.so*|libm.so*|libpthread*|libdl.so*|librt.so*|libgcc_s*|libstdc++*|libcrypt.so*|libresolv*|libutil*) ;; # core runtime — present on every glibc system *) cp -n "$lib" "$OUT/$(basename "$lib")" 2>/dev/null || true ;; esac done patchelf --set-rpath '$ORIGIN' "$OUT/$b" done ;; macos-latest|macos-15-intel) git clone --depth 1 --branch "mariadb-${MARIADB_VER}" https://github.com/MariaDB/server.git /tmp/mariadb-server cd /tmp/mariadb-server # macOS connects the in-tree Connector C against brew OpenSSL # (proven to build+run on the runners); the Linux-only GnuTLS # probe does not fire here. Absolute brew paths are rewritten to # @loader_path below so user machines resolve them from the # resource dir. if [ "$(uname -m)" = arm64 ]; then SSL_DIR="/opt/homebrew/opt/openssl" else SSL_DIR="/usr/local/opt/openssl" fi [ -d "$SSL_DIR" ] || brew install openssl cmake -DCMAKE_BUILD_TYPE=Release \ -DWITHOUT_SERVER=ON \ -DWITHOUT_TOKUDB=1 \ -DWITHOUT_ROCKSDB=1 \ -DWITHOUT_MROONGA=1 \ -DWITHOUT_SPIDER=1 \ -DWITHOUT_SEQUENCE=1 \ -DWITH_UNIT_TESTS=OFF \ -DWITH_SSL="$SSL_DIR" \ -DWITH_ZLIB=bundled . make -j"$(sysctl -n hw.ncpu)" mariadb-dump mariadb for b in mariadb-dump mariadb; do src=$(find client -maxdepth 1 -type f -name "$b" -print -quit 2>/dev/null || true) test -n "$src" || src=$(find . -type f -name "$b" -print -quit || true) test -n "$src" || { echo "build produced no $b binary"; exit 1; } cp "$src" "$OUT"/ done # Rewrite absolute Homebrew dylib deps to @loader_path so the # bundled clients (and OpenSSL + their own deps) resolve from the # resource dir on user machines. Fixed-point loop: each pass # copies newly-seen dylibs and rewrites their parents' refs. # Ad-hoc re-sign after each edit — arm64 dyld refuses to load a # dylib whose (Homebrew) code signature was invalidated. for pass in 1 2 3 4 5 6; do for dylib in "$OUT"/*.dylib "$OUT"/mariadb-dump "$OUT"/mariadb; do [ -f "$dylib" ] || continue # `|| true` — with pipefail, grep exits 1 on zero matches. otool -L "$dylib" | awk 'NR>1 {print $1}' | grep -E '^/(usr/local|opt/homebrew)' | while read -r lib; do base=$(basename "$lib") if [ ! -f "$OUT/$base" ]; then cp "$lib" "$OUT/$base" 2>/dev/null || true; fi install_name_tool -change "$lib" "@loader_path/$base" "$dylib" 2>/dev/null || true done || true if [ -n "${APPLE_SIGNING_IDENTITY:-}" ]; then codesign --force --options runtime --timestamp \ --sign "$APPLE_SIGNING_IDENTITY" "$dylib" else codesign --force --sign - "$dylib" 2>/dev/null || true fi done done ;; windows-latest) URL="https://archive.mariadb.org/mariadb-${MARIADB_VER}/winx64-packages/mariadb-${MARIADB_VER}-winx64.zip" curl -fsSL "$URL" -o /tmp/mariadb.zip # TODO(RELEASE): pin the sha256 printed on the first CI run, then # uncomment the check so later releases verify the download. # EXPECTED="" # echo "$EXPECTED /tmp/mariadb.zip" | sha256sum -c - sha256sum /tmp/mariadb.zip unzip -o /tmp/mariadb.zip -d /tmp/mariadb WINROOT="/tmp/mariadb/mariadb-${MARIADB_VER}-winx64" cp "$WINROOT"/bin/mariadb-dump.exe "$WINROOT"/bin/mariadb.exe "$OUT"/ # The clients' only runtime dependency is the client library # (lib/libmariadb.dll); the winx64 package statically links # wolfSSL, so there are no OpenSSL DLLs to bundle. bin/*.dll is # just the embedded server.dll, which the client tools don't need. cp "$WINROOT"/lib/libmariadb.dll "$OUT"/ ;; esac (cd "$OUT" && sha256sum * | tee checksums.txt) # Resolve the per-platform binary suffix WITHOUT a command # substitution (see the pg_tools step for why). if [ "${{ matrix.platform }}" = windows-latest ]; then BIN_EXT=".exe" else BIN_EXT="" fi for b in mariadb-dump mariadb; do f="$OUT/${b}${BIN_EXT}" test -f "$f" || { echo "missing $f"; exit 1; } done # Sanity: every tool must run (loader path is correct) — this catches # a missing shared library before we ship a broken bundle. for b in mariadb-dump mariadb; do "$OUT/${b}${BIN_EXT}" --version >/dev/null 2>&1 || { echo "$b failed to run from resource dir"; exit 1; } done - name: Build and upload to GitHub Release uses: tauri-apps/tauri-action@v0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: projectPath: desktop tagName: ${{ env.RELEASE_TAG }} releaseName: 'Gridline ${{ env.RELEASE_TAG }}' releaseDraft: true args: ${{ matrix.args }} # Assets use tauri-action's default versioned naming (e.g. # Gridline_0.7.5_aarch64.dmg, Gridline-0.7.5-1.x86_64.rpm) and the # README download tables link to them statically per release — # remember to update both README tables when cutting a new version. # tauri-action notarizes + staples the .app but NOT the .dmg wrapping it, # so Gatekeeper rejects the downloaded DMG as "Unnotarized Developer ID" # even though the app inside is fine. Submit the DMG to the same notary # service, staple the ticket, and replace the uploaded asset. # # Assets are replaced via the release ID rather than `gh release upload`: # the GitHub releases/tags endpoint returns 404 for drafts, so uploading # by tag cannot work while the release is still a draft. - name: Notarize and staple the DMGs if: startsWith(matrix.platform, 'macos') && steps.apple.outputs.enabled == 'true' shell: bash env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -euo pipefail shopt -s nullglob dmgs=(desktop/src-tauri/target/*/release/bundle/dmg/*.dmg) if [ ${#dmgs[@]} -eq 0 ]; then echo "no DMG produced" >&2 exit 1 fi REL_ID=$(gh api "repos/${GITHUB_REPOSITORY}/releases?per_page=100" \ --jq ".[] | select(.tag_name == \"${RELEASE_TAG}\") | .id" | head -1) if [ -z "$REL_ID" ]; then echo "could not resolve a release id for ${RELEASE_TAG}" >&2 exit 1 fi for dmg in "${dmgs[@]}"; do name=$(basename "$dmg") echo ">> notarizing $name (this can take a few minutes)" xcrun notarytool submit "$dmg" \ --key "$APPLE_API_KEY_PATH" \ --key-id "$APPLE_API_KEY" \ --issuer "$APPLE_API_ISSUER" \ --wait xcrun stapler staple "$dmg" xcrun stapler validate "$dmg" # Replace the copy tauri-action uploaded, which carries no DMG ticket. old=$(gh api "repos/${GITHUB_REPOSITORY}/releases/${REL_ID}/assets" \ --jq ".[] | select(.name == \"${name}\") | .id" | head -1) if [ -n "$old" ]; then gh api -X DELETE "repos/${GITHUB_REPOSITORY}/releases/assets/${old}" fi echo ">> re-uploading stapled $name" curl -fsS -X POST \ -H "Authorization: token ${GH_TOKEN}" \ -H "Content-Type: application/octet-stream" \ --data-binary "@${dmg}" \ "https://uploads.github.com/repos/${GITHUB_REPOSITORY}/releases/${REL_ID}/assets?name=${name}" echo done echo "all DMGs notarized and stapled" # After the installers are uploaded, refresh the Homebrew cask in the # AdrianBonpin/homebrew-gridline tap: hash the freshly-published DMGs, # render Casks/gridline.rb from the template, and push it. Users then get # the new version via `brew upgrade --cask gridline`. # # Requires the HOMEBREW_TAP_DEPLOY_KEY secret — a write-enabled SSH deploy # key on the tap repo (the default GITHUB_TOKEN cannot push to a different # repository, and a deploy key avoids storing a broad PAT). The job skips # cleanly until that secret is set, so releases stay green before this is # configured. bump-cask: # Normally fires on `release: published`, which requires the DMGs to be # downloadable — the GitHub releases/tags API returns 404 for drafts, so # this cannot run on the tag push. NOTE: a release whose DRAFT was created # by tauri-action's GITHUB_TOKEN does not reliably emit a `release` event, # so `workflow_dispatch` with bump_cask=true is the dependable path. if: github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && inputs.bump_cask == true) runs-on: ubuntu-latest permissions: contents: read steps: - name: Check for tap deploy key id: tap shell: bash run: | if [ -n "${{ secrets.HOMEBREW_TAP_DEPLOY_KEY }}" ]; then echo "enabled=true" >> "$GITHUB_OUTPUT" else echo "enabled=false" >> "$GITHUB_OUTPUT" echo "::notice::HOMEBREW_TAP_DEPLOY_KEY not set - skipping Homebrew cask bump." fi - name: Checkout if: steps.tap.outputs.enabled == 'true' uses: actions/checkout@v4 - name: Resolve version and DMG checksums id: meta if: steps.tap.outputs.enabled == 'true' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | VERSION="${RELEASE_TAG#v}" gh release download "$RELEASE_TAG" -p "Gridline_${VERSION}_aarch64.dmg" -O /tmp/arm.dmg gh release download "$RELEASE_TAG" -p "Gridline_${VERSION}_x64.dmg" -O /tmp/intel.dmg echo "version=$VERSION" >> "$GITHUB_OUTPUT" echo "sha_arm=$(shasum -a 256 /tmp/arm.dmg | cut -d' ' -f1)" >> "$GITHUB_OUTPUT" echo "sha_intel=$(shasum -a 256 /tmp/intel.dmg | cut -d' ' -f1)" >> "$GITHUB_OUTPUT" - name: Checkout tap repo if: steps.tap.outputs.enabled == 'true' uses: actions/checkout@v4 with: repository: AdrianBonpin/homebrew-gridline ssh-key: ${{ secrets.HOMEBREW_TAP_DEPLOY_KEY }} path: tap - name: Render and push cask if: steps.tap.outputs.enabled == 'true' env: VERSION: ${{ steps.meta.outputs.version }} SHA_ARM: ${{ steps.meta.outputs.sha_arm }} SHA_INTEL: ${{ steps.meta.outputs.sha_intel }} run: | mkdir -p tap/Casks ./scripts/render-cask.sh "$VERSION" "$SHA_ARM" "$SHA_INTEL" > tap/Casks/gridline.rb cat tap/Casks/gridline.rb cd tap git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git add Casks/gridline.rb if git diff --cached --quiet; then echo "cask already up to date" else git commit -m "gridline $VERSION" git push fi