Skip to content

Commit 051af27

Browse files
committed
build: notarize macos builds in parallel
Waiting for Apple to notarize binaries often takes up the bulk of the publish script's execution time. Doing the three jobs in parallel ought to cut that down. Since this function prints both log output and captured output, we additionally change the script to print logs to stderr rather than stdout in general.
1 parent 1796f98 commit 051af27

File tree

1 file changed

+46
-29
lines changed

1 file changed

+46
-29
lines changed

publish.bash

Lines changed: 46 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ if test -z "$APPLE_DEVELOPER_ID" ||
1212
exit 1
1313
fi
1414

15+
function log() { echo "$@" 1>&2 ; }
16+
1517
function main() {
1618
git fetch --tags --force
1719

@@ -21,7 +23,7 @@ function main() {
2123
trap 'code=$? ; echo "FAILURE: $code" ; rm -rf $bdir $pdir ; exit $code' EXIT
2224

2325
version_name="$(git describe --tags --abbrev=0 HEAD)"
24-
echo "-- Building '$version_name'"
26+
log "-- Building '$version_name'"
2527

2628
setup_macos_keychain
2729

@@ -39,9 +41,12 @@ function main() {
3941
sign_macos run_darwin_arm64
4042
sign_macos run_darwin_universal
4143

42-
notarize_macos run_darwin_universal
43-
notarize_macos run_darwin_amd64
44-
notarize_macos run_darwin_arm64
44+
lipod_submission_id="$(notarize_macos run_darwin_universal)"
45+
amd64_submission_id="$(notarize_macos run_darwin_amd64)"
46+
arm64_submission_id="$(notarize_macos run_darwin_arm64)"
47+
wait_for_notarization "$lipod_submission_id"
48+
wait_for_notarization "$amd64_submission_id"
49+
wait_for_notarization "$arm64_submission_id"
4550

4651
create_package freebsd arm64
4752
create_package freebsd amd64
@@ -56,7 +61,7 @@ function main() {
5661

5762
# setup_macos_keychain adds $CERTIFICATE_BASE64 to the macOS keychain.
5863
function setup_macos_keychain() {
59-
echo "-- Setting up macos keychain"
64+
log "-- Setting up macos keychain"
6065

6166
cert_path="$(mktemp -d)/cert.p12"
6267
keychain_path="$(mktemp -d)/keys.keychain-db"
@@ -91,11 +96,11 @@ function setup_macos_keychain() {
9196
function build() {
9297
goos="$1"; goarch="$2"
9398
if test -z "$goos" || test -z "$goarch" ; then
94-
echo "build requires 2 arguments"
99+
log "build requires 2 arguments"
95100
return 1
96101
fi
97102

98-
echo "-- Building $goos ($goarch)."
103+
log "-- Building $goos ($goarch)"
99104

100105
CGO_ENABLED=0 GOOS=$goos GOARCH=$goarch \
101106
go build \
@@ -108,7 +113,7 @@ function build() {
108113
#$bdir/run_darwin_arm64 into a "fat" universal binary called
109114
#$bdir/run_darwin_universal.
110115
function make_macos_universal_binary() {
111-
echo "-- Making universal macos binary."
116+
log "-- Making universal macos binary"
112117
lipo \
113118
-output "${bdir}/run_darwin_universal" \
114119
-create "${bdir}/run_darwin_amd64" "${bdir}/run_darwin_arm64"
@@ -118,11 +123,11 @@ function make_macos_universal_binary() {
118123
function sign_macos() {
119124
binary=$1
120125
if test -z "$binary" ; then
121-
echo "sign_macos requires 1 argument"
126+
log "sign_macos requires 1 argument"
122127
return 1
123128
fi
124129

125-
echo "-- Signing $binary."
130+
log "-- Signing $binary"
126131

127132
codesign \
128133
--keychain buildagent \
@@ -134,38 +139,50 @@ function sign_macos() {
134139
return 0
135140
}
136141

137-
# notarize_macos, given a binary file, sends it to Apple for notarization,
138-
# and waits for that notarization to complete.
142+
# notarize_macos, given a binary file, sends it to Apple for notarization. It
143+
# returns immediately after the submission is submitted, it **does not** wait
144+
# for the submission to complete. It returns the Submission ID, which can be
145+
# used to wait for the submission or check its status.
139146
#
140147
# When a binary is run for the first time on macOS, the operating system
141148
# sends its hash to Apple's server to check whether it appears in their
142149
# notarization database. If it is not, the binary won't run.
143-
#
144-
# TODO:
145-
# We currently notarize->wait->notarize->wait in serial. We could shave a
146-
# few seconds of action runtime by submitting all of the binaries at once,
147-
# _then_ waiting for all of them.
148150
function notarize_macos() {
149-
binary=$1
151+
binary="$1"
150152
if test -z "$binary" ; then
151-
echo "notarize_macos requires 1 argument"
153+
log "notarize_macos requires 1 argument"
152154
return 1
153155
fi
154156

155-
echo "-- Asking Apple to notarize $binary; this could take some time."
157+
log "-- Asking Apple to notarize $binary; this could take some time"
156158

157159
/usr/bin/ditto -c -k \
158160
--keepParent \
159161
"${bdir}/${binary}" \
160162
"${bdir}/${binary}.zip"
161163

162164
xcrun notarytool submit \
163-
-f json \
165+
--output-format json \
164166
--apple-id "$APPLE_DEVELOPER_ID" \
165167
--team-id "$APPLE_DEVELOPER_TEAM" \
166168
--password "$APPLE_DEVELOPER_PASSWORD" \
167-
--wait "${bdir}/${binary}.zip" \
168-
2>&1 | tee /tmp/notarization_info.json
169+
"${bdir}/${binary}.zip" | \
170+
sed 's/.*"id":"\([-A-z0-9]\{36\}\)".*/\1/'
171+
}
172+
173+
function wait_for_notarization() {
174+
submission_id="$1"
175+
if test -z "$submission_id" ; then
176+
log "wait_for_notarization requires 1 argument"
177+
return 1
178+
fi
179+
180+
log "-- Waiting for notarization submission '$submission_id'"
181+
182+
xcrun notarytool wait "$submission_id" \
183+
--apple-id "$APPLE_DEVELOPER_ID" \
184+
--team-id "$APPLE_DEVELOPER_TEAM" \
185+
--password "$APPLE_DEVELOPER_PASSWORD"
169186
}
170187

171188
# create_pacakge, given GOOS and GOARCH values, produces a tar.gz archive
@@ -178,12 +195,12 @@ function notarize_macos() {
178195
function create_package() {
179196
os="$1"; arch="$2"
180197
if test -z "$os" || test -z "$arch" ; then
181-
echo "create_package requires 2 arguments"
198+
log "create_package requires 2 arguments"
182199
return 1
183200
fi
184201

185202
package_name="$(package_name "$os" "$arch")"
186-
echo "-- Creating package $package_name"
203+
log "-- Creating package $package_name"
187204

188205
binary="${bdir}/run_${os}_${arch}"
189206
mkdir -p "${pdir}/${package_name}"
@@ -214,7 +231,7 @@ function create_package() {
214231
function package_name() {
215232
os="$1"; arch="$2"
216233
if test -z "$os" || test -z "$arch" ; then
217-
echo "package_name requires 2 arguments"
234+
log "package_name requires 2 arguments"
218235
return 1
219236
fi
220237

@@ -223,14 +240,14 @@ function package_name() {
223240
darwin) os_name="Darwin" ;;
224241
freebsd) os_name="FreeBSD" ;;
225242
linux) os_name="Linux" ;;
226-
*) echo "unsupported os $os" ; exit 1 ;;
243+
*) log "unsupported os $os" ; exit 1 ;;
227244
esac
228245

229246
case $arch in
230247
arm64) arch_name="arm64" ;;
231248
amd64) arch_name="amd64" ;;
232249
universal) arch_name="universal" ;;
233-
*) echo "unsupported arch $arch" ; exit 1 ;;
250+
*) log "unsupported arch $arch" ; exit 1 ;;
234251
esac
235252

236253
if test "$os" = "darwin" && test "$arch" = "amd64" ; then
@@ -258,7 +275,7 @@ function create_release_notes() {
258275
# create_release uses the Github API to create the release and upload the
259276
# release artifacts.
260277
function create_release() {
261-
echo "-- Uploading release to Github."
278+
log "-- Uploading release to Github"
262279
create_release_notes | gh release create \
263280
--repo="${GITHUB_REPOSITORY:-amonks/run}" \
264281
--notes-file=- \

0 commit comments

Comments
 (0)