1+ name : Build Appling
2+
3+ on :
4+ push :
5+ branches :
6+ - main
7+ - dev
8+ workflow_dispatch :
9+ inputs :
10+ tag :
11+ description : ' Version tag'
12+ required : true
13+ type : string
14+
15+ jobs :
16+ version :
17+ runs-on : ubuntu-22.04
18+ outputs :
19+ version : ${{ steps.meta.outputs.VERSION }}
20+ strategy :
21+ matrix :
22+ arch :
23+ - x64
24+ steps :
25+ - uses : actions/checkout@v4
26+
27+ - name : Read & validate version
28+ id : meta
29+ run : |
30+ set -euo pipefail
31+ VERSION=$(jq -r '.version' package.json)
32+ echo "VERSION=$VERSION"
33+ if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
34+ echo "❌ Error: package.json version ('$VERSION') is not semantic versioning (MAJOR.MINOR.PATCH)."
35+ exit 1
36+ fi
37+ TAG="v$VERSION"
38+ echo "TAG=$TAG"
39+ echo "VERSION=$VERSION" >> "$GITHUB_OUTPUT"
40+ echo "TAG=$TAG" >> "$GITHUB_OUTPUT"
41+
42+ linux :
43+ runs-on : ubuntu-22.04
44+ needs : [version]
45+ strategy :
46+ matrix :
47+ arch :
48+ - x64
49+ defaults :
50+ run :
51+ working-directory : ./appling
52+ env :
53+ SLACK_WEBHOOK_URL_PATH : ${{ secrets.SLACK_WEBHOOK_URL_PATH }}
54+ GOOGLE_FORM_KEY : ${{ secrets.GOOGLE_FORM_KEY }}
55+ GOOGLE_FORM_MAPPING_TIMESTAMP : ${{ secrets.GOOGLE_FORM_MAPPING_TIMESTAMP }}
56+ GOOGLE_FORM_MAPPING_TOPIC : ${{ secrets.GOOGLE_FORM_MAPPING_TOPIC }}
57+ GOOGLE_FORM_MAPPING_APP : ${{ secrets.GOOGLE_FORM_MAPPING_APP }}
58+ GOOGLE_FORM_MAPPING_OPERATING_SYSTEM : ${{ secrets.GOOGLE_FORM_MAPPING_OPERATING_SYSTEM }}
59+ GOOGLE_FORM_MAPPING_DEVICE_MODEL : ${{ secrets.GOOGLE_FORM_MAPPING_DEVICE_MODEL }}
60+ GOOGLE_FORM_MAPPING_MESSAGE : ${{ secrets.GOOGLE_FORM_MAPPING_MESSAGE }}
61+ GOOGLE_FORM_MAPPING_APP_VERSION : ${{ secrets.GOOGLE_FORM_MAPPING_APP_VERSION }}
62+ TEST_SLACK_WEBHOOK_URL_PATH : ${{ secrets.TEST_SLACK_WEBHOOK_URL_PATH }}
63+ TEST_GOOGLE_FORM_KEY : ${{ secrets.TEST_GOOGLE_FORM_KEY }}
64+ TEST_GOOGLE_FORM_MAPPING_TIMESTAMP : ${{ secrets.TEST_GOOGLE_FORM_MAPPING_TIMESTAMP }}
65+ TEST_GOOGLE_FORM_MAPPING_TOPIC : ${{ secrets.TEST_GOOGLE_FORM_MAPPING_TOPIC }}
66+ TEST_GOOGLE_FORM_MAPPING_APP : ${{ secrets.TEST_GOOGLE_FORM_MAPPING_APP }}
67+ TEST_GOOGLE_FORM_MAPPING_OPERATING_SYSTEM : ${{ secrets.TEST_GOOGLE_FORM_MAPPING_OPERATING_SYSTEM }}
68+ TEST_GOOGLE_FORM_MAPPING_DEVICE_MODEL : ${{ secrets.TEST_GOOGLE_FORM_MAPPING_DEVICE_MODEL }}
69+ TEST_GOOGLE_FORM_MAPPING_MESSAGE : ${{ secrets.TEST_GOOGLE_FORM_MAPPING_MESSAGE }}
70+ TEST_GOOGLE_FORM_MAPPING_APP_VERSION : ${{ secrets.TEST_GOOGLE_FORM_MAPPING_APP_VERSION }}
71+ steps :
72+ - uses : actions/checkout@v4
73+
74+ - uses : actions/setup-node@v4
75+ with :
76+ node-version : 20
77+ registry-url : ' https://npm.pkg.github.com'
78+ scope : ' @tetherto'
79+
80+ - name : Install dependencies
81+ run : |
82+ sudo apt-get update
83+ sudo apt-get install -y curl ca-certificates build-essential git libgtk-4-dev pkg-config fuse file
84+ # sudo apt-get install -y clang pkg-config libgtk-4-dev clang-tools fuse file
85+ wget https://apt.llvm.org/llvm.sh
86+ chmod +x llvm.sh
87+ sudo ./llvm.sh 20
88+ npm install --global bare-make
89+ npm install --install-links --legacy-peer-deps
90+ env :
91+ NODE_AUTH_TOKEN : ${{ secrets.PAT_TOKEN }}
92+
93+ - name : Build Linux AppImage
94+ run : |
95+ bare-make generate --platform linux --arch ${{ matrix.arch }}
96+ bare-make build
97+
98+ - name : Find AppImage file
99+ id : find_file
100+ run : |
101+ APPIMAGE_PATH=$(find $GITHUB_WORKSPACE -name "*.AppImage" -type f | head -n 1)
102+ echo "APPIMAGE_PATH=$APPIMAGE_PATH" >> $GITHUB_OUTPUT
103+ echo "Found AppImage at: $APPIMAGE_PATH"
104+
105+ TIMESTAMP=$(date +%Y%m%d-%H%M%S)
106+ echo "TIMESTAMP=$TIMESTAMP" >> $GITHUB_OUTPUT
107+
108+ - uses : actions/upload-artifact@v4
109+ if : ${{ steps.find_file.outputs.APPIMAGE_PATH != '' }}
110+ with :
111+ name : PearPass-Desktop-Linux-${{ matrix.arch }}-v${{ needs.version.outputs.version }}.AppImage
112+ path : " ${{ steps.find_file.outputs.APPIMAGE_PATH }}"
113+
114+ macos :
115+ runs-on : macos-14
116+ needs : [version]
117+ strategy :
118+ matrix :
119+ arch :
120+ - x64
121+ - arm64
122+ defaults :
123+ run :
124+ working-directory : ./appling
125+ env :
126+ SLACK_WEBHOOK_URL_PATH : ${{ secrets.SLACK_WEBHOOK_URL_PATH }}
127+ GOOGLE_FORM_KEY : ${{ secrets.GOOGLE_FORM_KEY }}
128+ GOOGLE_FORM_MAPPING_TIMESTAMP : ${{ secrets.GOOGLE_FORM_MAPPING_TIMESTAMP }}
129+ GOOGLE_FORM_MAPPING_TOPIC : ${{ secrets.GOOGLE_FORM_MAPPING_TOPIC }}
130+ GOOGLE_FORM_MAPPING_APP : ${{ secrets.GOOGLE_FORM_MAPPING_APP }}
131+ GOOGLE_FORM_MAPPING_OPERATING_SYSTEM : ${{ secrets.GOOGLE_FORM_MAPPING_OPERATING_SYSTEM }}
132+ GOOGLE_FORM_MAPPING_DEVICE_MODEL : ${{ secrets.GOOGLE_FORM_MAPPING_DEVICE_MODEL }}
133+ GOOGLE_FORM_MAPPING_MESSAGE : ${{ secrets.GOOGLE_FORM_MAPPING_MESSAGE }}
134+ GOOGLE_FORM_MAPPING_APP_VERSION : ${{ secrets.GOOGLE_FORM_MAPPING_APP_VERSION }}
135+ TEST_SLACK_WEBHOOK_URL_PATH : ${{ secrets.TEST_SLACK_WEBHOOK_URL_PATH }}
136+ TEST_GOOGLE_FORM_KEY : ${{ secrets.TEST_GOOGLE_FORM_KEY }}
137+ TEST_GOOGLE_FORM_MAPPING_TIMESTAMP : ${{ secrets.TEST_GOOGLE_FORM_MAPPING_TIMESTAMP }}
138+ TEST_GOOGLE_FORM_MAPPING_TOPIC : ${{ secrets.TEST_GOOGLE_FORM_MAPPING_TOPIC }}
139+ TEST_GOOGLE_FORM_MAPPING_APP : ${{ secrets.TEST_GOOGLE_FORM_MAPPING_APP }}
140+ TEST_GOOGLE_FORM_MAPPING_OPERATING_SYSTEM : ${{ secrets.TEST_GOOGLE_FORM_MAPPING_OPERATING_SYSTEM }}
141+ TEST_GOOGLE_FORM_MAPPING_DEVICE_MODEL : ${{ secrets.TEST_GOOGLE_FORM_MAPPING_DEVICE_MODEL }}
142+ TEST_GOOGLE_FORM_MAPPING_MESSAGE : ${{ secrets.TEST_GOOGLE_FORM_MAPPING_MESSAGE }}
143+ TEST_GOOGLE_FORM_MAPPING_APP_VERSION : ${{ secrets.TEST_GOOGLE_FORM_MAPPING_APP_VERSION }}
144+ steps :
145+ - uses : actions/checkout@v4
146+
147+ - uses : actions/setup-node@v4
148+ with :
149+ node-version : 20
150+ registry-url : ' https://npm.pkg.github.com'
151+ scope : ' @tetherto'
152+
153+ - name : Install dependencies
154+ run : |
155+ npm install --global bare-make
156+ npm install --install-links --legacy-peer-deps
157+ env :
158+ NODE_AUTH_TOKEN : ${{ secrets.PAT_TOKEN }}
159+
160+ - name : Install the Apple certificate and provisioning profile
161+ env :
162+ BUILD_CERTIFICATE_BASE64 : ${{ secrets.APPLE_DISTRIBUTION_CERTIFICATE }}
163+ P12_PASSWORD : ${{ secrets.APPLE_P12_PASSWORD }}
164+ BUILD_PROVISION_PROFILE_BASE64 : ${{ secrets.APPLE_PROVISIONING_PROFILE }}
165+ KEYCHAIN_PASSWORD : ${{ secrets.APPLE_KEYCHAIN_PASSWORD }}
166+ APIKEY_BASE64 : ${{ secrets.APPLE_APIKEY }}
167+ run : |
168+ # create variables
169+ CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
170+ PP_PATH=$RUNNER_TEMP/build_pp.provisionprofile
171+ KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
172+ APIKEY_PATH=$RUNNER_TEMP/AuthKey.p8
173+
174+ # import certificate and provisioning profile from secrets
175+ echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
176+ echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_PATH
177+ echo -n "$APIKEY_BASE64" | base64 --decode -o $APIKEY_PATH
178+
179+ # create temporary keychain
180+ security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
181+ security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
182+ security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
183+
184+ # import certificate to keychain
185+ security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
186+ security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
187+ security list-keychain -d user -s $KEYCHAIN_PATH
188+
189+ # add notarytool credentials
190+ xcrun notarytool store-credentials "pearpass" --key "$APIKEY_PATH" --key-id S3AG2UXSC5 --issuer 2067dae8-140d-4016-9a2b-d6ea80a20708
191+
192+ # apply provisioning profile
193+ mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
194+ cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles
195+
196+ - name : Build macOS app
197+ run : |
198+ bare-make generate --platform darwin --arch ${{ matrix.arch }}
199+ bare-make build
200+
201+ - name : Find App file
202+ id : find_file
203+ run : |
204+ # find the .app bundle (it's a directory)
205+ APPIMAGE_PATH=$(find "$GITHUB_WORKSPACE" -name "*.app" -type d | head -n 1)
206+ echo "APPIMAGE_PATH=$APPIMAGE_PATH" >> $GITHUB_OUTPUT
207+ echo "Found app at: $APPIMAGE_PATH"
208+
209+ TIMESTAMP=$(date +%Y%m%d-%H%M%S)
210+ echo "TIMESTAMP=$TIMESTAMP" >> $GITHUB_OUTPUT
211+
212+ - name : Create DMG and notarize
213+ id : create_dmg
214+ if : ${{ steps.find_file.outputs.APPIMAGE_PATH != '' }}
215+ run : |
216+ npm install --global create-dmg
217+ create-dmg "${{ steps.find_file.outputs.APPIMAGE_PATH }}" --identity=959D2C8BB8323AEF9C2367ACA2F854AE4D7DE458 --no-version-in-filename
218+ DMG=$(find "$GITHUB_WORKSPACE" -name "*.dmg" -type d | head -n 1)
219+ echo "DMG=$DMG" >> $GITHUB_OUTPUT
220+ echo "Found dmg at: $DMG"
221+
222+ - name : Notarize DMG
223+ run : |
224+ xcrun notarytool submit "Pearpass.dmg" --keychain-profile "pearpass" --wait
225+
226+ - name : Staple DMG
227+ run : |
228+ xcrun stapler staple "Pearpass.dmg"
229+ xcrun stapler validate "Pearpass.dmg"
230+
231+ - uses : actions/upload-artifact@v4
232+ if : ${{ steps.find_file.outputs.APPIMAGE_PATH != '' }}
233+ with :
234+ name : PearPass-Desktop-MacOS-${{ matrix.arch }}-v${{ needs.version.outputs.version }}.dmg
235+ path : " ${{ github.workspace }}/appling/Pearpass.dmg"
236+
237+ - name : Clean up keychain and provisioning profile
238+ if : ${{ always() }}
239+ run : |
240+ security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
241+ rm ~/Library/MobileDevice/Provisioning\ Profiles/build_pp.provisionprofile
242+
243+ release :
244+ runs-on : ubuntu-latest
245+ needs : [version, linux, macos]
246+ if : github.ref == 'refs/heads/main'
247+ steps :
248+ - name : Download artifacts
249+ uses : actions/download-artifact@v5
250+ with :
251+ path : artifacts/
252+ merge-multiple : true
253+
254+ - name : Create Release
255+ uses : softprops/action-gh-release@v2
256+ with :
257+ tag_name : v${{ needs.version.outputs.version }}
258+ name : PearPass-Desktop-v${{ needs.version.outputs.version }}
259+ files : artifacts/**
0 commit comments