1+ # CI/CD workflow for macOS systems to build bittorrent tracker editor app
2+ # Uses GitHub Actions macOS runners to build the app for both Apple silicon (aarch64) and Intel Mac (x86_64)
3+ # Then create a Universal binary using lipo tool.
4+ # Finally create a dmg file for end user distribution.
5+ # The build also codesign and notarize the dmg file if the required Apple developer certificate
6+ # and notarization credentials are present in the GitHub secrets.
7+ # The build is triggered on push, pull request, manual workflow dispatch and every 6 months cron job.
8+ #
9+ # macos-15-intel runner is used to build the x86_64 version.
10+ # macos-latest runner is used to build the aarch64 version and also to create the Universal binary dmg file.
11+ # The build uses Free Pascal Compiler (FPC) and Lazarus IDE to build the app.
12+ #
13+ # macos-15-intel runner is the last macOS runner that supports Intel architecture.
14+ # Newer macOS runners only support Apple silicon (aarch64) architecture.
15+ # Keep supporting Intel architecture build while there runners are still available.
16+ #
17+ # Must use macOS ditto tool to create zip files.
18+ # Using zip command creates zip files that missing some metadata required for macOS apps.
19+
20+
121name : CI/CD on macOS systems.
222
323permissions :
1131 schedule :
1232 - cron : " 0 0 1 1/6 *"
1333
34+ env :
35+ MACOS_APP : enduser/trackereditor.app
36+ PROGRAM_NAME_WITH_PATH : ' enduser/trackereditor'
37+ BUILD_WITH_CERTIFICATE : ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
38+ PROJECT_LPI : source/project/tracker_editor/trackereditor.lpi
39+ RELEASE_DMG_FILE : trackereditor_macOS_notarized_universal_binary.dmg
40+ # Copied the latest Lazarus source code from: https://sourceforge.net/projects/lazarus/files/Lazarus%20Zip%20_%20GZip/
41+ LAZARUS_URL_TAR_GZ : " https://github.com/GerryFerdinandus/bittorrent-tracker-editor/releases/download/V1.32.0/lazarus.tar.gz"
42+
1443jobs :
15- build :
44+ build_aarch64 : # Build for Apple silicon Mac architecture
1645 runs-on : macos-latest
1746 timeout-minutes : 60
18- env :
19- MACOS_APP : enduser/trackereditor.app
20- PROGRAM_NAME_WITH_PATH : ' enduser/trackereditor'
21- BUILD_WITH_CERTIFICATE : ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
22- PROJECT_LPI : source/project/tracker_editor/trackereditor.lpi
23- RELEASE_DMG_FILE : trackereditor_macOS_notarized_universal_binary.dmg
24- # Copied the latest Lazarus source code from: https://sourceforge.net/projects/lazarus/files/Lazarus%20Zip%20_%20GZip/
25- LAZARUS_URL_TAR_GZ : " https://github.com/GerryFerdinandus/bittorrent-tracker-editor/releases/download/V1.32.0/lazarus.tar.gz"
26-
2747 steps :
28- - uses : actions/checkout@v4
48+ - uses : actions/checkout@v5
2949 with :
3050 submodules : true
3151
3252 - name : Install Free Pascal Compiler (FPC) multi arch version for macOS x86_64 and aarch64
33- run : brew install --cask fpc-laz
53+ run : brew install fpc
3454 shell : bash
3555
36- - name : Install Create dmg
37- run : brew install create-dmg
38-
3956 - name : Download Lazarus source code into temp folder
4057 run : |
4158 #Download lazarus source code. Directory 'lazarus' will be created in the temp folder.
@@ -59,25 +76,13 @@ jobs:
5976 - name : Build trackereditor app for Apple silicon (aarch64)
6077 run : |
6178 lazbuild --build-all --build-mode=Release --widgetset=cocoa --cpu=aarch64 ${{ env.PROJECT_LPI }}
62- mv ${{ env.PROGRAM_NAME_WITH_PATH }} ${{ env.PROGRAM_NAME_WITH_PATH }}-aarch64
6379 shell : bash
6480
65- - name : Build trackereditor app for Intel Mac version (x86_64)
66- run : |
67- lazbuild --build-all --build-mode=Release --widgetset=cocoa --cpu=x86_64 ${{ env.PROJECT_LPI }}
68- mv ${{ env.PROGRAM_NAME_WITH_PATH }} ${{ env.PROGRAM_NAME_WITH_PATH }}-x86_64
69- shell : bash
70-
71- - name : Create a Universal macOS binary from aarch64 and x86_64
72- run : |
73- # Create a new Universal macOS binary
74- lipo -create -output ${{ env.PROGRAM_NAME_WITH_PATH }} ${{ env.PROGRAM_NAME_WITH_PATH }}-aarch64 ${{ env.PROGRAM_NAME_WITH_PATH }}-x86_64
75-
76- # Remove these extra binary build. Not needed any more.
77- rm -f ${{ env.PROGRAM_NAME_WITH_PATH }}-*
81+ - name : Test App SSL connection
82+ run : open "${{ env.PROGRAM_NAME_WITH_PATH }}" --args -TEST_SSL
7883 shell : bash
7984
80- - name : Extract latest program version from metainfo and update the Info.plist with it
85+ - name : Set correct version number in macOS .app bundle Info.plist from metainfo xml file
8186 env :
8287 METAINFO_FILE : metainfo/io.github.gerryferdinandus.bittorrent-tracker-editor.metainfo.xml
8388 run : |
@@ -86,17 +91,10 @@ jobs:
8691 plutil -replace CFBundleShortVersionString -string $TRACKER_EDITOR_VERSION ${{ env.MACOS_APP }}/Contents/Info.plist
8792 shell : bash
8893
89- - name : Move program and icon into macOS .app
94+ - name : Create and set app icon in macOS .app bundle
9095 env :
9196 ICON_FILE : ' metainfo/io.github.gerryferdinandus.bittorrent-tracker-editor.png'
9297 run : |
93- PROGRAM_NAME_ONLY=$(basename -- "${{ env.PROGRAM_NAME_WITH_PATH }}")
94-
95- # ------ Move program to app
96- # remove the previeus app version
97- rm -f "${{ env.MACOS_APP }}/Contents/MacOS/${PROGRAM_NAME_ONLY}"
98- # copy the program to the app version.
99- mv -f "${{ env.PROGRAM_NAME_WITH_PATH }}" "${{ env.MACOS_APP }}/Contents/MacOS"
10098
10199 # ------ Create icon set and move it into the app
102100 iconset_folder="temp_folder.iconset"
@@ -120,7 +118,139 @@ jobs:
120118 plutil -insert CFBundleIconFile -string "iconfile" "${{ env.MACOS_APP }}/Contents/Info.plist"
121119 shell : bash
122120
123- - name : Check CPU type generated by Lazbuild
121+ - name : Zip the macOS .app bundle for artifact upload
122+ run : ditto -c -k enduser/trackereditor.app enduser/trackereditor_app.zip
123+ shell : bash
124+
125+ - name : Rename built -aarch64 binary for artifact upload
126+ run : |
127+ mv ${{ env.PROGRAM_NAME_WITH_PATH }} ${{ env.PROGRAM_NAME_WITH_PATH }}-aarch64
128+ ditto -c -k ${{ env.PROGRAM_NAME_WITH_PATH }}-aarch64 ${{ env.PROGRAM_NAME_WITH_PATH }}-aarch64.zip
129+ shell : bash
130+
131+ - name : Upload Artifact.
132+ uses : actions/upload-artifact@v4
133+ with :
134+ name : artifact-aarch64
135+ # Include both the zipped universal app bundle and the aarch64 binary zip
136+ path : enduser/*.zip
137+ if-no-files-found : error
138+
139+ build_x86_64 : # Build for Intel Mac architecture
140+ runs-on : macos-15-intel
141+ timeout-minutes : 60
142+ steps :
143+ - uses : actions/checkout@v5
144+ with :
145+ submodules : true
146+
147+ - name : Install Free Pascal Compiler (FPC) multi arch version for macOS x86_64 and aarch64
148+ run : brew install fpc
149+ shell : bash
150+
151+ - name : Download Lazarus source code into temp folder
152+ run : |
153+ #Download lazarus source code. Directory 'lazarus' will be created in the temp folder.
154+ cd ${RUNNER_TEMP}
155+ curl -L -O ${{ env.LAZARUS_URL_TAR_GZ }}
156+ tar -xzf *.tar.gz
157+ shell : bash
158+
159+ - name : Build lazbuild from Lazarus source code
160+ run : |
161+ # make lazbuild and put the link with extra parameter in the temp folder.
162+ LAZARUS_DIR=${RUNNER_TEMP}/lazarus
163+ cd "$LAZARUS_DIR"
164+ make lazbuild
165+ echo "$LAZARUS_DIR/lazbuild --primary-config-path=$LAZARUS_DIR --lazarusdir=$LAZARUS_DIR \$*" > ${RUNNER_TEMP}/lazbuild
166+ chmod +x ${RUNNER_TEMP}/lazbuild
167+ # Add lazbuild to the PATH variable. So it can be used in the next steps.
168+ echo ${RUNNER_TEMP} >> $GITHUB_PATH
169+ shell : bash
170+
171+ - name : Build trackereditor app for Intel Mac version (x86_64)
172+ run : |
173+ lazbuild --build-all --build-mode=Release --widgetset=cocoa --cpu=x86_64 ${{ env.PROJECT_LPI }}
174+ shell : bash
175+
176+ - name : Test App SSL connection
177+ run : open "${{ env.PROGRAM_NAME_WITH_PATH }}" --args -TEST_SSL
178+ shell : bash
179+
180+ - name : Rename built -x86_64 binary for artifact upload
181+ run : |
182+ mv ${{ env.PROGRAM_NAME_WITH_PATH }} ${{ env.PROGRAM_NAME_WITH_PATH }}-x86_64
183+ ditto -c -k ${{ env.PROGRAM_NAME_WITH_PATH }}-x86_64 ${{ env.PROGRAM_NAME_WITH_PATH }}-x86_64.zip
184+ shell : bash
185+
186+ - name : Upload Artifact.
187+ uses : actions/upload-artifact@v4
188+ with :
189+ name : artifact-x86_64
190+ path : enduser/*.zip
191+ if-no-files-found : error
192+
193+
194+ create_universal_macOS_binary : # Create Universal binary from aarch64 and x86_64 builds
195+ runs-on : macos-latest
196+ timeout-minutes : 60
197+
198+ needs :
199+ - build_aarch64
200+ - build_x86_64
201+
202+ steps :
203+ - name : Install create-dmg tool
204+ run : brew install create-dmg
205+ shell : bash
206+
207+ - name : Download build artifacts from previous jobs
208+ uses : actions/download-artifact@v5
209+ with :
210+ path : enduser/
211+ merge-multiple : true
212+
213+ - name : Display the downloaded artifact files
214+ run : ls -R enduser/
215+ shell : bash
216+
217+ - name : Unzip all the artifact files
218+ run : |
219+ ditto -xk enduser/trackereditor_app.zip enduser/trackereditor.app
220+ ditto -xk ${{ env.PROGRAM_NAME_WITH_PATH }}-x86_64.zip enduser/
221+ ditto -xk ${{ env.PROGRAM_NAME_WITH_PATH }}-aarch64.zip enduser/
222+ # Remove the zip files after extraction
223+ rm -f enduser/*.zip
224+ shell : bash
225+
226+ - name : Display the downloaded artifact files after unzip
227+ run : ls -R enduser/
228+ shell : bash
229+
230+ - name : Create a Universal macOS binary from aarch64 and x86_64
231+ run : |
232+ # Create Universal binary using lipo tool
233+ lipo -create -output ${{ env.PROGRAM_NAME_WITH_PATH }} ${{ env.PROGRAM_NAME_WITH_PATH }}-aarch64 ${{ env.PROGRAM_NAME_WITH_PATH }}-x86_64
234+
235+ # Remove the previous architecture specific binaries
236+ rm -f ${{ env.PROGRAM_NAME_WITH_PATH }}-*
237+ shell : bash
238+
239+ - name : Replace the macOS .app bundle binary with the Universal binary
240+ run : |
241+ PROGRAM_NAME_ONLY=$(basename -- "${{ env.PROGRAM_NAME_WITH_PATH }}")
242+ # remove the previous app (symbolic link)
243+ rm -f "${{ env.MACOS_APP }}/Contents/MacOS/${PROGRAM_NAME_ONLY}"
244+ # copy the program to the app version.
245+ mv -f "${{ env.PROGRAM_NAME_WITH_PATH }}" "${{ env.MACOS_APP }}/Contents/MacOS"
246+ ls -l "${{ env.MACOS_APP }}/Contents/MacOS/"
247+ shell : bash
248+
249+ - name : Display the enduser/ folder contents
250+ run : ls -R enduser/
251+ shell : bash
252+
253+ - name : Verify the Universal binary architectures
124254 run : |
125255 lipo -archs "${{ env.MACOS_APP }}"/Contents/MacOS/trackereditor
126256 lipo -archs "${{ env.MACOS_APP }}"/Contents/MacOS/trackereditor | grep -Fq x86_64
@@ -160,11 +290,12 @@ jobs:
160290 /usr/bin/codesign --timestamp --force --options runtime --sign "$MACOS_CERTIFICATE_NAME" "${{ env.MACOS_APP }}"
161291 shell : bash
162292
293+ - name : Display the enduser/ folder contents
294+ run : ls -R enduser/
295+ shell : bash
296+
163297 - name : Create dmg file from the enduser/ folder
164298 run : |
165- # Remove all txt file. There are not needed.
166- rm -f enduser/*.txt
167-
168299 # Build dmg image. https://github.com/create-dmg/create-dmg
169300 create-dmg \
170301 --volname "bittorrent-tracker-editor" \
0 commit comments