Skip to content

Commit fa233d9

Browse files
Fold macOS desktop release flow into tag release workflow
1 parent 74cc41e commit fa233d9

3 files changed

Lines changed: 142 additions & 171 deletions

File tree

.github/RELEASE_SETUP.md

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Release Setup
22

33
This project ships:
4-
- signed macOS `.app` and `.dmg` (manual test workflow)
4+
- signed/notarized macOS `.dmg` on tag release (when Apple secrets are present)
55
- tag-based GitHub Releases with `attn` CLI binaries
66
- crates.io publishing for `cargo install attn`
77
- npm package publishing for `npx attnmd`
@@ -13,9 +13,7 @@ This project ships:
1313
- `scripts/macos-create-dmg.sh`: packages and optionally signs DMG
1414
- `scripts/macos-notarize-dmg.sh`: notarizes and staples DMG
1515
- `.github/workflows/test-signing.yml`: signing smoke test
16-
- `.github/workflows/macos-desktop-test.yml`: build/sign/notarize artifact test
17-
- `.github/workflows/release.yml`: build release binaries on tag push (`v*`), publish crate, and publish npm
18-
(signing/notarization remains in dedicated macOS workflows)
16+
- `.github/workflows/release.yml`: build release binaries on tag push (`v*`), optionally sign/notarize DMG, publish crate, and publish npm
1917
- `.github/workflows/npm-publish.yml`: manual fallback publisher (workflow_dispatch or release events)
2018

2119
## Required GitHub Secrets
@@ -66,10 +64,7 @@ scripts/macos-notarize-dmg.sh target/aarch64-apple-darwin/release/bundle/osx/att
6664
## CI test run
6765

6866
1. Run `Test Code Signing` workflow to validate cert/keychain/signing.
69-
2. Run `macOS Desktop Build Test` workflow:
70-
- `mode=prod`
71-
- `target=aarch64-apple-darwin`
72-
- `notarize=true`
67+
2. Push a version tag (`v*`) and verify `Release` workflow completes.
7368

7469
## GitHub release flow (tag-based)
7570

@@ -83,6 +78,7 @@ scripts/macos-notarize-dmg.sh target/aarch64-apple-darwin/release/bundle/osx/att
8378
- `attn-v<VERSION>-darwin-arm64`
8479
- `attn-v<VERSION>-darwin-x64`
8580
- matching `.sha256` files
81+
- `attn-v<VERSION>-darwin-arm64.dmg` and checksum when notarization secrets are configured
8682
4. A GitHub Release for the tag is created/updated with those assets.
8783
5. The same workflow publishes crate `attn` to crates.io.
8884
6. The same workflow publishes npm package `attnmd`.

.github/workflows/macos-desktop-test.yml

Lines changed: 0 additions & 145 deletions
This file was deleted.

.github/workflows/release.yml

Lines changed: 138 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,19 @@ permissions:
1010
id-token: write
1111

