Skip to content

Commit c2482d6

Browse files
author
Brandon Evans
authored
Merge pull request #42 from RobotsAndPencils/enhancement/13-softwareUpdates
Enhancement 13: A software update mechanism (step 1 of 3)
2 parents 808dd02 + 6e0daa5 commit c2482d6

File tree

7 files changed

+162
-3
lines changed

7 files changed

+162
-3
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ DerivedData/
2929
*.ipa
3030
*.dSYM.zip
3131
*.dSYM
32+
Archive/*
33+
Product/*
3234

3335
## Playgrounds
3436
timeline.xctimeline

README.md

+36
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,42 @@ Notable design decisions are recorded in [DECISIONS.md](./DECISIONS.md). The App
2929

3030
[`xcode-install`](https://github.com/xcpretty/xcode-install) and [fastlane/spaceship](https://github.com/fastlane/fastlane/tree/master/spaceship) both deserve credit for figuring out the hard parts of what makes this possible.
3131

32+
## Releasing a new version
33+
34+
Follow the steps below to build and release a new version of Xcodes.app. For any of the git steps, you can use your preferred tool, but please sign the tag.
35+
36+
```sh
37+
# Update the version number in Xcode and commit the change, if necessary
38+
39+
# Increment the build number
40+
scripts/increment_build_number.sh
41+
42+
# Commit the change
43+
git add Xcodes/Resources/Info.plist
44+
git commit -asm "Increment build number"
45+
46+
# Tag the latest commit
47+
# Replace $VERSION and $BUILD below with the latest real values
48+
git tag -asm "v$VERSION.b$BUILD" "v$VERSION.b$BUILD"
49+
50+
# Push to origin
51+
git push --follow-tags
52+
53+
# Build the app
54+
scripts/package_release.sh
55+
56+
# Notarize the app
57+
scripts/notarize.sh "[email protected]" "@keychain:altool" MyOrg Product/Xcodes.zip
58+
59+
# Go to https://github.com/RobotsAndPencils/XcodesApp/releases
60+
# Edit the latest draft release
61+
# Set its tag to the tag you just pushed
62+
# Set its title to a string with the format "$VERSION ($BUILD)"
63+
# Polish the draft release notes, if necessary
64+
# Attach the zip that was created in the Product directory to the release
65+
# Publish the release
66+
```
67+
3268
## Contact
3369

3470
<a href="http://www.robotsandpencils.com"><img src="R&PLogo.png" width="153" height="74" /></a>

Scripts/export_options.plist

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>method</key>
6+
<string>developer-id</string>
7+
</dict>
8+
</plist>

Scripts/increment_build_number.sh

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/bin/sh
2+
#
3+
# Increment build number
4+
#
5+
# This will get the latest build number from git tags, add 1, then set it in the Info.plist.
6+
# Assumes that build numbers are monotonically increasing positive integers, across version numbers.
7+
# Tags must be named v$version_numberb$build_number, e.g. v1.2.3b456
8+
9+
infoplist_file="$(pwd)/Xcodes/Resources/Info.plist"
10+
11+
# Get latest tag hash matching pattern
12+
hash=$(git rev-list --tags="v" --max-count=1)
13+
# Get latest tag at hash that matches the same pattern as a prefix in order to support commits with multiple tags
14+
last_tag=$(git describe --tags --match "v*" "$hash")
15+
# Get build number from last component of tag name
16+
last_build_number=$(echo "$last_tag" | grep -o "b.*" | cut -c 2-)
17+
18+
build_number=$(($last_build_number + 1))
19+
20+
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $build_number" "${infoplist_file}"

Scripts/notarize.sh

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#!/bin/sh
2+
#
3+
# Notarize
4+
#
5+
# Uploads to Apple's notarization service, polls until it completes, staples the ticket to the built app, then creates a new zip.
6+
#
7+
# Requires four arguments:
8+
# - Apple ID username
9+
# - Apple ID app-specific password (store this in your Keychain and use the @keychain:$NAME syntax to prevent your password from being added to your shell history)
10+
# - App Store Connect provider name
11+
# - Path to .app to upload
12+
#
13+
# Assumes that there's a .app beside the .zip with the same name so it can be stapled and re-zipped.
14+
#
15+
# E.g. notarize.sh "[email protected]" "@keychain:altool" MyOrg Xcodes.zip
16+
#
17+
# https://developer.apple.com/documentation/xcode/notarizing_macos_software_before_distribution/customizing_the_notarization_workflow
18+
# Adapted from https://github.com/keybase/client/blob/46f5df0aa64ff19198ba7b044bbb7cd907c0be9f/packaging/desktop/package_darwin.sh
19+
20+
username="$1"
21+
password="$2"
22+
asc_provider="$3"
23+
file="$4"
24+
25+
echo "Uploading to notarization service"
26+
27+
uuid=$(xcrun altool \
28+
--notarize-app \
29+
--primary-bundle-id "com.robotsandpencils.XcodesApp.zip" \
30+
--username "$username" \
31+
--password "$password" \
32+
--asc-provider "$asc_provider" \
33+
--file "$file" 2>&1 | \
34+
grep 'RequestUUID' | \
35+
awk '{ print $3 }')
36+
37+
echo "Successfully uploaded to notarization service, polling for result: $uuid"
38+
39+
sleep 15
40+
while :
41+
do
42+
fullstatus=$(xcrun altool \
43+
--notarization-info "$uuid" \
44+
--username "$username" \
45+
--password "$password" \
46+
--asc-provider "$asc_provider" 2>&1)
47+
status=$(echo "$fullstatus" | grep 'Status\:' | awk '{ print $2 }')
48+
if [ "$status" = "success" ]; then
49+
echo "Notarization success"
50+
exit 0
51+
elif [ "$status" = "in" ]; then
52+
echo "Notarization still in progress, sleeping for 15 seconds and trying again"
53+
sleep 15
54+
else
55+
echo "Notarization failed, full status below"
56+
echo "$fullstatus"
57+
exit 1
58+
fi
59+
done
60+
61+
# Remove .zip
62+
rm $file
63+
64+
# Staple ticket to .app
65+
app_path="$(basename -s ".zip" "$file").app"
66+
xcrun stapler staple "$app_path"
67+
68+
# Zip the stapled app for distribution
69+
zip -r "$file" "$app_path"

Scripts/package_release.sh

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/bin/bash
2+
#
3+
# Package release
4+
#
5+
# This will build and archive the app and then compress it in a .zip file at Product/Xcodes.zip
6+
# You must already have all required code signing assets installed on your computer
7+
8+
PROJECT_NAME=Xcodes
9+
PROJECT_DIR=$(pwd)/$PROJECT_NAME/Resources
10+
SCRIPTS_DIR=$(pwd)/Scripts
11+
INFOPLIST_FILE="Info.plist"
12+
13+
# Ensure a clean build
14+
rm -rf Archive/*
15+
rm -rf Product/*
16+
xcodebuild clean -project $PROJECT_NAME.xcodeproj -configuration Release -alltargets
17+
18+
# Archive the app and export for release distribution
19+
xcodebuild archive -project $PROJECT_NAME.xcodeproj -scheme $PROJECT_NAME -archivePath Archive/$PROJECT_NAME.xcarchive
20+
xcodebuild -archivePath Archive/$PROJECT_NAME.xcarchive -exportArchive -exportPath Product/$PROJECT_NAME -exportOptionsPlist "${SCRIPTS_DIR}/export_options.plist"
21+
cp -r "Product/$PROJECT_NAME/$PROJECT_NAME.app" "Product/$PROJECT_NAME.app"
22+
23+
# Create a ZIP archive suitable for altool.
24+
/usr/bin/ditto -c -k --keepParent "Product/$PROJECT_NAME.app" "Product/$PROJECT_NAME.zip"

Xcodes/Resources/Info.plist

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
<string>1.0.0</string>
2121
<key>CFBundleVersion</key>
2222
<string>1</string>
23+
<key>CODE_SIGNING_SUBJECT_ORGANIZATIONAL_UNIT</key>
24+
<string>$(CODE_SIGNING_SUBJECT_ORGANIZATIONAL_UNIT)</string>
2325
<key>LSMinimumSystemVersion</key>
2426
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
2527
<key>NSHumanReadableCopyright</key>
@@ -33,9 +35,7 @@
3335
<key>SMPrivilegedExecutables</key>
3436
<dict>
3537
<key>com.robotsandpencils.XcodesApp.Helper</key>
36-
<string>identifier &quot;com.robotsandpencils.XcodesApp.Helper&quot; and info [CFBundleShortVersionString] &gt;= &quot;1.0.0&quot; and anchor apple generic and certificate leaf[subject.OU] = &quot;$(CODE_SIGNING_SUBJECT_ORGANIZATIONAL_UNIT)&quot;</string>
38+
<string>identifier "com.robotsandpencils.XcodesApp.Helper" and info [CFBundleShortVersionString] &gt;= "1.0.0" and anchor apple generic and certificate leaf[subject.OU] = "$(CODE_SIGNING_SUBJECT_ORGANIZATIONAL_UNIT)"</string>
3739
</dict>
38-
<key>CODE_SIGNING_SUBJECT_ORGANIZATIONAL_UNIT</key>
39-
<string>$(CODE_SIGNING_SUBJECT_ORGANIZATIONAL_UNIT)</string>
4040
</dict>
4141
</plist>

0 commit comments

Comments
 (0)