@@ -2,175 +2,258 @@ name: CI
22
33on :
44 push :
5- branches : [ main, develop ]
5+ branches : [main, develop]
66 pull_request :
7- branches : [ main, develop ]
7+ branches : [main, develop]
88 workflow_dispatch :
99
10+ # Cancel in-flight runs for the same branch on new pushes
11+ concurrency :
12+ group : ci-${{ github.ref }}
13+ cancel-in-progress : true
14+
1015jobs :
16+ # ── Dart analysis + format ──────────────────────────────────────────────────
1117 analyze :
12- name : Dart Analyze
18+ name : Analyze & Format
1319 runs-on : ubuntu-latest
1420 timeout-minutes : 10
15-
1621 steps :
17- - name : Checkout code
18- uses : actions/checkout@v4
22+ - uses : actions/checkout@v4
1923
20- - name : Setup Flutter
21- uses : subosito/flutter-action@v2
24+ - uses : subosito/flutter-action@v2
2225 with :
23- flutter-version : ' 3.19.0 '
24- channel : ' stable'
26+ flutter-version-file : .flutter-version
27+ channel : stable
2528 cache : true
2629
27- - name : Get dependencies
30+ - name : Get dependencies (plugin)
2831 run : flutter pub get
2932
30- - name : Verify formatting
31- run : dart format --output=none --set-exit-if-changed .
33+ - name : Get dependencies (gen)
34+ working-directory : native_workmanager_gen
35+ run : dart pub get
36+
37+ - name : Verify formatting (plugin)
38+ run : dart format --output=none --set-exit-if-changed lib test
39+
40+ - name : Verify formatting (gen)
41+ working-directory : native_workmanager_gen
42+ run : dart format --output=none --set-exit-if-changed lib
43+
44+ - name : Analyze plugin
45+ run : flutter analyze --fatal-warnings
3246
33- - name : Analyze project
34- run : flutter analyze --no-fatal-infos
47+ - name : Analyze gen package
48+ working-directory : native_workmanager_gen
49+ run : dart analyze --fatal-warnings
3550
51+ - name : Pub publish dry-run (plugin)
52+ run : dart pub publish --dry-run
53+
54+ - name : Pub publish dry-run (gen)
55+ working-directory : native_workmanager_gen
56+ run : dart pub publish --dry-run
57+
58+ # ── Dart unit tests ─────────────────────────────────────────────────────────
3659 test :
3760 name : Unit Tests
3861 runs-on : ubuntu-latest
3962 timeout-minutes : 15
40-
4163 steps :
42- - name : Checkout code
43- uses : actions/checkout@v4
64+ - uses : actions/checkout@v4
4465
45- - name : Setup Flutter
46- uses : subosito/flutter-action@v2
66+ - uses : subosito/flutter-action@v2
4767 with :
48- flutter-version : ' 3.19.0 '
49- channel : ' stable'
68+ flutter-version-file : .flutter-version
69+ channel : stable
5070 cache : true
5171
5272 - name : Get dependencies
5373 run : flutter pub get
5474
55- - name : Run tests
75+ - name : Run plugin unit tests with coverage
5676 run : flutter test --coverage --reporter=expanded
5777
58- - name : Upload coverage to Codecov
78+ - name : Upload coverage
5979 uses : codecov/codecov-action@v4
6080 with :
6181 files : ./coverage/lcov.info
6282 token : ${{ secrets.CODECOV_TOKEN }}
6383 fail_ci_if_error : false
64- verbose : true
6584
85+ # ── gen package tests ───────────────────────────────────────────────────────
86+ test-gen :
87+ name : Gen Package Tests
88+ runs-on : ubuntu-latest
89+ timeout-minutes : 10
90+ steps :
91+ - uses : actions/checkout@v4
92+
93+ - uses : subosito/flutter-action@v2
94+ with :
95+ flutter-version-file : .flutter-version
96+ channel : stable
97+ cache : true
98+
99+ - name : Get dependencies (plugin — needed by gen)
100+ run : flutter pub get
101+
102+ - name : Get dependencies (gen)
103+ working-directory : native_workmanager_gen
104+ run : dart pub get
105+
106+ - name : Run gen tests
107+ working-directory : native_workmanager_gen
108+ run : dart test
109+
110+ # ── Android build + unit tests ──────────────────────────────────────────────
66111 build-android :
67112 name : Build Android
68113 runs-on : ubuntu-latest
69- timeout-minutes : 20
70-
114+ timeout-minutes : 25
71115 steps :
72- - name : Checkout code
73- uses : actions/checkout@v4
116+ - uses : actions/checkout@v4
74117
75- - name : Setup Flutter
76- uses : subosito/flutter-action@v2
118+ - uses : subosito/flutter-action@v2
77119 with :
78- flutter-version : ' 3.19.0 '
79- channel : ' stable'
120+ flutter-version-file : .flutter-version
121+ channel : stable
80122 cache : true
81123
82- - name : Setup Java 17
83- uses : actions/setup-java@v4
124+ - uses : actions/setup-java@v4
84125 with :
85- distribution : ' temurin'
126+ distribution : temurin
86127 java-version : ' 17'
87- cache : ' gradle'
128+ cache : gradle
88129
89130 - name : Get dependencies
90131 run : flutter pub get
91132
92- - name : Build Android plugin
93- run : |
94- cd example/android
95- ./gradlew build --stacktrace
133+ - name : Build Android (debug)
134+ working-directory : example
135+ run : flutter build apk --debug --no-shrink
96136
97137 - name : Run Android unit tests
98- run : |
99- cd example/android
100- ./gradlew test
138+ working-directory : example/android
139+ run : ./gradlew testDebugUnitTest --stacktrace
101140
141+ # ── iOS build ───────────────────────────────────────────────────────────────
102142 build-ios :
103- name : Build iOS
143+ name : Build iOS (Simulator)
104144 runs-on : macos-latest
105- timeout-minutes : 30
106-
145+ timeout-minutes : 40
107146 steps :
108- - name : Checkout code
109- uses : actions/checkout@v4
147+ - uses : actions/checkout@v4
110148
111- - name : Setup Flutter
112- uses : subosito/flutter-action@v2
149+ - uses : subosito/flutter-action@v2
113150 with :
114- flutter-version : ' 3.19.0 '
115- channel : ' stable'
151+ flutter-version-file : .flutter-version
152+ channel : stable
116153 cache : true
117154
118155 - name : Get dependencies
119156 run : flutter pub get
120157
158+ - name : Cache CocoaPods
159+ uses : actions/cache@v4
160+ with :
161+ path : example/ios/Pods
162+ key : pods-${{ hashFiles('example/ios/Podfile.lock') }}
163+ restore-keys : pods-
164+
121165 - name : Install CocoaPods
122- run : |
123- cd example/ios
124- pod install
166+ working-directory : example/ios
167+ run : pod install --repo-update
125168
126- - name : Build iOS plugin
169+ - name : Build iOS (simulator, no signing)
170+ working-directory : example/ios
127171 run : |
128- cd example/ios
129172 xcodebuild build \
130173 -workspace Runner.xcworkspace \
131174 -scheme Runner \
132175 -sdk iphonesimulator \
133- -destination 'platform=iOS Simulator,name=iPhone 15 ,OS=latest' \
176+ -destination 'platform=iOS Simulator,name=iPhone 16 ,OS=latest' \
134177 CODE_SIGNING_ALLOWED=NO \
135178 | xcpretty
136179
137- publish-dry-run :
138- name : Publish Dry Run
139- runs-on : ubuntu-latest
140- timeout-minutes : 10
141- if : github.event_name == 'pull_request'
142-
180+ # ── Integration smoke test (iOS Simulator) ──────────────────────────────────
181+ integration-ios-simulator :
182+ name : Integration (iOS Simulator)
183+ runs-on : macos-latest
184+ timeout-minutes : 40
185+ if : github.event_name != 'pull_request'
143186 steps :
144- - name : Checkout code
145- uses : actions/checkout@v4
187+ - uses : actions/checkout@v4
146188
147- - name : Setup Flutter
148- uses : subosito/flutter-action@v2
189+ - uses : subosito/flutter-action@v2
149190 with :
150- flutter-version : ' 3.19.0 '
151- channel : ' stable'
191+ flutter-version-file : .flutter-version
192+ channel : stable
152193 cache : true
153194
154195 - name : Get dependencies
155196 run : flutter pub get
156197
157- - name : Dry run publish
158- run : dart pub publish --dry-run
198+ - name : Cache CocoaPods
199+ uses : actions/cache@v4
200+ with :
201+ path : example/ios/Pods
202+ key : pods-${{ hashFiles('example/ios/Podfile.lock') }}
203+ restore-keys : pods-
204+
205+ - name : Install CocoaPods
206+ working-directory : example/ios
207+ run : pod install
208+
209+ # L-04 fix: robust simulator selection with fallback chain
210+ - name : Resolve simulator UDID
211+ id : sim
212+ run : |
213+ # Try iPhone 16 first, fall back to any available iPhone simulator
214+ UDID=$(xcrun simctl list devices available | grep 'iPhone 16 ' | head -1 | grep -Eo '\([A-F0-9-]+\)' | tr -d '()')
215+ if [ -z "$UDID" ]; then
216+ UDID=$(xcrun simctl list devices available | grep 'iPhone' | grep -v 'Plus\|Pro\|Max' | head -1 | grep -Eo '\([A-F0-9-]+\)' | tr -d '()')
217+ fi
218+ if [ -z "$UDID" ]; then
219+ echo "❌ No iPhone simulator found. Available devices:"
220+ xcrun simctl list devices available
221+ exit 1
222+ fi
223+ echo "Using simulator UDID: $UDID"
224+ echo "udid=$UDID" >> "$GITHUB_OUTPUT"
159225
160- status-check :
226+ - name : Boot simulator
227+ run : xcrun simctl boot "${{ steps.sim.outputs.udid }}" || true
228+
229+ - name : Run integration tests (simulator subset)
230+ working-directory : example
231+ run : |
232+ flutter test integration_test/device_integration_test.dart \
233+ -d "${{ steps.sim.outputs.udid }}" \
234+ --dart-define=SIMULATOR=true \
235+ --timeout=120s
236+
237+ # ── Gate ───────────────────────────────────────────────────────────────────
238+ all-checks :
161239 name : All Checks Passed
162240 runs-on : ubuntu-latest
163- needs : [analyze, test, build-android, build-ios]
241+ needs : [analyze, test, test-gen, build-android, build-ios]
164242 if : always()
165-
166243 steps :
167- - name : Check all jobs
244+ - name : Verify all required jobs succeeded
168245 run : |
169- if [[ "${{ needs.analyze.result }}" != "success" ]] || \
170- [[ "${{ needs.test.result }}" != "success" ]] || \
171- [[ "${{ needs.build-android.result }}" != "success" ]] || \
172- [[ "${{ needs.build-ios.result }}" != "success" ]]; then
173- echo "❌ One or more jobs failed"
174- exit 1
175- fi
176- echo "✅ All checks passed!"
246+ results=(
247+ "${{ needs.analyze.result }}"
248+ "${{ needs.test.result }}"
249+ "${{ needs.test-gen.result }}"
250+ "${{ needs.build-android.result }}"
251+ "${{ needs.build-ios.result }}"
252+ )
253+ for r in "${results[@]}"; do
254+ if [[ "$r" != "success" ]]; then
255+ echo "❌ One or more required jobs failed or were skipped."
256+ exit 1
257+ fi
258+ done
259+ echo "✅ All required checks passed."
0 commit comments