1212
jobs:
13-
build-binary:
14-
name: Build darwin-arm64
15-
runs-on: macos-14
13+
build-binaries:
14+
name: Build ${{ matrix.asset_suffix }}
15+
runs-on: ${{ matrix.runner }}
16+
strategy:
17+
fail-fast: false
18+
matrix:
19+
include:
20+
- runner: macos-14
21+
target: aarch64-apple-darwin
22+
asset_suffix: darwin-arm64
23+
- runner: macos-13
24+
target: x86_64-apple-darwin
25+
asset_suffix: darwin-x64
1626
steps:
1727
- name: Checkout
1828
uses: actions/checkout@v4
@@ -30,37 +40,150 @@ jobs:
3040
npm ci
3141
3242
- name: Setup Rust
43+
uses: dtolnay/rust-toolchain@stable
44+
with:
45+
targets: ${{ matrix.target }}
46+
47+
- name: Cache Rust
48+
uses: Swatinem/rust-cache@v2
49+
50+
- name: Build release binary
51+
run: cargo build --release --target ${{ matrix.target }} --locked
52+
53+
- name: Prepare binary assets
54+
env:
55+
TAG: ${{ github.ref_name }}
56+
TARGET: ${{ matrix.target }}
57+
ASSET_SUFFIX: ${{ matrix.asset_suffix }}
58+
run: |
59+
VERSION="${TAG#v}"
60+
mkdir -p dist
61+
cp "target/${TARGET}/release/attn" "dist/attn-v${VERSION}-${ASSET_SUFFIX}"
62+
chmod +x "dist/attn-v${VERSION}-${ASSET_SUFFIX}"
63+
shasum -a 256 "dist/attn-v${VERSION}-${ASSET_SUFFIX}" > "dist/attn-v${VERSION}-${ASSET_SUFFIX}.sha256"
64+
65+
- name: Upload binary artifacts
66+
uses: actions/upload-artifact@v4
67+
with:
68+
name: release-${{ matrix.asset_suffix }}
69+
path: dist/*
70+
retention-days: 7
71+
72+
build-signed-dmg:
73+
name: Build, sign & notarize DMG
74+
runs-on: macos-14
75+
if: ${{ secrets.APPLE_CERTIFICATE != '' && secrets.APPLE_CERTIFICATE_PASSWORD != '' && secrets.KEYCHAIN_PASSWORD != '' && secrets.APPLE_SIGNING_IDENTITY != '' && secrets.APPLE_ID != '' && secrets.APPLE_APP_SPECIFIC_PASSWORD != '' && secrets.APPLE_TEAM_ID != '' }}
76+
steps:
77+
- name: Checkout
78+
uses: actions/checkout@v4
79+
80+
- name: Setup Node
81+
uses: actions/setup-node@v4
82+
with:
83+
node-version: "20"
84+
cache: npm
85+
cache-dependency-path: web/package-lock.json
86+
87+
- name: Setup Rust toolchain
3388
uses: dtolnay/rust-toolchain@stable
3489
with:
3590
targets: aarch64-apple-darwin
3691

3792
- name: Cache Rust
3893
uses: Swatinem/rust-cache@v2
3994

40-
- name: Build production binary
41-
run: cargo build --release --target aarch64-apple-darwin --locked
95+
- name: Install cargo-bundle
96+
uses: taiki-e/cache-cargo-install-action@v2
97+
with:
98+
tool: cargo-bundle
99+
100+
- name: Install frontend dependencies
101+
run: |
102+
cd web
103+
npm ci
42104
43-
- name: Prepare release assets
105+
- name: Import code signing certificate
106+
env:
107+
CERTIFICATE_BASE64: ${{ secrets.APPLE_CERTIFICATE }}
108+
CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
109+
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
110+
run: |
111+
CERTIFICATE_PATH="$RUNNER_TEMP/build_certificate.p12"
112+
KEYCHAIN_PATH="$RUNNER_TEMP/app-signing.keychain-db"
113+
114+
echo -n "$CERTIFICATE_BASE64" | base64 --decode > "$CERTIFICATE_PATH" || \
115+
echo -n "$CERTIFICATE_BASE64" | base64 -D > "$CERTIFICATE_PATH"
116+
117+
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
118+
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
119+
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
120+
security import "$CERTIFICATE_PATH" -P "$CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH"
121+
security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
122+
security list-keychain -d user -s "$KEYCHAIN_PATH"
123+
124+
echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV"
125+
126+
- name: Build app bundle
127+
run: |
128+
scripts/macos-build-bundle.sh prod aarch64-apple-darwin
129+
130+
APP_PATH="$(find target/aarch64-apple-darwin -path '*/bundle/osx/*.app' -maxdepth 6 | head -n1)"
131+
if [ -z "$APP_PATH" ]; then
132+
echo "No app bundle found" >&2
133+
exit 1
134+
fi
135+
136+
DMG_PATH="$(dirname "$APP_PATH")/attn.dmg"
137+
echo "APP_PATH=$APP_PATH" >> "$GITHUB_ENV"
138+
echo "DMG_PATH=$DMG_PATH" >> "$GITHUB_ENV"
139+
140+
- name: Sign app bundle
141+
env:
142+
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
143+
run: scripts/macos-sign-app.sh "$APP_PATH" "$APPLE_SIGNING_IDENTITY"
144+
145+
- name: Create DMG
146+
env:
147+
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
148+
run: scripts/macos-create-dmg.sh "$APP_PATH" "$DMG_PATH"
149+
150+
- name: Notarize DMG
151+
env:
152+
APPLE_ID: ${{ secrets.APPLE_ID }}
153+
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
154+
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
155+
run: scripts/macos-notarize-dmg.sh "$DMG_PATH"
156+
157+
- name: Prepare DMG assets
44158
env:
45159
TAG: ${{ github.ref_name }}
46160
run: |
47161
VERSION="${TAG#v}"
48162
mkdir -p dist
49-
cp "target/aarch64-apple-darwin/release/attn" "dist/attn-v${VERSION}-darwin-arm64"
50-
chmod +x "dist/attn-v${VERSION}-darwin-arm64"
51-
shasum -a 256 "dist/attn-v${VERSION}-darwin-arm64" > "dist/attn-v${VERSION}-darwin-arm64.sha256"
163+
cp "$DMG_PATH" "dist/attn-v${VERSION}-darwin-arm64.dmg"
164+
shasum -a 256 "dist/attn-v${VERSION}-darwin-arm64.dmg" > "dist/attn-v${VERSION}-darwin-arm64.dmg.sha256"
52165
53-
- name: Upload build artifacts
166+
- name: Upload DMG artifacts
54167
uses: actions/upload-artifact@v4
55168
with:
56-
name: release-darwin-arm64
169+
name: release-dmg-darwin-arm64
57170
path: dist/*
58171
retention-days: 7
59172

173+
- name: Cleanup keychain
174+
if: always()
175+
run: |
176+
if [ -n "${KEYCHAIN_PATH:-}" ] && [ -f "$KEYCHAIN_PATH" ]; then
177+
security delete-keychain "$KEYCHAIN_PATH"
178+
fi
179+
60180
publish-release:
61181
name: Publish GitHub Release
62182
runs-on: ubuntu-latest
63-
needs: build-binary
183+
needs:
184+
- build-binaries
185+
- build-signed-dmg
186+
if: ${{ always() && needs.build-binaries.result == 'success' && (needs.build-signed-dmg.result == 'success' || needs.build-signed-dmg.result == 'skipped') }}
64187
steps:
65188
- name: Checkout
66189
uses: actions/checkout@v4
@@ -71,11 +194,8 @@ jobs:
71194
uses: actions/download-artifact@v4
72195
with:
73196
path: dist
74-
75-
- name: Flatten artifact directories
76-
run: |
77-
mkdir -p release-assets
78-
find dist -type f -maxdepth 3 -exec cp {} release-assets/ \;
197+
pattern: release-*
198+
merge-multiple: true
79199

80200
- name: Create or update release
81201
env:
@@ -89,7 +209,7 @@ jobs:
89209
--title "$TAG" \
90210
--notes "Automated release for $TAG."
91211
fi
92-
gh release upload "$TAG" release-assets/* --clobber
212+
gh release upload "$TAG" dist/* --clobber
93213
94214
publish-crates:
95215
name: Publish crates.io

0 commit comments

Comments
 (0)