Skip to content

Commit 10d2e18

Browse files
committed
Add macOS signing, notarisation, and release Slack notifications
1 parent a3bd913 commit 10d2e18

2 files changed

Lines changed: 103 additions & 1 deletion

File tree

.github/workflows/release.yml

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,96 @@ jobs:
7373
--archive-dir build/artifacts \
7474
--github-output "${GITHUB_OUTPUT}"
7575
76+
- name: Import Apple signing certificate
77+
if: runner.os == 'macOS'
78+
env:
79+
APPLE_CERT_P12_BASE64: ${{ secrets.APPLE_CERT_P12_BASE64 }}
80+
APPLE_CERT_PASSWORD: ${{ secrets.APPLE_CERT_PASSWORD }}
81+
shell: bash
82+
run: |
83+
echo "$APPLE_CERT_P12_BASE64" | base64 --decode > apple-cert.p12
84+
85+
security create-keychain -p temp123 build.keychain
86+
security default-keychain -s build.keychain
87+
security unlock-keychain -p temp123 build.keychain
88+
security set-keychain-settings -lut 21600 build.keychain
89+
90+
security import apple-cert.p12 \
91+
-k build.keychain \
92+
-P "$APPLE_CERT_PASSWORD" \
93+
-T /usr/bin/codesign \
94+
-T /usr/bin/security
95+
96+
security set-key-partition-list \
97+
-S apple-tool:,apple: \
98+
-s \
99+
-k temp123 \
100+
build.keychain
101+
102+
- name: Sign macOS packaged bundle
103+
if: runner.os == 'macOS'
104+
env:
105+
APPLE_SIGNING_IDENTITY: ${{ vars.APPLE_SIGNING_IDENTITY || secrets.APPLE_SIGNING_IDENTITY }}
106+
shell: bash
107+
run: |
108+
BUNDLE_DIR="${{ steps.package.outputs.bundle_dir }}"
109+
BUNDLE_EXECUTABLE="${{ steps.package.outputs.bundle_executable }}"
110+
111+
while IFS= read -r -d '' path; do
112+
if file "$path" | grep -q 'Mach-O'; then
113+
codesign --force --options runtime --timestamp \
114+
--sign "$APPLE_SIGNING_IDENTITY" \
115+
"$path"
116+
fi
117+
done < <(find "$BUNDLE_DIR" -type f -print0)
118+
119+
codesign --force --options runtime --timestamp \
120+
--sign "$APPLE_SIGNING_IDENTITY" \
121+
"$BUNDLE_EXECUTABLE"
122+
123+
- name: Verify macOS packaged signature
124+
if: runner.os == 'macOS'
125+
shell: bash
126+
run: |
127+
codesign --verify --verbose=4 "${{ steps.package.outputs.bundle_executable }}"
128+
codesign --display --verbose=4 "${{ steps.package.outputs.bundle_executable }}"
129+
spctl -a -t exec -vv "${{ steps.package.outputs.bundle_executable }}" || true
130+
131+
- name: Repackage signed macOS archive
132+
if: runner.os == 'macOS'
133+
shell: bash
134+
run: |
135+
ARCHIVE_PATH="${{ steps.package.outputs.archive_path }}"
136+
STAGING_DIR="$(dirname "${{ steps.package.outputs.bundle_dir }}")"
137+
rm -f "$ARCHIVE_PATH"
138+
ditto -c -k --keepParent "$STAGING_DIR" "$ARCHIVE_PATH"
139+
76140
- name: Smoke test packaged help output
77141
shell: bash
78142
run: |
79143
"${{ steps.package.outputs.bundle_executable }}" --help
80144
145+
- name: Restore App Store Connect key
146+
if: runner.os == 'macOS'
147+
env:
148+
APPSTORE_CONNECT_API_KEY_P8_BASE64: ${{ secrets.APPSTORE_CONNECT_API_KEY_P8_BASE64 }}
149+
shell: bash
150+
run: |
151+
echo "$APPSTORE_CONNECT_API_KEY_P8_BASE64" | base64 --decode > AuthKey.p8
152+
153+
- name: Notarise macOS archive
154+
if: runner.os == 'macOS'
155+
env:
156+
APPSTORE_CONNECT_KEY_ID: ${{ vars.APPSTORE_CONNECT_KEY_ID || secrets.APPSTORE_CONNECT_KEY_ID }}
157+
APPSTORE_CONNECT_ISSUER_ID: ${{ vars.APPSTORE_CONNECT_ISSUER_ID || secrets.APPSTORE_CONNECT_ISSUER_ID }}
158+
shell: bash
159+
run: |
160+
xcrun notarytool submit "${{ steps.package.outputs.archive_path }}" \
161+
--key AuthKey.p8 \
162+
--key-id "$APPSTORE_CONNECT_KEY_ID" \
163+
--issuer "$APPSTORE_CONNECT_ISSUER_ID" \
164+
--wait
165+
81166
- name: Real backend smoke after packaging
82167
if: matrix.run_real_smoke
83168
shell: bash
@@ -93,6 +178,8 @@ jobs:
93178
if: startsWith(github.ref, 'refs/tags/v')
94179
needs: build
95180
runs-on: ubuntu-24.04
181+
env:
182+
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
96183

97184
steps:
98185
- name: Download packaged artefacts
@@ -105,3 +192,12 @@ jobs:
105192
uses: softprops/action-gh-release@v2
106193
with:
107194
files: release-artifacts/*
195+
196+
- name: Send Slack notification
197+
if: env.SLACK_WEBHOOK_URL != ''
198+
uses: slackapi/slack-github-action@v2.1.1
199+
with:
200+
webhook: ${{ env.SLACK_WEBHOOK_URL }}
201+
webhook-type: incoming-webhook
202+
payload: |
203+
text: "🚀 bitloops-embeddings ${{ github.ref_name }} has been released!"

scripts/package_release.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ def build_release(*, version: str, target: str, archive_dir: Path) -> tuple[Path
8989
shutil.copy2(ROOT / "README.md", staging_dir / "README.md")
9090
shutil.copy2(ROOT / "LICENSE", staging_dir / "LICENSE")
9191

92-
archive_extension = ".zip" if target.endswith("windows-msvc") else ".tar.gz"
92+
archive_extension = archive_extension_for_target(target)
9393
archive_path = archive_dir / f"{archive_root_name}{archive_extension}"
9494
if archive_path.exists():
9595
archive_path.unlink()
@@ -162,6 +162,12 @@ def executable_name_for_target(target: str) -> str:
162162
return PACKAGE_NAME
163163

164164

165+
def archive_extension_for_target(target: str) -> str:
166+
if target.endswith("windows-msvc") or target.endswith("apple-darwin"):
167+
return ".zip"
168+
return ".tar.gz"
169+
170+
165171
def write_github_outputs(output_path: Path, outputs: dict[str, str]) -> None:
166172
with output_path.open("a", encoding="utf-8") as file_handle:
167173
for key, value in outputs.items():

0 commit comments

Comments
 (0)