Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions PReek.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@
6C1CB6FD2C92344200305288 /* RevealSecureField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C1CB6FC2C92342F00305288 /* RevealSecureField.swift */; };
6C1F49B82CB5BB9B00C30677 /* SafeArrayIndex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C1F49B72CB5BB9300C30677 /* SafeArrayIndex.swift */; };
6C1F49B92CB5BB9B00C30677 /* SafeArrayIndex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C1F49B72CB5BB9300C30677 /* SafeArrayIndex.swift */; };
E300212E25D94E51B33AB453 /* PullRequestUnreadCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E300212F25D94E51B33AB454 /* PullRequestUnreadCalculator.swift */; };
AB76BF5A49F34BF6B75F6415 /* PullRequestUnreadCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E300212F25D94E51B33AB454 /* PullRequestUnreadCalculator.swift */; };
6C232DE72C08C51D00C003B1 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 6C232DE62C08C51D00C003B1 /* KeychainAccess */; };
6C232DEB2C08C95E00C003B1 /* ConfigViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C232DEA2C08C95E00C003B1 /* ConfigViewModel.swift */; };
6C232DED2C08CB9600C003B1 /* KeychainStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C232DEC2C08CB9600C003B1 /* KeychainStorage.swift */; };
Expand Down Expand Up @@ -121,8 +119,11 @@
6CE564162C011BAE008E9A4B /* toPullRequests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CE564152C011BAE008E9A4B /* toPullRequests.swift */; };
6CE5641A2C013529008E9A4B /* PullRequestsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CE564192C013529008E9A4B /* PullRequestsViewModel.swift */; };
6CF15A542C03909900A7CE3E /* SettingsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CF15A532C03909900A7CE3E /* SettingsScreen.swift */; };
6CFBFDBD2EA7A58400DAD857 /* build-dmg.sh in Resources */ = {isa = PBXBuildFile; fileRef = 6CFBFDBC2EA7A57800DAD857 /* build-dmg.sh */; };
6CFE0C732D86FD5C00985A1C /* CodeScanner in Frameworks */ = {isa = PBXBuildFile; platformFilter = ios; productRef = 6CFE0C722D86FD5C00985A1C /* CodeScanner */; };
6CFE0C752D87217E00985A1C /* ImportSheetModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CFE0C742D87217800985A1C /* ImportSheetModifier.swift */; };
AB76BF5A49F34BF6B75F6415 /* PullRequestUnreadCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E300212F25D94E51B33AB454 /* PullRequestUnreadCalculator.swift */; };
E300212E25D94E51B33AB453 /* PullRequestUnreadCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E300212F25D94E51B33AB454 /* PullRequestUnreadCalculator.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand All @@ -145,7 +146,6 @@
6C1CB6F62C921CCF00305288 /* IfView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IfView.swift; sourceTree = "<group>"; };
6C1CB6FC2C92342F00305288 /* RevealSecureField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RevealSecureField.swift; sourceTree = "<group>"; };
6C1F49B72CB5BB9300C30677 /* SafeArrayIndex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafeArrayIndex.swift; sourceTree = "<group>"; };
E300212F25D94E51B33AB454 /* PullRequestUnreadCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PullRequestUnreadCalculator.swift; sourceTree = "<group>"; };
6C232DEA2C08C95E00C003B1 /* ConfigViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigViewModel.swift; sourceTree = "<group>"; };
6C232DEC2C08CB9600C003B1 /* KeychainStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainStorage.swift; sourceTree = "<group>"; };
6C232DEE2C08F6C600C003B1 /* ConfigService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigService.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -214,7 +214,9 @@
6CE564152C011BAE008E9A4B /* toPullRequests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = toPullRequests.swift; sourceTree = "<group>"; };
6CE564192C013529008E9A4B /* PullRequestsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PullRequestsViewModel.swift; sourceTree = "<group>"; };
6CF15A532C03909900A7CE3E /* SettingsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreen.swift; sourceTree = "<group>"; };
6CFBFDBC2EA7A57800DAD857 /* build-dmg.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "build-dmg.sh"; sourceTree = "<group>"; };
6CFE0C742D87217800985A1C /* ImportSheetModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportSheetModifier.swift; sourceTree = "<group>"; };
E300212F25D94E51B33AB454 /* PullRequestUnreadCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PullRequestUnreadCalculator.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFileSystemSynchronizedRootGroup section */
Expand Down Expand Up @@ -338,6 +340,7 @@
6C043E4F2C68DE6D00DEBF35 /* README.md */,
6C19E97B2C68AE130035845C /* Localizable.xcstrings */,
6CB720452C725FA70067CA1D /* ExportOptions.plist */,
6CFBFDBC2EA7A57800DAD857 /* build-dmg.sh */,
6CB027232BFF817E00C4C3B1 /* Products */,
);
sourceTree = "<group>";
Expand Down Expand Up @@ -565,6 +568,7 @@
6CDC9FAD2C75C8C5005FAFFD /* .gitignore in Resources */,
6C043E522C68DE9C00DEBF35 /* .github in Resources */,
6CDC9FAE2C75C8C5005FAFFD /* .swift-version in Resources */,
6CFBFDBD2EA7A58400DAD857 /* build-dmg.sh in Resources */,
6CDC9FB12C75C8FB005FAFFD /* .swiftformat in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
20 changes: 1 addition & 19 deletions PReek.xcodeproj/xcshareddata/xcschemes/PReek.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -86,24 +86,6 @@
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
<PostActions>
<ExecutionAction
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
<ActionContent
title = "Create Signed and Notarized DMG"
scriptText = "# Add brew binaries to path, needed for fnm and image tooling&#10;export PATH=$PATH:/opt/homebrew/bin&#10;&#10;# notarytool credentials.&#10;# AC_PASSWORD is the name of the keychain item created with `notarytool store-credentials`.&#10;# Grant keychain access to Xcode if prompted by Xcode.&#10;AC_PASSWORD=&quot;personal&quot;&#10;&#10;# Do all of the work in a subdirectory of /tmp, and use a&#10;# unique ID so that there&apos;s no collision with previous builds.&#10;EXPORT_UUID=`uuidgen`&#10;EXPORT_PATH=&quot;/tmp/$PRODUCT_NAME-$EXPORT_UUID&quot;&#10;APP_NAME=&quot;$PRODUCT_NAME.app&quot;&#10;# Needs to match what create-dmg outputs&#10;CREATE_DMG_PATH=&quot;$EXPORT_PATH/$PRODUCT_NAME $MARKETING_VERSION.dmg&quot;&#10;DMG_PATH=&quot;$EXPORT_PATH/$PRODUCT_NAME-$MARKETING_VERSION.dmg&quot;&#10;&#10;mkdir -p &quot;$EXPORT_PATH&quot;&#10;&#10;# Open the folder that was created&#10;open &quot;$EXPORT_PATH&quot;&#10;&#10;# Xcode doesn&apos;t show run script errors in build log.&#10;exec &gt; &quot;$EXPORT_PATH/Xcode run script.log&quot; 2&gt;&amp;1&#10;&#10;# Use osascript(1) to present notification banners; otherwise&#10;# there&apos;s no progress indication until the script finishes.&#10;/usr/bin/osascript -e &apos;display notification &quot;Exporting application archive&#x2026;&quot; with title &quot;Submitting app for notarization&quot;&apos;&#10;&#10;# Ask xcodebuild(1) to export the app.&#10;/usr/bin/xcodebuild -exportArchive -archivePath &quot;$ARCHIVE_PATH&quot; -exportOptionsPlist &quot;$SRCROOT/ExportOptions.plist&quot; -exportPath &quot;$EXPORT_PATH&quot;&#10;&#10;if [ $? -ne 0 ]; then&#10; /usr/bin/osascript -e &apos;display notification &quot;Export of application archive failed&quot; with title &quot;Submitting app for notarization&quot;&apos;&#10; open &quot;$EXPORT_PATH/Xcode run script.log&quot;&#10; exit 1&#10;fi&#10;&#10;osascript -e &apos;display notification &quot;Creating DMG&quot; with title &quot;Submitting app for notarization&quot;&apos;&#10;&#10;# Ensure correct node version&#10;# Requires fnm to be installed&#10;eval &quot;$(fnm env)&quot;&#10;fnm use v20.9.0&#10;&#10;if [ $? -ne 0 ]; then&#10; /usr/bin/osascript -e &apos;display notification &quot;Creating DMG failed while ensuring node version with fnm&quot; with title &quot;Submitting app for notarization&quot;&apos;&#10; open &quot;$EXPORT_PATH/Xcode run script.log&quot;&#10; exit 1&#10;fi&#10;&#10;# Create DMG using create-dmg (requires python and python-setuptools to be installed!)&#10;# For icons to be set correctly, also required graphicsmagick and imagemagick to be installed&#10;# More info under https://github.com/sindresorhus/create-dmg&#10;(cd $EXPORT_PATH &amp;&amp; npx --yes create-dmg@7.0.0 &quot;$APP_NAME&quot;)&#10;&#10;if [ $? -ne 0 ]; then&#10; /usr/bin/osascript -e &apos;display notification &quot;Creating DMG failed, retrying once&quot; with title &quot;Submitting app for notarization&quot;&apos;&#10; (cd $EXPORT_PATH &amp;&amp; npx --yes create-dmg@7.0.0 --overwrite &quot;$APP_NAME&quot;)&#10;&#10; if [ $? -ne 0 ]; then&#10; /usr/bin/osascript -e &apos;display notification &quot;Creating DMG failed again, aborting&quot; with title &quot;Submitting app for notarization&quot;&apos;&#10; open &quot;$EXPORT_PATH/Xcode run script.log&quot;&#10; exit 1&#10; fi&#10;fi&#10;&#10;mv &quot;$CREATE_DMG_PATH&quot; &quot;$DMG_PATH&quot;&#10;&#10;osascript -e &apos;display notification &quot;Submitting DMG for notarization&#x2026;&quot; with title &quot;Submitting app for notarization&quot;&apos;&#10;&#10;# Submit the finished deliverables for notarization.&#10;# Wait up to 2 hours for a response.&#10;# Use verbose logging in order to file feedback if an error occurs.&#10;&quot;$DEVELOPER_BIN_DIR/notarytool&quot; submit -p &quot;$AC_PASSWORD&quot; --verbose &quot;$DMG_PATH&quot; --wait --timeout 2h --output-format plist &gt; &quot;$EXPORT_PATH/NotarizationResponse.plist&quot;&#10;&#10;if [ $? -eq 0 ]; then&#10; message=`/usr/libexec/PlistBuddy -c &quot;Print :message&quot; &quot;$EXPORT_PATH/NotarizationResponse.plist&quot;`&#10; status=`/usr/libexec/PlistBuddy -c &quot;Print :status&quot; &quot;$EXPORT_PATH/NotarizationResponse.plist&quot;`&#10;else&#10; /usr/bin/osascript -e &apos;display notification &quot;Failed to submit DMG for notarization&quot; with title &quot;Submitting app for notarization&quot;&apos;&#10; open &quot;$EXPORT_PATH/Xcode run script.log&quot;&#10; exit 1&#10;fi&#10;&#10;osascript -e &quot;display notification \&quot;$message: $status\&quot; with title \&quot;Submitting app for notarization\&quot;&quot;&#10;&#10;osascript -e &apos;display notification &quot;Stapling notarization ticket to DMG&quot; with title &quot;Submitting app for notarization&quot;&apos;&#10;&#10;&quot;$DEVELOPER_BIN_DIR/stapler&quot; staple &quot;$DMG_PATH&quot; &#10;&#10;if [ $? -ne 0 ]; then&#10; /usr/bin/osascript -e &apos;display notification &quot;Failed stapling ticket to DMG&quot; with title &quot;Submitting app for notarization&quot;&apos;&#10; open &quot;$EXPORT_PATH/Xcode run script.log&quot;&#10; exit 1&#10;fi&#10;&#10;osascript -e &apos;display notification &quot;Sucessfully stapled DMG with ticket&quot; with title &quot;Submitting app for notarization&quot;&apos;&#10;">
<EnvironmentBuildable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6CB027212BFF817E00C4C3B1"
BuildableName = "PReek.app"
BlueprintName = "PReek"
ReferencedContainer = "container:PReek.xcodeproj">
</BuildableReference>
</EnvironmentBuildable>
</ActionContent>
</ExecutionAction>
</PostActions>
revealArchiveInOrganizer = "NO">
</ArchiveAction>
</Scheme>
148 changes: 148 additions & 0 deletions build-dmg.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
#!/bin/bash

# Exit on error
set -e

# Configuration
SCHEME_NAME="PReek"
PROJECT_PATH="PReek.xcodeproj"
EXPORT_OPTIONS_PLIST="./ExportOptions.plist"
AC_PASSWORD="personal" # Keychain item name for notarytool credentials created via `notarytool store-credentials`

PRODUCT_NAME="PReek"
MARKETING_VERSION=$(xcodebuild -showBuildSettings -scheme "$SCHEME_NAME" -project "$PROJECT_PATH" -destination "platform=macOS,arch=arm64" 2>&1 | grep MARKETING_VERSION | awk '{print $3}')

# Create unique build directory
EXPORT_UUID=$(uuidgen)
BUILD_PATH="/tmp/$PRODUCT_NAME-build-$EXPORT_UUID"
ARCHIVE_PATH="$BUILD_PATH/$PRODUCT_NAME.xcarchive"
DMG_PATH="$BUILD_PATH/$PRODUCT_NAME-$MARKETING_VERSION.dmg"
LOGS_PATH="$BUILD_PATH/logs"

mkdir -p "$BUILD_PATH"
mkdir -p "$LOGS_PATH"

# Open the export folder
open "$BUILD_PATH"

echo "=== Starting Build Process ==="
echo "Detected version: $MARKETING_VERSION"
echo "Build directory: $BUILD_PATH"
echo "Archive path: $ARCHIVE_PATH"
echo "Logs directory: $LOGS_PATH"
echo ""

# Step 1: Create Archive
echo "=== Creating Archive ==="
xcodebuild archive \
-scheme "$SCHEME_NAME" \
-project "$PROJECT_PATH" \
-destination "platform=macOS,arch=arm64" \
-archivePath "$ARCHIVE_PATH" \
-configuration Release \
CODE_SIGN_STYLE=Automatic \
-allowProvisioningUpdates \
> "$LOGS_PATH/01-archive.log" 2>&1

if [ $? -ne 0 ]; then
echo "Archive creation failed. Check log: $LOGS_PATH/01-archive.log"
exit 1
fi

echo "Archive created successfully"
echo ""

# Step 2: Export Archive
echo "=== Exporting Archive ==="
xcodebuild -exportArchive \
-archivePath "$ARCHIVE_PATH" \
-exportOptionsPlist "$EXPORT_OPTIONS_PLIST" \
-exportPath "$BUILD_PATH" \
-allowProvisioningUpdates \
> "$LOGS_PATH/02-export.log" 2>&1

if [ $? -ne 0 ]; then
echo "Export of application archive failed. Check log: $LOGS_PATH/02-export.log"
exit 1
fi

echo "Export completed successfully"
echo ""

# Step 3: Setup Node environment
echo "=== Setting up Node Environment ==="
fnm use v22 > "$LOGS_PATH/03-fnm.log" 2>&1

if [ $? -ne 0 ]; then
echo "Failed to set Node version with fnm. Check log: $LOGS_PATH/03-fnm.log"
exit 1
fi

echo "Node environment ready"
echo ""

# Step 4: Create DMG
echo "=== Creating DMG ==="

pushd "$BUILD_PATH" > /dev/null

npm install --global create-dmg > "$LOGS_PATH/04-npm-install.log" 2>&1

if [ $? -ne 0 ]; then
echo "npm install failed. Check log: $LOGS_PATH/04-npm-install.log"
exit 1
fi

create-dmg --no-version-in-filename "$PRODUCT_NAME.app" > "$LOGS_PATH/05-create-dmg.log" 2>&1

if [ $? -ne 0 ]; then
echo "Creating DMG failed. Check log: $LOGS_PATH/05-create-dmg.log"
exit 1
fi

# Rename DMG to expected name incl. version
mv "$PRODUCT_NAME.dmg" "$DMG_PATH"

popd > /dev/null

echo "DMG created successfully: $DMG_PATH"
echo ""

# Step 5: Submit for Notarization
echo "=== Submitting for Notarization ==="
xcrun notarytool submit \
-p "$AC_PASSWORD" \
--verbose \
"$DMG_PATH" \
--wait \
--timeout 2h \
--output-format plist > "$BUILD_PATH/NotarizationResponse.plist" 2> "$LOGS_PATH/06-notarization.log"

if [ $? -eq 0 ]; then
message=$(/usr/libexec/PlistBuddy -c "Print :message" "$BUILD_PATH/NotarizationResponse.plist")
status=$(/usr/libexec/PlistBuddy -c "Print :status" "$BUILD_PATH/NotarizationResponse.plist")
echo "Notarization response: $message - $status"
else
echo "Failed to submit DMG for notarization. Check log: $LOGS_PATH/06-notarization.log"
exit 1
fi

echo "$message: $status"
echo ""

# Step 6: Staple Notarization Ticket
echo "=== Stapling Notarization Ticket ==="
xcrun stapler staple "$DMG_PATH" > "$LOGS_PATH/07-stapler.log" 2>&1

if [ $? -ne 0 ]; then
echo "Failed stapling ticket to DMG. Check log: $LOGS_PATH/07-stapler.log"
exit 1
fi

echo "Stapling completed successfully"
echo ""

# Success!
echo "=== Build Process Complete ==="
echo "Final DMG location: $DMG_PATH"
echo "Logs location: $LOGS_PATH"