Skip to content

CI/CD on macOS systems. #16

CI/CD on macOS systems.

CI/CD on macOS systems. #16

Workflow file for this run

name: CI/CD on macOS systems.
permissions:
contents: write
on:
push:
pull_request:
workflow_dispatch:
# Automatic cron build every 6 months to check if everything still works.
schedule:
- cron: "0 0 1 1/6 *"
jobs:
build:
runs-on: macos-latest
timeout-minutes: 60
env:
LAZBUILD_WITH_PATH: /Applications/Lazarus/lazbuild
MACOS_APP: enduser/trackereditor.app
PROGRAM_NAME_WITH_PATH: 'enduser/trackereditor'
BUILD_WITH_CERTIFICATE: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
PROJECT_LPI: source/project/tracker_editor/trackereditor.lpi
RELEASE_DMG_FILE: trackereditor_macOS_notarized_universal_binary.dmg
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Install Lazarus IDE
run: brew install --cask lazarus
- name: Install Create dmg
run: brew install create-dmg
- name: Build trackereditor app for Apple silicon (aarch64)
run: |
${{ env.LAZBUILD_WITH_PATH }} --build-all --build-mode=Release --widgetset=cocoa --cpu=aarch64 ${{ env.PROJECT_LPI }}
mv ${{ env.PROGRAM_NAME_WITH_PATH }} ${{ env.PROGRAM_NAME_WITH_PATH }}-aarch64
shell: bash
- name: Build trackereditor app for Intel Mac version (x86_64)
run: |
${{ env.LAZBUILD_WITH_PATH }} --build-all --build-mode=Release --widgetset=cocoa --cpu=x86_64 ${{ env.PROJECT_LPI }}
mv ${{ env.PROGRAM_NAME_WITH_PATH }} ${{ env.PROGRAM_NAME_WITH_PATH }}-x86_64
shell: bash
- name: Create a Universal macOS binary from aarch64 and x86_64
run: |
# Create a new Universal macOS binary
lipo -create -output ${{ env.PROGRAM_NAME_WITH_PATH }} ${{ env.PROGRAM_NAME_WITH_PATH }}-aarch64 ${{ env.PROGRAM_NAME_WITH_PATH }}-x86_64
# Remove these extra binary build. Not needed any more.
rm -f ${{ env.PROGRAM_NAME_WITH_PATH }}-*
shell: bash
- name: Extract latest program version from metainfo and update the Info.plist with it
env:
METAINFO_FILE: metainfo/io.github.gerryferdinandus.bittorrent-tracker-editor.metainfo.xml
run: |
TRACKER_EDITOR_VERSION=$(xmllint --xpath "string(/component/releases/release[1]/@version)" $METAINFO_FILE)
echo Program version: $TRACKER_EDITOR_VERSION
plutil -replace CFBundleShortVersionString -string $TRACKER_EDITOR_VERSION ${{ env.MACOS_APP }}/Contents/Info.plist
shell: bash
- name: Move program and icon into macOS .app
env:
ICON_FILE: 'metainfo/io.github.gerryferdinandus.bittorrent-tracker-editor.png'
run: |
PROGRAM_NAME_ONLY=$(basename -- "${{ env.PROGRAM_NAME_WITH_PATH }}")
# ------ Move program to app
# remove the previeus app version
rm -f "${{ env.MACOS_APP }}/Contents/MacOS/${PROGRAM_NAME_ONLY}"
# copy the program to the app version.
mv -f "${{ env.PROGRAM_NAME_WITH_PATH }}" "${{ env.MACOS_APP }}/Contents/MacOS"
# ------ Create icon set and move it into the app
iconset_folder="temp_folder.iconset"
rm -rf "${iconset_folder}"
mkdir -p "${iconset_folder}"
for s in 16 32 128 256 512; do
d=$(($s*2))
sips -Z $s $ICON_FILE --out "${iconset_folder}/icon_${s}x$s.png"
sips -Z $d $ICON_FILE --out "${iconset_folder}/icon_${s}[email protected]"
done
# create .icns icon file
iconutil -c icns "${iconset_folder}" -o "iconfile.icns"
rm -r "${iconset_folder}"
# move icon file to the app
mv -f "iconfile.icns" "${{ env.MACOS_APP }}/Contents/Resources"
# add icon to plist xml file CFBundleIconFile = "iconfile"
plutil -insert CFBundleIconFile -string "iconfile" "${{ env.MACOS_APP }}/Contents/Info.plist"
shell: bash
- name: Check CPU type generated by Lazbuild
run: |
lipo -archs "${{ env.MACOS_APP }}"/Contents/MacOS/trackereditor
lipo -archs "${{ env.MACOS_APP }}"/Contents/MacOS/trackereditor | grep -Fq x86_64
lipo -archs "${{ env.MACOS_APP }}"/Contents/MacOS/trackereditor | grep -Fq arm64
shell: bash
- name: Test App SSL connection
run: open "${{ env.MACOS_APP }}" --args -TEST_SSL
shell: bash
- name: Codesign macOS app bundle. If certificate is present.
if: ${{ env.BUILD_WITH_CERTIFICATE != '' }}
# This macOS Codesign step is copied from:
# https://federicoterzi.com/blog/automatic-code-signing-and-notarization-for-macos-apps-using-github-actions/
# This is a bit different from the previous version for Travis-CI build system to build bittorrent tracker editor
# More info https://developer.apple.com/forums/thread/128166
env:
MACOS_CERTIFICATE: ${{ secrets.PROD_MACOS_CERTIFICATE }}
MACOS_CERTIFICATE_PWD: ${{ secrets.PROD_MACOS_CERTIFICATE_PWD }}
MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }}
run: |
# Turn our base64-encoded certificate back to a regular .p12 file
echo $MACOS_CERTIFICATE | base64 --decode > certificate.p12
# We need to create a new keychain, otherwise using the certificate will prompt
# with a UI dialog asking for the certificate password, which we can't
# use in a headless CI environment
security create-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain
security import certificate.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PWD" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_CI_KEYCHAIN_PWD" build.keychain
# sign the app. -sign is the developer cetificate ID
/usr/bin/codesign --timestamp --force --options runtime --sign "$MACOS_CERTIFICATE_NAME" "${{ env.MACOS_APP }}"
shell: bash
- name: Create dmg file from the enduser/ folder
run: |
# Remove all txt file. There are not needed.
rm -f enduser/*.txt
# Build dmg image. https://github.com/create-dmg/create-dmg
create-dmg \
--volname "bittorrent-tracker-editor" \
--window-pos 200 120 \
--window-size 800 400 \
--icon "trackereditor.app" 200 190 \
--app-drop-link 600 185 \
${{ env.RELEASE_DMG_FILE }} \
"./enduser"
shell: bash
- name: Codesign dmg file. If certificate is present.
if: ${{ env.BUILD_WITH_CERTIFICATE != '' }}
env:
MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
run: |
/usr/bin/codesign --timestamp --force --options runtime --sign "$MACOS_CERTIFICATE_NAME" "${{ env.RELEASE_DMG_FILE }}"
shell: bash
- name: Notarize macOS DMG bundle. If certificate is present.
if: ${{ env.BUILD_WITH_CERTIFICATE != '' }}
env:
PROD_MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }}
PROD_MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }}
PROD_MACOS_NOTARIZATION_PWD: ${{ secrets.PROD_MACOS_NOTARIZATION_PWD }}
run: |
# Store the notarization credentials so that we can prevent a UI password dialog
# from blocking the CI
echo "Create keychain profile"
xcrun notarytool store-credentials "notarytool-profile" --apple-id "$PROD_MACOS_NOTARIZATION_APPLE_ID" --team-id "$PROD_MACOS_NOTARIZATION_TEAM_ID" --password "$PROD_MACOS_NOTARIZATION_PWD"
# We can't notarize an app bundle directly, but we need to compress it as an archive.
# Therefore, we create a zip file containing our app bundle, so that we can send it to the
# notarization service
echo "Creating temp notarization archive"
ditto -c -k --keepParent "${{ env.RELEASE_DMG_FILE }}" "notarization.zip"
# Here we send the notarization request to the Apple's Notarization service, waiting for the result.
# This typically takes a few seconds inside a CI environment, but it might take more depending on the App
# characteristics. Visit the Notarization docs for more information and strategies on how to optimize it if
# you're curious
echo "Notarize app"
xcrun notarytool submit "notarization.zip" --keychain-profile "notarytool-profile" --wait
# Finally, we need to "attach the staple" to our executable, which will allow our app to be
# validated by macOS even when an internet connection is not available.
echo "Attach staple"
xcrun stapler staple "${{ env.RELEASE_DMG_FILE }}"
shell: bash
- name: Use diferent .dmg file name for non signed/notarize version
if: ${{ env.BUILD_WITH_CERTIFICATE == '' }}
run: mv ${{ env.RELEASE_DMG_FILE }} trackereditor_macOS_UNSIGNED_universal_binary.dmg
shell: bash
- name: Upload Artifact. Signed/Notarize is optional.
uses: actions/upload-artifact@v4
with:
name: artifact-${{ runner.os }}
path: "*.dmg"
compression-level: 0 # no compression. Content is already a zip file
if-no-files-found: error
- name: Notarize file release to end user. If certificate is present.
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/') && (env.BUILD_WITH_CERTIFICATE != '')
with:
files: ${{ env.RELEASE_DMG_FILE }}