Skip to content

Commit 00d535a

Browse files
committed
Add a self-hosted Azure pipeline that builds the internal repo for all OS, uploads debug symbols, updates LatestVersion.json, Telemetry.json, publishes GitHub releases, and notifies on Discord ("Release" posts to the release channel, "Beta" posts to the beta channel).
1 parent 6a25e7d commit 00d535a

10 files changed

Lines changed: 2192 additions & 0 deletions

.azure-pipelines/azure-pipelines.yml

Lines changed: 509 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# templates/checkout.yml
2+
# Template for checking out the Arduino-Source repositories
3+
4+
steps:
5+
- checkout: Arduino-Source-Internal
6+
path: Arduino-Source-Internal
7+
fetchDepth: 1
8+
persistCredentials: true
9+
sparseCheckoutPatterns: |
10+
/*
11+
!Repository/Public/*
12+
!Repository/Deployment-SerialPrograms-Qt6.10.0-MSVC2022/
13+
!Repository/Deployment-SerialPrograms-Qt6.8.3-MSVC2022/
14+
workspaceRepo: true
15+
16+
- checkout: Arduino-Source
17+
path: Arduino-Source-Internal/Repository/Public
18+
persistCredentials: true

.azure-pipelines/templates/github-release.yml

Lines changed: 387 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
# templates/macos-build.yml
2+
# Template for building SerialPrograms on MacOS
3+
4+
parameters:
5+
stageName: ''
6+
displayName: ''
7+
targetOS: ''
8+
poolName: ''
9+
imageName: ''
10+
architecture: ''
11+
compiler: ''
12+
qt_version: ''
13+
qt_version_major: ''
14+
qt_modules: ''
15+
cmake_preset: ''
16+
macos_path: ''
17+
cmake_version_params: ''
18+
cmake_additional_param: ''
19+
condition: ''
20+
21+
stages:
22+
- stage: ${{ parameters.stageName }}
23+
displayName: ${{ parameters.displayName }}
24+
dependsOn: []
25+
condition: ${{ parameters.condition }}
26+
27+
jobs:
28+
- job: MacOS
29+
timeoutInMinutes: 60
30+
cancelTimeoutInMinutes: 1
31+
displayName: MacOS ${{ parameters.architecture }}
32+
33+
pool:
34+
name: ${{ parameters.poolName }}
35+
demands:
36+
- Agent.OSArchitecture -equals ${{ lower(parameters.architecture) }}
37+
38+
variables:
39+
architecture: ${{ parameters.architecture }}
40+
compiler: ${{ parameters.compiler }}
41+
qt_version: ${{ parameters.qt_version }}
42+
cmake_preset: ${{ parameters.cmake_preset }}
43+
macos_path: ${{ parameters.macos_path }}
44+
cmake_version_params: ${{ parameters.cmake_version_params }}
45+
cmake_additional_param: ${{ parameters.cmake_additional_param }}
46+
47+
steps:
48+
- template: checkout.yml
49+
50+
#- script: |
51+
# set -e
52+
# PERSISTENT_ONNX="/Users/Shared/onnxruntime"
53+
# WORK_ONNX="$(Pipeline.Workspace)/onnxruntime"
54+
#
55+
# if [ -d "$PERSISTENT_ONNX" ]; then
56+
# echo "=== Found ONNX Runtime at $PERSISTENT_ONNX ==="
57+
# if [ ! -L "$WORK_ONNX" ]; then
58+
# ln -sf "$PERSISTENT_ONNX" "$WORK_ONNX"
59+
# echo "=== Created symlink to ONNX Runtime ==="
60+
# fi
61+
# else
62+
# echo "=== ERROR: ONNX Runtime not found at $PERSISTENT_ONNX ==="
63+
# exit 1
64+
# fi
65+
# displayName: 'Link ONNX Runtime'
66+
# condition: succeeded()
67+
68+
- script: |
69+
export PATH=$(macos_path)
70+
cd "$(Pipeline.Workspace)/Arduino-Source-Internal/Repository/Public/SerialPrograms"
71+
cmake $(cmake_additional_param) $(cmake_version_params) --preset=$(cmake_preset) --fresh
72+
displayName: 'Configure CMake'
73+
condition: succeeded()
74+
75+
- script: |
76+
export PATH=$(macos_path)
77+
cd "$(Pipeline.Workspace)/Arduino-Source-Internal/Repository/Public/SerialPrograms"
78+
cmake --build --preset=$(cmake_preset)
79+
displayName: 'Build'
80+
condition: succeeded()
81+
82+
- script: |
83+
set -e
84+
export PATH=$(macos_path)
85+
BUILD_DIR="$(Pipeline.Workspace)/Arduino-Source-Internal/Repository/Public/build/$(cmake_preset)"
86+
87+
echo "=== Generating dSYM bundle ==="
88+
mkdir -p "$(Pipeline.Workspace)/Arduino-Source-Internal/Repository/Public/build/$(cmake_preset)/cache-symbols"
89+
cd "$BUILD_DIR"
90+
dsymutil SerialPrograms.app/Contents/MacOS/SerialPrograms -o cache-symbols/SerialPrograms.dSYM
91+
92+
echo "=== dSYM bundle created ==="
93+
displayName: 'Generate Debug Symbols'
94+
condition: succeeded()
95+
96+
- script: |
97+
set -e
98+
export PATH=$(macos_path)
99+
APP_DIR="$(Pipeline.Workspace)/Arduino-Source-Internal/Repository/Public/build/$(cmake_preset)/SerialPrograms.app"
100+
MACOS_DIR="$APP_DIR/Contents/MacOS"
101+
FW_DIR="$APP_DIR/Contents/Frameworks"
102+
BREW_PREFIX=$(brew --prefix)
103+
104+
mkdir -p "$FW_DIR"
105+
if [ "$(architecture)" = "x64" ]; then
106+
QT_BIN="/usr/local/Qt/$(qt_version)/macos/bin"
107+
else
108+
QT_BIN="/opt/Qt/$(qt_version)/macos/bin"
109+
fi
110+
111+
echo "=== Copying additional deps ==="
112+
cp $BREW_PREFIX/opt/gcc/lib/gcc/current/libgcc_s.1.1.dylib $APP_DIR/Contents/Frameworks
113+
cp $BREW_PREFIX/opt/protobuf/lib/libutf8_validity.dylib $APP_DIR/Contents/Frameworks
114+
cp $BREW_PREFIX/opt/little-cms2/lib/liblcms2.2.dylib $APP_DIR/Contents/Frameworks
115+
cp $BREW_PREFIX/opt/webp/lib/libsharpyuv.0.dylib $APP_DIR/Contents/Frameworks
116+
cp $BREW_PREFIX/opt/jpeg-xl/lib/libjxl_cms.0.11.dylib $APP_DIR/Contents/Frameworks
117+
cp $BREW_PREFIX/opt/vtk/lib/libvtkCommonComputationalGeometry-*.dylib $APP_DIR/Contents/Frameworks
118+
cp $BREW_PREFIX/opt/vtk/lib/libvtkFiltersVerdict-*.dylib $APP_DIR/Contents/Frameworks
119+
cp $BREW_PREFIX/opt/vtk/lib/libvtkfmt-*.dylib $APP_DIR/Contents/Frameworks
120+
cp $BREW_PREFIX/opt/vtk/lib/libvtkFiltersGeometry-*.dylib $APP_DIR/Contents/Frameworks
121+
cp $BREW_PREFIX/opt/vtk/lib/libvtkFiltersCore-*.dylib $APP_DIR/Contents/Frameworks
122+
cp $BREW_PREFIX/opt/vtk/lib/libvtkCommonCore-*.dylib $APP_DIR/Contents/Frameworks
123+
cp $BREW_PREFIX/opt/vtk/lib/libvtkCommonSystem-*.dylib $APP_DIR/Contents/Frameworks
124+
125+
echo "=== Running macdeployqt6 ==="
126+
install_name_tool -add_rpath $BREW_PREFIX/lib $MACOS_DIR/SerialPrograms
127+
otool -l $MACOS_DIR/SerialPrograms | grep -A2 LC_RPATH
128+
"$QT_BIN/macdeployqt6" $APP_DIR -no-strip -verbose=3
129+
130+
echo "=== Fixing install IDs in copied libs ==="
131+
for dylib in "$FW_DIR"/*.dylib; do
132+
[ -f "$dylib" ] || continue
133+
base=$(basename "$dylib")
134+
install_name_tool -id "@executable_path/../Frameworks/$base" "$dylib"
135+
done
136+
137+
echo "=== Rewriting internal dylib references ==="
138+
for dylib in "$FW_DIR"/*.dylib; do
139+
[ -f "$dylib" ] || continue
140+
for linked in $(otool -L "$dylib" | awk 'NR>1 {print $1}' | grep "$BREW_PREFIX" || true); do
141+
base=$(basename "$linked")
142+
if [ -f "$FW_DIR/$base" ]; then
143+
install_name_tool -change "$linked" "@executable_path/../Frameworks/$base" "$dylib"
144+
fi
145+
done
146+
done
147+
148+
echo "=== Rewriting main executable references ==="
149+
for linked in $(otool -L "$MACOS_DIR/SerialPrograms" | awk 'NR>1 {print $1}' | grep "$BREW_PREFIX" || true); do
150+
base=$(basename "$linked")
151+
if [ -f "$FW_DIR/$base" ]; then
152+
install_name_tool -change "$linked" "@executable_path/../Frameworks/$base" "$MACOS_DIR/SerialPrograms"
153+
fi
154+
done
155+
156+
echo "=== Creating tarballs for build and symbols ==="
157+
mkdir -p "$(Pipeline.Workspace)/Arduino-Source-Internal/Repository/Public/build/$(cmake_preset)/cache-build"
158+
cd "$(Pipeline.Workspace)/Arduino-Source-Internal/Repository/Public/build/$(cmake_preset)"
159+
tar -czf "cache-build/macos-build-${{ parameters.architecture }}.tar.gz" SerialPrograms.app
160+
tar -czf "cache-symbols/macos-symbols-${{ parameters.architecture }}.tar.gz" cache-symbols/SerialPrograms.dSYM
161+
162+
echo "Deployment complete for $(architecture)"
163+
displayName: 'Deploy app'
164+
condition: succeeded()
165+
166+
- task: Cache@2
167+
displayName: 'Cache the build artifact'
168+
inputs:
169+
key: 'macos-build-${{ parameters.architecture }} | "$(Build.BuildId)"'
170+
path: '$(Pipeline.Workspace)/Arduino-Source-Internal/Repository/Public/build/$(cmake_preset)/cache-build'
171+
condition: succeeded()
172+
173+
- task: Cache@2
174+
displayName: 'Cache debug symbols'
175+
inputs:
176+
key: 'macos-symbols-${{ parameters.architecture }} | "$(Build.BuildId)"'
177+
path: '$(Pipeline.Workspace)/Arduino-Source-Internal/Repository/Public/build/$(cmake_preset)/cache-symbols'
178+
condition: succeeded()
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
# templates/macos-notarize.yml
2+
# Template for codesigning and notarizing SerialPrograms on MacOS
3+
4+
parameters:
5+
stageName: ''
6+
displayName: ''
7+
dependsOnStage: ''
8+
buildType: ''
9+
poolName: ''
10+
imageName: ''
11+
architecture: ''
12+
compiler: ''
13+
cmake_preset: ''
14+
macos_path: ''
15+
openssl_pkcs_args: ''
16+
condition: ''
17+
18+
stages:
19+
- stage: ${{ parameters.stageName }}
20+
displayName: ${{ parameters.displayName }}
21+
dependsOn: ${{ parameters.dependsOnStage }}
22+
condition: ${{ parameters.condition }}
23+
24+
jobs:
25+
- job: Codesign
26+
displayName: Codesign ${{ parameters.architecture }}
27+
timeoutInMinutes: 120
28+
cancelTimeoutInMinutes: 1
29+
30+
pool:
31+
name: ${{ parameters.poolName }}
32+
demands:
33+
- Agent.OSArchitecture -equals ${{ lower(parameters.architecture) }}
34+
35+
variables:
36+
architecture: ${{ parameters.architecture }}
37+
compiler: ${{ parameters.compiler }}
38+
cmake_preset: ${{ parameters.cmake_preset }}
39+
40+
steps:
41+
- template: checkout.yml
42+
43+
- task: Cache@2
44+
displayName: 'Restore the cached build artifact'
45+
inputs:
46+
key: 'macos-build-${{ parameters.architecture }} | "$(Build.BuildId)"'
47+
path: $(Pipeline.Workspace)
48+
restoreKeys: |
49+
macos-build-${{ parameters.architecture }} | "$(Build.BuildId)"
50+
condition: succeeded()
51+
52+
- task: InstallAppleCertificate@2
53+
displayName: 'Install Apple certificate'
54+
inputs:
55+
certSecureFile: 'CodesignCertMac.p12'
56+
certPwd: $(CERT_PW)
57+
keychain: custom
58+
keychainPassword: $(KEYCHAIN_PW)
59+
customKeychainPath: '$(HOME)/Library/Keychains/azure-signing.keychain-db'
60+
deleteCert: true
61+
deleteCustomKeychain: true
62+
opensslPkcsArgs: ${{ parameters.openssl_pkcs_args }}
63+
condition: succeeded()
64+
65+
- script: |
66+
set -e
67+
KEYCHAIN="$HOME/Library/Keychains/azure-signing.keychain-db"
68+
69+
echo "=== Activating keychain ==="
70+
security list-keychains -d user -s "$KEYCHAIN" "$HOME/Library/Keychains/login.keychain-db"
71+
security unlock-keychain -p "$(KEYCHAIN_PW)" "$KEYCHAIN"
72+
73+
echo "=== Allowing codesign to access private key ==="
74+
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$(KEYCHAIN_PW)" "$KEYCHAIN"
75+
76+
echo "=== Verifying identities ==="
77+
security find-identity -p codesigning -v
78+
env:
79+
KEYCHAIN_PW: $(KEYCHAIN_PW)
80+
displayName: 'Authorize signing key'
81+
condition: succeeded()
82+
83+
- script: |
84+
set -euo pipefail
85+
export PATH=${{ parameters.macos_path }}
86+
APP_DIR="$(Pipeline.Workspace)/Arduino-Source-Internal/SerialPrograms.app"
87+
ZIP_PATH="$(Pipeline.Workspace)/SerialPrograms-MacOS-$(compiler)-$(architecture).zip"
88+
ENTITLEMENTS_DIR="$(Pipeline.Workspace)/Arduino-Source-Internal/Repository/Public/SerialPrograms/cmake/MacOSXEntitlements.plist"
89+
90+
echo "=== Extracting tarball ==="
91+
tar -xzf "$(Pipeline.Workspace)/macos-build-${{ parameters.architecture }}.tar.gz"
92+
93+
echo "=== Signing app ==="
94+
codesign --deep --force --options runtime --timestamp --entitlements "$ENTITLEMENTS_DIR" --sign "$SIGN_IDENTITY" "$APP_DIR"
95+
96+
echo "=== Verifying code signature ==="
97+
codesign --verify --deep --strict --verbose=2 "$APP_DIR"
98+
99+
echo "Creating ZIP for notarization..."
100+
ditto -c -k --keepParent "$APP_DIR" "$ZIP_PATH"
101+
env:
102+
SIGN_IDENTITY: $(SIGNING_IDENTITY)
103+
displayName: 'Codesign, verify, create ZIP'
104+
condition: succeeded()
105+
106+
- script: |
107+
set -euo pipefail
108+
ZIP_PATH="$(Pipeline.Workspace)/SerialPrograms-MacOS-$(compiler)-$(architecture).zip"
109+
110+
SUBMIT_JSON=$(xcrun notarytool submit "$ZIP_PATH" \
111+
--apple-id "$APPLE_ID" \
112+
--password "$APPLE_APP_PW" \
113+
--team-id "$APPLE_TEAM_ID" \
114+
--output-format json)
115+
116+
REQUEST_ID=$(echo "$SUBMIT_JSON" | jq -r '.id')
117+
[ -n "$REQUEST_ID" ] && [ "$REQUEST_ID" != "null" ]
118+
119+
echo "##vso[task.setvariable variable=NOTARY_REQUEST_ID]$REQUEST_ID"
120+
env:
121+
APPLE_ID: $(APPLE_ID)
122+
APPLE_APP_PW: $(APPLE_APP_PW)
123+
APPLE_TEAM_ID: $(APPLE_TEAM_ID)
124+
displayName: 'Submit for notarization'
125+
condition: succeeded()
126+
127+
- script: |
128+
set -euo pipefail
129+
MAX_WAIT=14400
130+
INTERVAL=30
131+
ELAPSED=0
132+
133+
while true; do
134+
STATUS=$(xcrun notarytool info "$(NOTARY_REQUEST_ID)" \
135+
--apple-id "$APPLE_ID" \
136+
--password "$APPLE_APP_PW" \
137+
--team-id "$APPLE_TEAM_ID" \
138+
--output-format json | jq -r '.status')
139+
140+
case "$STATUS" in
141+
Accepted) break ;;
142+
Invalid)
143+
xcrun notarytool log "$(NOTARY_REQUEST_ID)" \
144+
--apple-id "$APPLE_ID" \
145+
--password "$APPLE_APP_PW" \
146+
--team-id "$APPLE_TEAM_ID"
147+
exit 1 ;;
148+
esac
149+
150+
sleep "$INTERVAL"
151+
ELAPSED=$((ELAPSED + INTERVAL))
152+
[ "$ELAPSED" -lt "$MAX_WAIT" ]
153+
done
154+
env:
155+
APPLE_ID: $(APPLE_ID)
156+
APPLE_APP_PW: $(APPLE_APP_PW)
157+
APPLE_TEAM_ID: $(APPLE_TEAM_ID)
158+
displayName: 'Wait for notarization'
159+
condition: succeeded()
160+
161+
- script: |
162+
set -euo pipefail
163+
APP_DIR="$(Pipeline.Workspace)/Arduino-Source-Internal/SerialPrograms.app"
164+
xcrun stapler staple "$APP_DIR"
165+
spctl --assess --type execute --verbose=4 "$APP_DIR"
166+
displayName: 'Staple and verify'
167+
condition: succeeded()
168+
169+
- script: |
170+
echo "=== Creating a tarball ==="
171+
tar -czf "SerialPrograms-MacOS-$(compiler)-$(architecture).tar.gz" -C "$(Pipeline.Workspace)/Arduino-Source-Internal" "SerialPrograms.app"
172+
echo "=== Creating cache directory and moving tarball ==="
173+
CACHE_DIR="$(Pipeline.Workspace)/Arduino-Source-Internal/cache-notarized"
174+
mkdir -p "$CACHE_DIR"
175+
mv "$(Pipeline.Workspace)/Arduino-Source-Internal/SerialPrograms-MacOS-$(compiler)-$(architecture).tar.gz" "$CACHE_DIR/"
176+
displayName: 'Create a tarball'
177+
condition: succeeded()
178+
179+
- task: Cache@2
180+
displayName: 'Cache the notarized artifact'
181+
inputs:
182+
key: 'macos-notarized-${{ parameters.architecture }} | "$(Build.BuildId)"'
183+
path: '$(Pipeline.Workspace)/Arduino-Source-Internal/cache-notarized'
184+
condition: succeeded()
185+
186+
- task: PublishPipelineArtifact@1
187+
displayName: 'Publish notarized app'
188+
inputs:
189+
targetPath: '$(Pipeline.Workspace)/Arduino-Source-Internal/cache-notarized/SerialPrograms-MacOS-$(compiler)-$(architecture).tar.gz'
190+
artifact: 'SerialPrograms-MacOS-$(compiler)-$(architecture)'
191+
condition: succeeded()

0 commit comments

Comments
 (0)