Skip to content

v2.8.1

v2.8.1 #35

Workflow file for this run

name: Release
# Native macOS release workflow.
#
# Current status: MANUAL
# DMG artifacts are built locally on the release Mac with `make release`
# (scripts/release.sh: Developer ID signing + notarization + stapling) and
# uploaded to GitHub Releases with `gh release upload`. See BUILDING.md
# "Building a Release".
#
# Future: automate with a self-hosted macOS runner or GitHub's macos-latest
# (requires exporting the Developer ID certificate and notary API key as
# repository secrets).
#
# Windows / Linux: Zerm is a native macOS Swift app (AppKit + SwiftUI).
# There is no Windows or Linux build. The archived Tauri prototype that
# previously built cross-platform installers is no longer maintained.
on:
# Manual trigger only — for running any future automated steps
workflow_dispatch:
inputs:
tag:
description: "Release tag (e.g. v1.0.4)"
required: true
type: string
# Keep the published changelog in step with GitHub Releases.
#
# Only `released`. Publishing a release fires `published` AND `released`, and
# every asset upload fires `edited`, so the old four-type list ran this whole
# workflow three times per release and raced three identical changelog branches
# against each other. `deleted` was pointless here: the regenerated changelog
# reads the releases list, which a deletion also changes, but a deleted release
# cannot be validated by the tag job below.
release:
types: [released]
permissions:
contents: write
# createCommitOnBranch needs contents; opening the changelog PR needs this.
# Without it `gh pr create` fails with "Resource not accessible by integration".
pull-requests: write
jobs:
release-notes:
name: Validate release tag
# Guarded because this job reads `inputs.tag`, which only exists for a manual
# run. On a release event it evaluated to "", so the job failed with
# "Tag not found" on every single release — the other half of why this
# workflow has never gone green.
if: github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
with:
# Tags are not fetched by the default shallow checkout, so `git rev-parse`
# below reported every tag as missing — including ones that plainly exist.
fetch-depth: 0
- name: Verify tag exists
run: |
TAG="${{ inputs.tag }}"
if git rev-parse "$TAG" >/dev/null 2>&1; then
echo "Tag $TAG exists — release is valid"
else
echo "Tag $TAG not found. Create the tag first:"
echo " git tag $TAG && git push origin $TAG"
exit 1
fi
- name: Check release assets
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG="${{ inputs.tag }}"
ASSETS=$(gh release view "$TAG" --json assets --jq '.assets[].name' 2>/dev/null || echo "")
if echo "$ASSETS" | grep -qi "\.dmg"; then
echo "Release $TAG has DMG assets:"
echo "$ASSETS"
else
echo "WARNING: Release $TAG has no .dmg assets yet."
echo "Upload a DMG with:"
echo " gh release upload $TAG path/to/Zerm_VERSION_aarch64.dmg"
fi
publish-changelog:
name: Regenerate site changelog
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
with:
ref: Production
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: "22"
- name: Regenerate derived pages
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: node scripts/build-site.mjs
# This job cannot publish the changelog itself, and pretending otherwise is
# what made it useless for so long. The history:
#
# 1. It committed as github-actions[bot] and pushed to Production. The
# "Require signed commits" ruleset covers ~ALL branches with no bypass
# actors, so the push was rejected — every release, silently, which is
# how the site changelog got stuck at 2.6.1 while 2.7.0 shipped.
# 2. Creating the commit via GraphQL createCommitOnBranch fixed the signing
# (GitHub signs those server-side) and that part does work.
# 3. But Production takes changes by pull request only, and the org forbids
# GitHub Actions from creating pull requests:
# "GitHub Actions is not permitted to create or approve pull requests"
# That is an org-wide security policy. Loosening it for a changelog is a
# bad trade, so this job no longer tries.
#
# Instead it reports drift and fails loudly. Regenerating is a one-liner a
# maintainer runs with their own credentials, and `make release` does it as
# part of cutting a release.
- name: Check the site is in step with published releases
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
if git diff --quiet -- docs/; then
echo "Site is up to date with the published releases."
exit 0
fi
echo "::error::The published site is out of date with the GitHub Releases."
echo "Stale files:"
git diff --name-only -- docs/ | sed 's/^/ /'
echo ""
echo "Regenerate and open a PR:"
echo " node scripts/build-site.mjs && git add docs/ && git commit -m 'Regenerate site changelog from releases'"
echo ""
echo "Diff of what would change:"
git --no-pager diff --stat -- docs/
exit 1