-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathrelease.sh
More file actions
executable file
·152 lines (134 loc) · 5.48 KB
/
Copy pathrelease.sh
File metadata and controls
executable file
·152 lines (134 loc) · 5.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/bin/zsh
#
# Builds a release: archive with Hardened Runtime, export with a Developer ID Application
# signature, verify it, create a drag-to-Applications DMG, sign and notarize the DMG, and
# staple the ticket. The result is build/release/Mectrics.dmg (local output, not committed).
# The release-candidate wrapper redirects the output and skips appcast generation.
#
# MECTRICS_TEAM_ID=... MECTRICS_NOTARY_PROFILE=... ./scripts/release.sh
#
# Requires a Developer ID Application certificate and a notarytool keychain profile
# (`xcrun notarytool store-credentials`). Never pass credentials on the command line.
set -euo pipefail
repo_root=${0:A:h:h}
release_root=${MECTRICS_RELEASE_ROOT:-$repo_root/build/release}
release_root=${release_root:A}
skip_appcast=${MECTRICS_SKIP_APPCAST:-0}
# Archive and staging directories are replaced below. Keep every destructive target
# inside one explicit build subdirectory even when an override is supplied.
if [[ "$release_root" != "$repo_root/build/"* || "$release_root" == "$repo_root/build" ]]; then
echo "MECTRICS_RELEASE_ROOT must be a subdirectory of $repo_root/build" >&2
exit 64
fi
if [[ "$skip_appcast" != 0 && "$skip_appcast" != 1 ]]; then
echo "MECTRICS_SKIP_APPCAST must be 0 or 1" >&2
exit 64
fi
archive_path="$release_root/Mectrics.xcarchive"
export_path="$release_root/export"
export_options_path="$release_root/ExportOptions.plist"
staging_path="$release_root/dmg"
dmg_path="$release_root/Mectrics.dmg"
: "${MECTRICS_TEAM_ID:?Set MECTRICS_TEAM_ID to your Apple Developer Team ID.}"
# xcodegen reads this to fill DEVELOPMENT_TEAM, which is not committed in project.yml.
export MECTRICS_TEAM_ID
: "${MECTRICS_NOTARY_PROFILE:?Set MECTRICS_NOTARY_PROFILE to a notarytool keychain profile.}"
MECTRICS_SIGNING_IDENTITY=${MECTRICS_SIGNING_IDENTITY:-Developer ID Application}
command -v xcodegen >/dev/null
xcrun notarytool history --keychain-profile "$MECTRICS_NOTARY_PROFILE" >/dev/null
mkdir -p "$release_root"
xcodegen generate
rm -rf "$archive_path" "$export_path"
xcodebuild archive \
-project Mectrics.xcodeproj \
-scheme Mectrics \
-configuration Release \
-archivePath "$archive_path" \
-destination "generic/platform=macOS" \
ENABLE_CODE_COVERAGE=NO \
DEVELOPMENT_TEAM="$MECTRICS_TEAM_ID" \
CODE_SIGN_STYLE=Automatic \
-allowProvisioningUpdates
rm -f "$export_options_path"
plutil -create xml1 "$export_options_path"
plutil -insert method -string developer-id "$export_options_path"
plutil -insert signingStyle -string automatic "$export_options_path"
plutil -insert teamID -string "$MECTRICS_TEAM_ID" "$export_options_path"
xcodebuild -exportArchive \
-archivePath "$archive_path" \
-exportPath "$export_path" \
-exportOptionsPlist "$export_options_path" \
-allowProvisioningUpdates
app_path="$export_path/Mectrics.app"
cli_path="$app_path/Contents/Helpers/mectrics"
[[ -x "$cli_path" ]]
codesign --verify --strict --verbose=2 "$cli_path"
codesign --verify --deep --strict --verbose=2 "$app_path"
"$cli_path" --version
"$cli_path" --help >/dev/null
if "$cli_path" invalid-release-smoke-command >/dev/null 2>&1; then
echo "CLI smoke test unexpectedly accepted an invalid command" >&2
exit 1
else
cli_usage_status=$?
fi
[[ "$cli_usage_status" -eq 64 ]]
rm -rf "$staging_path"
mkdir -p "$staging_path"
ditto "$app_path" "$staging_path/Mectrics.app"
ln -s /Applications "$staging_path/Applications"
rm -f "$dmg_path"
hdiutil create \
-volname "Mectrics" \
-srcfolder "$staging_path" \
-ov \
-format UDZO \
"$dmg_path"
codesign --force \
--timestamp \
--sign "$MECTRICS_SIGNING_IDENTITY" \
"$dmg_path"
codesign --verify --strict --verbose=2 "$dmg_path"
xcrun notarytool submit "$dmg_path" \
--keychain-profile "$MECTRICS_NOTARY_PROFILE" \
--wait
xcrun stapler staple "$dmg_path"
xcrun stapler validate "$dmg_path"
if [[ "$skip_appcast" == 1 ]]; then
version=$(defaults read "$app_path/Contents/Info" CFBundleShortVersionString)
echo
echo "Private candidate ready: $dmg_path"
echo "Version: $version"
echo "Appcast: unchanged"
echo
echo "This candidate is signed, notarized, and stapled, but it has not been published."
exit 0
fi
# ---- appcast
#
# SUFeedURL points at appcast.xml on the main branch, so a release is not finished
# until that file describes it. generate_appcast signs each entry with the private
# EdDSA key from the login Keychain, the half that never leaves this machine.
version=$(defaults read "$app_path/Contents/Info" CFBundleShortVersionString)
appcast_tool=${MECTRICS_APPCAST_TOOL:-$(command -v generate_appcast || true)}
if [[ -z "$appcast_tool" ]]; then
appcast_tool=$(find "$HOME/Library/Developer/Xcode/DerivedData" \
-path '*artifacts/sparkle/Sparkle/bin/generate_appcast' -print -quit 2>/dev/null || true)
fi
: "${appcast_tool:?Could not find generate_appcast. Set MECTRICS_APPCAST_TOOL to its path.}"
# generate_appcast reads a directory of archives, so give it one holding only the DMG.
appcast_staging="$release_root/appcast"
rm -rf "$appcast_staging"
mkdir -p "$appcast_staging"
cp "$dmg_path" "$appcast_staging/"
"$appcast_tool" \
--download-url-prefix "https://github.com/farukkamcici/mectrics/releases/download/v$version/" \
--maximum-versions 5 \
-o "$repo_root/appcast.xml" \
"$appcast_staging"
echo
echo "Release ready: $dmg_path"
echo "Appcast: $repo_root/appcast.xml (version $version)"
echo
echo "Next: create the v$version tag and GitHub Release, attach the DMG, then commit"
echo "appcast.xml — the enclosure URL above only resolves once the release exists."