From 1e6da44f75f3c2aeda58373db9bf854db366f7e8 Mon Sep 17 00:00:00 2001 From: JNHFlow21 Date: Thu, 23 Jul 2026 03:06:23 -0400 Subject: [PATCH] feat: add unsigned macOS release pipeline --- .github/workflows/ci.yml | 2 + .github/workflows/release.yml | 70 +++++++++++++++++++++++++++++++++++ CHANGELOG.md | 5 ++- scripts/build-release.sh | 63 +++++++++++++++++++++++++++++++ 4 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/release.yml create mode 100755 scripts/build-release.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 900f267..b1b4aed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,3 +54,5 @@ jobs: - uses: actions/checkout@v7 - run: zsh -n scripts/install.sh - run: test -x scripts/install.sh + - run: zsh -n scripts/build-release.sh + - run: test -x scripts/build-release.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..63f740c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,70 @@ +name: Release + +on: + push: + tags: + - "v*" + +permissions: + contents: write + +jobs: + release: + runs-on: macos-14 + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 + with: + python-version: "3.14" + + - name: Verify tag and version + shell: bash + run: | + set -euo pipefail + version="$(cat VERSION)" + test "$GITHUB_REF_NAME" = "v$version" + PYTHONPATH=src python -c 'import agent_switch; print(agent_switch.__version__)' + + - name: Run release tests + run: | + PYTHONPATH=src python -m unittest discover -s tests -v + PYTHONPATH=src python -m unittest discover -s tests/integration -v + + - name: Build release artifacts + run: | + python -m pip install --upgrade build + python -m build --sdist --outdir dist + ./scripts/build-release.sh dist + cd dist + shasum -a 256 "agent_switch-$(cat ../VERSION).tar.gz" \ + > "agent_switch-$(cat ../VERSION).tar.gz.sha256" + + - name: Create GitHub prerelease + env: + GH_TOKEN: ${{ github.token }} + shell: bash + run: | + set -euo pipefail + version="$(cat VERSION)" + cat > "$RUNNER_TEMP/release-notes.md" </dev/null 2>&1 || fail "$command is required." +done + +mkdir -p "$OUTPUT_DIR" +rm -f "$ARCHIVE" "$ARCHIVE.sha256" + +xcodebuild \ + -project "$PROJECT" \ + -scheme "$SCHEME" \ + -configuration Release \ + -destination "generic/platform=macOS" \ + -derivedDataPath "$DERIVED_DATA" \ + -quiet \ + ARCHS="arm64 x86_64" \ + ONLY_ACTIVE_ARCH=NO \ + CODE_SIGNING_ALLOWED=NO \ + build + +[[ -d "$APP" ]] || fail "Xcode did not produce $APP" + +APP_VERSION="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$APP/Contents/Info.plist")" +[[ "$APP_VERSION" == "$VERSION" ]] || fail "App version $APP_VERSION does not match VERSION $VERSION." + +ARCHS="$(lipo -archs "$APP/Contents/MacOS/Agent Switch")" +[[ " $ARCHS " == *" arm64 "* ]] || fail "Release is missing arm64." +[[ " $ARCHS " == *" x86_64 "* ]] || fail "Release is missing x86_64." + +# The public alpha is intentionally ad-hoc signed until a Developer ID is +# available. Homebrew installation documents the resulting Gatekeeper tradeoff. +xattr -cr "$APP" +codesign --force --sign - --options runtime --timestamp=none "$APP" +codesign --verify --deep --strict --verbose=2 "$APP" + +ditto -c -k --sequesterRsrc --keepParent "$APP" "$ARCHIVE" +(cd "$OUTPUT_DIR" && shasum -a 256 "${ARCHIVE:t}" > "${ARCHIVE:t}.sha256") + +print "Built $ARCHIVE" +print "Architectures: $ARCHS" +print "Signing: ad-hoc (not notarized)"