From 33b3518365497a061ff89a67a2852c93ae7aa27b Mon Sep 17 00:00:00 2001 From: Jason Morley Date: Mon, 29 Jan 2024 14:58:49 -1000 Subject: [PATCH] ci: Automated macOS builds (#7) --- .github/workflows/build.yaml | 50 +++++ .gitmodules | 6 + ExportOptions.plist | 27 +++ Thoughts.xcodeproj/project.pbxproj | 10 +- Thoughts/Info.plist | 2 + ...hts_Mac_App_Store_Profile.provisionprofile | Bin 0 -> 12298 bytes scripts/build-tools | 1 + scripts/build.sh | 173 ++++++++++++++++++ scripts/changes | 1 + scripts/environment.sh | 32 ++++ scripts/install-dependencies.sh | 43 +++++ scripts/release.sh | 51 ++++++ 12 files changed, 394 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/build.yaml create mode 100644 ExportOptions.plist create mode 100644 Thoughts_Mac_App_Store_Profile.provisionprofile create mode 160000 scripts/build-tools create mode 100755 scripts/build.sh create mode 160000 scripts/changes create mode 100755 scripts/environment.sh create mode 100755 scripts/install-dependencies.sh create mode 100755 scripts/release.sh diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..822ec88 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,50 @@ +name: build + +on: + pull_request: + branches: [ main ] + push: + branches: [ main ] + schedule: + - cron: '0 9 * * *' + workflow_dispatch: + +jobs: + + macos-build: + + runs-on: inseven-macos-14 + + steps: + + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - name: Install dependencies + run: scripts/install-dependencies.sh + + - name: Build and test + env: + APPLE_DISTRIBUTION_CERTIFICATE_BASE64: ${{ secrets.PERSONAL_APPLE_DISTRIBUTION_CERTIFICATE_BASE64 }} + APPLE_DISTRIBUTION_CERTIFICATE_PASSWORD: ${{ secrets.PERSONAL_APPLE_DISTRIBUTION_CERTIFICATE_PASSWORD }} + MACOS_DEVELOPER_INSTALLER_CERTIFICATE_BASE64: ${{ secrets.PERSONAL_MACOS_DEVELOPER_INSTALLER_CERTIFICATE_BASE64 }} + MACOS_DEVELOPER_INSTALLER_CERTIFICATE_PASSWORD: ${{ secrets.PERSONAL_MACOS_DEVELOPER_INSTALLER_CERTIFICATE_PASSWORD }} + + APPLE_API_KEY_BASE64: ${{ secrets.PERSONAL_APPLE_API_KEY_BASE64 }} + APPLE_API_KEY_ISSUER_ID: ${{ secrets.PERSONAL_APPLE_API_KEY_ISSUER_ID }} + APPLE_API_KEY_ID: ${{ secrets.PERSONAL_APPLE_API_KEY_ID }} + + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RELEASE: ${{ github.ref == 'refs/heads/main' }} + + run: | + scripts/build.sh + + - name: Archive the binary + uses: actions/upload-artifact@v4 + with: + path: build/build-*.zip + if-no-files-found: error diff --git a/.gitmodules b/.gitmodules index e6acfdd..e4a644c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,9 @@ [submodule "interact"] path = interact url = git@github.com:inseven/interact.git +[submodule "scripts/changes"] + path = scripts/changes + url = https://github.com/jbmorley/changes.git +[submodule "scripts/build-tools"] + path = scripts/build-tools + url = https://github.com/jbmorley/build-tools.git diff --git a/ExportOptions.plist b/ExportOptions.plist new file mode 100644 index 0000000..e724516 --- /dev/null +++ b/ExportOptions.plist @@ -0,0 +1,27 @@ + + + + + destination + export + installerSigningCertificate + C44BC9291462AE6729496E2CAC18CE475688F8CD + manageAppVersionAndBuildNumber + + method + app-store + provisioningProfiles + + uk.co.jbmorley.thoughts.apps.appstore + Thoughts Mac App Store Profile + + signingCertificate + 91DADFE184A1526FA94D4513D5B4C75E1DB3B252 + signingStyle + manual + teamID + QS82QFHKWB + uploadSymbols + + + diff --git a/Thoughts.xcodeproj/project.pbxproj b/Thoughts.xcodeproj/project.pbxproj index 077b429..1b7a1f2 100644 --- a/Thoughts.xcodeproj/project.pbxproj +++ b/Thoughts.xcodeproj/project.pbxproj @@ -512,6 +512,7 @@ ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Thoughts/Info.plist; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; INFOPLIST_KEY_LSUIElement = YES; INFOPLIST_KEY_NSHumanReadableCopyright = ""; LD_RUNPATH_SEARCH_PATHS = ( @@ -532,15 +533,18 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = Thoughts/Thoughts.entitlements; - CODE_SIGN_STYLE = Automatic; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "3rd Party Mac Developer Application"; + CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"Thoughts/Preview Content\""; - DEVELOPMENT_TEAM = QS82QFHKWB; + DEVELOPMENT_TEAM = ""; + "DEVELOPMENT_TEAM[sdk=macosx*]" = QS82QFHKWB; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Thoughts/Info.plist; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; INFOPLIST_KEY_LSUIElement = YES; INFOPLIST_KEY_NSHumanReadableCopyright = ""; LD_RUNPATH_SEARCH_PATHS = ( @@ -550,6 +554,8 @@ MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = uk.co.jbmorley.thoughts.apps.appstore; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "Thoughts Mac App Store Profile"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; }; diff --git a/Thoughts/Info.plist b/Thoughts/Info.plist index 57dbbb8..a80edd5 100644 --- a/Thoughts/Info.plist +++ b/Thoughts/Info.plist @@ -15,5 +15,7 @@ + ITSAppUsesNonExemptEncryption + diff --git a/Thoughts_Mac_App_Store_Profile.provisionprofile b/Thoughts_Mac_App_Store_Profile.provisionprofile new file mode 100644 index 0000000000000000000000000000000000000000..ac1cbba29ac8c442c3472ea43668ccaf775b5f7c GIT binary patch literal 12298 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 CI!xOD literal 0 HcmV?d00001 diff --git a/scripts/build-tools b/scripts/build-tools new file mode 160000 index 0000000..c0f02d8 --- /dev/null +++ b/scripts/build-tools @@ -0,0 +1 @@ +Subproject commit c0f02d8da114357ce680a632355f295327565db5 diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000..22018e1 --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,173 @@ +#!/bin/bash + +# Copyright (c) 2024 Jason Morley +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +set -e +set -o pipefail +set -x +set -u + +SCRIPTS_DIRECTORY="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" + +ROOT_DIRECTORY="${SCRIPTS_DIRECTORY}/.." +BUILD_DIRECTORY="${ROOT_DIRECTORY}/build" +TEMPORARY_DIRECTORY="${ROOT_DIRECTORY}/temp" + +KEYCHAIN_PATH="${TEMPORARY_DIRECTORY}/temporary.keychain" +ARCHIVE_PATH="${BUILD_DIRECTORY}/Thoughts.xcarchive" +ENV_PATH="${ROOT_DIRECTORY}/.env" + +RELEASE_SCRIPT_PATH="${SCRIPTS_DIRECTORY}/release.sh" + +IOS_XCODE_PATH=${IOS_XCODE_PATH:-/Applications/Xcode.app} +MACOS_XCODE_PATH=${MACOS_XCODE_PATH:-/Applications/Xcode.app} + +source "${SCRIPTS_DIRECTORY}/environment.sh" + +# Check that the GitHub command is available on the path. +which gh || (echo "GitHub cli (gh) not available on the path." && exit 1) + +# Process the command line arguments. +POSITIONAL=() +RELEASE=${RELEASE:-false} +while [[ $# -gt 0 ]] +do + key="$1" + case $key in + -r|--release) + RELEASE=true + shift + ;; + *) + POSITIONAL+=("$1") + shift + ;; + esac +done + +# Generate a random string to secure the local keychain. +export TEMPORARY_KEYCHAIN_PASSWORD=`openssl rand -base64 14` + +# Source the .env file if it exists to make local development easier. +if [ -f "$ENV_PATH" ] ; then + echo "Sourcing .env..." + source "$ENV_PATH" +fi + +function xcode_project { + xcodebuild \ + -project Thoughts.xcodeproj "$@" +} + +function build_scheme { + # Disable code signing for the build server. + xcode_project \ + -scheme "$1" \ + CODE_SIGN_IDENTITY="" \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGNING_ALLOWED=NO "${@:2}" +} + +cd "$ROOT_DIRECTORY" + +# Select the correct Xcode. +sudo xcode-select --switch "$MACOS_XCODE_PATH" + +# List the available schemes. +xcode_project -list + +# Clean up the build directory. +if [ -d "$BUILD_DIRECTORY" ] ; then + rm -r "$BUILD_DIRECTORY" +fi +mkdir -p "$BUILD_DIRECTORY" + +# Create the a new keychain. +if [ -d "$TEMPORARY_DIRECTORY" ] ; then + rm -rf "$TEMPORARY_DIRECTORY" +fi +mkdir -p "$TEMPORARY_DIRECTORY" +echo "$TEMPORARY_KEYCHAIN_PASSWORD" | build-tools create-keychain "$KEYCHAIN_PATH" --password + +function cleanup { + + # Cleanup the temporary files, keychain and keys. + cd "$ROOT_DIRECTORY" + build-tools delete-keychain "$KEYCHAIN_PATH" + rm -rf "$TEMPORARY_DIRECTORY" + rm -rf ~/.appstoreconnect/private_keys +} + +trap cleanup EXIT + +# Determine the version and build number. +VERSION_NUMBER=`changes version` +BUILD_NUMBER=`build-number.swift` + +# Import the certificates into our dedicated keychain. +echo "$APPLE_DISTRIBUTION_CERTIFICATE_PASSWORD" | build-tools import-base64-certificate --password "$KEYCHAIN_PATH" "$APPLE_DISTRIBUTION_CERTIFICATE_BASE64" +echo "$MACOS_DEVELOPER_INSTALLER_CERTIFICATE_PASSWORD" | build-tools import-base64-certificate --password "$KEYCHAIN_PATH" "$MACOS_DEVELOPER_INSTALLER_CERTIFICATE_BASE64" + +# Install the provisioning profiles. +build-tools install-provisioning-profile "Thoughts_Mac_App_Store_Profile.provisionprofile" + +# Build and archive the macOS project. +sudo xcode-select --switch "$MACOS_XCODE_PATH" +xcode_project \ + -scheme "Thoughts" \ + -config Release \ + -archivePath "$ARCHIVE_PATH" \ + OTHER_CODE_SIGN_FLAGS="--keychain=\"${KEYCHAIN_PATH}\"" \ + CURRENT_PROJECT_VERSION=$BUILD_NUMBER \ + MARKETING_VERSION=$VERSION_NUMBER \ + clean archive +xcodebuild \ + -archivePath "$ARCHIVE_PATH" \ + -exportArchive \ + -exportPath "$BUILD_DIRECTORY" \ + -exportOptionsPlist "ExportOptions.plist" + +APP_BASENAME="Thoughts.app" +APP_PATH="$BUILD_DIRECTORY/$APP_BASENAME" +PKG_PATH="$BUILD_DIRECTORY/Thoughts.pkg" + +# Install the private key. +mkdir -p ~/.appstoreconnect/private_keys/ +echo -n "$APPLE_API_KEY_BASE64" | base64 --decode -o ~/".appstoreconnect/private_keys/AuthKey_${APPLE_API_KEY_ID}.p8" + +# Archive the build directory. +ZIP_BASENAME="build-${VERSION_NUMBER}-${BUILD_NUMBER}.zip" +ZIP_PATH="${BUILD_DIRECTORY}/${ZIP_BASENAME}" +pushd "${BUILD_DIRECTORY}" +zip -r "${ZIP_BASENAME}" . +popd + +if $RELEASE ; then + + changes \ + release \ + --skip-if-empty \ + --pre-release \ + --push \ + --exec "${RELEASE_SCRIPT_PATH}" \ + "${PKG_PATH}" "${ZIP_PATH}" + +fi diff --git a/scripts/changes b/scripts/changes new file mode 160000 index 0000000..f68484b --- /dev/null +++ b/scripts/changes @@ -0,0 +1 @@ +Subproject commit f68484bb984f324acca17e69e15f0bed94ee6cbd diff --git a/scripts/environment.sh b/scripts/environment.sh new file mode 100755 index 0000000..51caabe --- /dev/null +++ b/scripts/environment.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +# Copyright (c) 2024 Jason Morley +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +SCRIPTS_DIRECTORY="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +ROOT_DIRECTORY="${SCRIPTS_DIRECTORY}/.." + +export PYTHONUSERBASE="${ROOT_DIRECTORY}/.local/python" +mkdir -p "$PYTHONUSERBASE" +export PATH="${PYTHONUSERBASE}/bin":$PATH + +export PATH=$PATH:"${SCRIPTS_DIRECTORY}/changes" +export PATH=$PATH:"${SCRIPTS_DIRECTORY}/build-tools" +export PATH=$PATH:"${ROOT_DIRECTORY}/diligence/scripts" diff --git a/scripts/install-dependencies.sh b/scripts/install-dependencies.sh new file mode 100755 index 0000000..755e2a6 --- /dev/null +++ b/scripts/install-dependencies.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +# Copyright (c) 2024 Jason Morley +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +set -e +set -o pipefail +set -x +set -u + +SCRIPTS_DIRECTORY="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +ROOT_DIRECTORY="${SCRIPTS_DIRECTORY}/.." +CHANGES_DIRECTORY="${SCRIPTS_DIRECTORY}/changes" +BUILD_TOOLS_DIRECTORY="${SCRIPTS_DIRECTORY}/build-tools" + +ENVIRONMENT_PATH="${SCRIPTS_DIRECTORY}/environment.sh" + +if [ -d "${ROOT_DIRECTORY}/.local" ] ; then + rm -r "${ROOT_DIRECTORY}/.local" +fi +source "${ENVIRONMENT_PATH}" + +# Install the Python dependencies +pip3 install --user pipenv +PIPENV_PIPFILE="$CHANGES_DIRECTORY/Pipfile" pipenv install +PIPENV_PIPFILE="$BUILD_TOOLS_DIRECTORY/Pipfile" pipenv install diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100755 index 0000000..712f371 --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +# Copyright (c) 2016-2024 Jason Morley +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +set -e +set -o pipefail +set -x + +# This script expects the macOS PKG as the first argument, and any additional files to be attached to the GitHub release +# to be passed as subsequent arguments. + +# Upload the macOS build. +xcrun altool --upload-app \ + -f "$1" \ + --primary-bundle-id "uk.co.jbmorley.thoughts.apps.appstore" \ + --apiKey "$APPLE_API_KEY_ID" \ + --apiIssuer "$APPLE_API_KEY_ISSUER_ID" \ + --type macos + +# Actually make the release. +FLAGS=() +if $CHANGES_INITIAL_DEVELOPMENT ; then + FLAGS+=("--prerelease") +elif $CHANGES_PRE_RELEASE ; then + FLAGS+=("--prerelease") +fi +gh release create "$CHANGES_TAG" --title "$CHANGES_QUALIFIED_TITLE" --notes-file "$CHANGES_NOTES_FILE" "${FLAGS[@]}" + +# Upload the attachments. +for attachment in "$@" +do + gh release upload "$CHANGES_TAG" "$attachment" +done