-
Notifications
You must be signed in to change notification settings - Fork 0
214 lines (176 loc) · 8.12 KB
/
build-macos.yml
File metadata and controls
214 lines (176 loc) · 8.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
name: Build macOS
on:
workflow_dispatch:
inputs:
version:
description: 'Version number (e.g., 0.2.0)'
required: true
type: string
deps_tag:
description: 'Deps release tag (e.g., deps-v1.0.0)'
required: true
type: string
arch:
description: 'Architecture'
required: false
type: choice
options:
- arm64
default: arm64
jobs:
build:
runs-on: macos-15 # M1 runner for arm64 support, Xcode 16+
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
channel: 'stable'
cache: true
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: aarch64-apple-darwin,x86_64-apple-darwin
- name: Cache Rust dependencies
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
worker/target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-
- name: Download macOS dependencies
run: |
DEPS_VERSION="${{ inputs.deps_tag }}"
DEPS_VERSION="${DEPS_VERSION#deps-v}"
mkdir -p deps/macos-arm64 deps/macos-x64
# Download arm64 deps (zip contains flat structure, no wrapper folder)
if [[ "${{ inputs.arch }}" == "arm64" || "${{ inputs.arch }}" == "both" ]]; then
DEPS_URL="https://github.com/${{ github.repository }}/releases/download/${{ inputs.deps_tag }}/VapourBox-deps-${DEPS_VERSION}-macos-arm64.zip"
echo "Downloading arm64 deps from: $DEPS_URL"
curl -L -o deps-arm64.zip "$DEPS_URL"
unzip -o deps-arm64.zip -d deps/macos-arm64
rm -f deps-arm64.zip
fi
# Download x64 deps (zip contains flat structure, no wrapper folder)
if [[ "${{ inputs.arch }}" == "x64" || "${{ inputs.arch }}" == "both" ]]; then
DEPS_URL="https://github.com/${{ github.repository }}/releases/download/${{ inputs.deps_tag }}/VapourBox-deps-${DEPS_VERSION}-macos-x64.zip"
echo "Downloading x64 deps from: $DEPS_URL"
curl -L -o deps-x64.zip "$DEPS_URL"
unzip -o deps-x64.zip -d deps/macos-x64
rm -f deps-x64.zip
fi
echo "Dependencies extracted:"
ls -la deps/
- name: Setup CocoaPods
run: |
gem install cocoapods
- name: Update version numbers
run: |
VERSION="${{ inputs.version }}"
DEPS_TAG="${{ inputs.deps_tag }}"
DEPS_VERSION="${DEPS_TAG#deps-v}"
# Update pubspec.yaml
sed -i '' "s/^version: .*/version: ${VERSION}+1/" app/pubspec.yaml
# Update deps-version.json
sed -i '' "s/\"version\": \"[^\"]*\"/\"version\": \"${DEPS_VERSION}\"/" app/assets/deps-version.json
sed -i '' "s/\"releaseTag\": \"[^\"]*\"/\"releaseTag\": \"${DEPS_TAG}\"/" app/assets/deps-version.json
# Update macOS Info.plist
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $VERSION" app/macos/Runner/Info.plist
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $VERSION" app/macos/Runner/Info.plist
# Update Cargo.toml
sed -i '' "s/^version = \".*\"/version = \"${VERSION}\"/" worker/Cargo.toml
- name: Build Rust worker (arm64)
if: ${{ inputs.arch == 'arm64' || inputs.arch == 'both' }}
run: |
cd worker
cargo build --release --target aarch64-apple-darwin
- name: Build Rust worker (x64)
if: ${{ inputs.arch == 'x64' || inputs.arch == 'both' }}
run: |
cd worker
cargo build --release --target x86_64-apple-darwin
- name: Build Flutter app
run: |
cd app
flutter pub get
dart run build_runner build --delete-conflicting-outputs
# Try flutter build first — it generates ephemeral files needed by xcodebuild.
# It may fail with module dependency errors, which is OK.
flutter build macos --release || true
# Two-step xcodebuild — handles module dependency errors that flutter build can't
cd macos
rm -rf Pods Podfile.lock
pod install
# Build Pods-Runner scheme first (all CocoaPods dependencies)
xcodebuild -workspace Runner.xcworkspace -scheme Pods-Runner \
-configuration Release build ONLY_ACTIVE_ARCH=NO \
-quiet
# Build Runner for arm64 only (must match Podfile ARCHS setting)
xcodebuild -workspace Runner.xcworkspace -scheme Runner \
-configuration Release build ARCHS=arm64 ONLY_ACTIVE_ARCH=YES \
-quiet
# Copy to Flutter build location
DERIVED_APP=$(find ~/Library/Developer/Xcode/DerivedData/Runner-*/Build/Products/Release/vapourbox.app -maxdepth 0 2>/dev/null | head -1)
if [ -z "$DERIVED_APP" ]; then
echo "ERROR: Could not find built app in DerivedData"
exit 1
fi
mkdir -p ../build/macos/Build/Products/Release
cp -R "$DERIVED_APP" ../build/macos/Build/Products/Release/
- name: Import Developer ID certificate
env:
MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
MACOS_KEYCHAIN_PASSWORD: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}
run: |
KEYCHAIN_PATH="$RUNNER_TEMP/app-signing.keychain-db"
CERT_PATH="$RUNNER_TEMP/developer-id.p12"
echo "$MACOS_CERTIFICATE" | base64 --decode > "$CERT_PATH"
# Create a dedicated, unlocked keychain just for this build
security create-keychain -p "$MACOS_KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
security unlock-keychain -p "$MACOS_KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
# Import the Developer ID Application cert + private key
security import "$CERT_PATH" -P "$MACOS_CERTIFICATE_PASSWORD" \
-A -t cert -f pkcs12 -k "$KEYCHAIN_PATH"
# Allow codesign to use the key without an interactive prompt
security set-key-partition-list -S apple-tool:,apple:,codesign: \
-s -k "$MACOS_KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
# Make this keychain the default + only one in the search list so
# package-macos.sh's `security find-identity` resolves the identity
security list-keychains -d user -s "$KEYCHAIN_PATH"
security default-keychain -s "$KEYCHAIN_PATH"
rm -f "$CERT_PATH"
echo "Signing identities available:"
security find-identity -v -p codesigning "$KEYCHAIN_PATH"
- name: Package release (arm64)
if: ${{ inputs.arch == 'arm64' || inputs.arch == 'both' }}
env:
NOTARY_APPLE_ID: ${{ secrets.MACOS_NOTARY_APPLE_ID }}
NOTARY_PASSWORD: ${{ secrets.MACOS_NOTARY_PASSWORD }}
NOTARY_TEAM_ID: ${{ secrets.MACOS_NOTARY_TEAM_ID }}
run: |
./Scripts/package-macos.sh --version "${{ inputs.version }}" --arch arm64 --skip-build --notarize
- name: Package release (x64)
if: ${{ inputs.arch == 'x64' || inputs.arch == 'both' }}
env:
NOTARY_APPLE_ID: ${{ secrets.MACOS_NOTARY_APPLE_ID }}
NOTARY_PASSWORD: ${{ secrets.MACOS_NOTARY_PASSWORD }}
NOTARY_TEAM_ID: ${{ secrets.MACOS_NOTARY_TEAM_ID }}
run: |
./Scripts/package-macos.sh --version "${{ inputs.version }}" --arch x64 --skip-build --notarize
- name: Clean up signing keychain
if: always()
run: |
security delete-keychain "$RUNNER_TEMP/app-signing.keychain-db" 2>/dev/null || true
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: VapourBox-${{ inputs.version }}-macos
path: dist/VapourBox-${{ inputs.version }}-macos-*.dmg