Skip to content

Commit 1b739f0

Browse files
committed
feat: add comprehensive cross-platform CI/CD workflows and documentation
This commit establishes the foundation for building iOS, Android, and macOS apps automatically via GitHub Actions. Changes: - Add iOS build workflow with Flutter support - Add Android build workflow with APK/AAB generation - Add macOS build workflow with desktop support - Add master cross-platform CI workflow - Add comprehensive CI/CD setup documentation - Add cross-platform roadmap with 5 epics - Add quick reference EPICS guide All workflows are ready to run with unsigned builds. Code signing steps are included but commented out, ready to enable once secrets are configured. Features: - Automated builds on push to main, develop, or claude/** branches - Parallel testing and building across platforms - Code quality checks (analyze, format) - Test execution with coverage reporting - Build artifact uploads - Ready for TestFlight, Play Store, and Mac App Store distribution Documentation: - Complete setup guide in docs/CI_CD_SETUP.md - Detailed roadmap in docs/CROSS_PLATFORM_ROADMAP.md - Quick epic overview in EPICS.md Workflows trigger automatically - no additional setup needed for basic builds.
1 parent 9643238 commit 1b739f0

7 files changed

Lines changed: 1884 additions & 0 deletions

File tree

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
name: Android Build
2+
3+
on:
4+
push:
5+
branches: [ "main", "develop", "claude/**" ]
6+
pull_request:
7+
branches: [ "main", "develop" ]
8+
workflow_dispatch:
9+
10+
jobs:
11+
build-android:
12+
name: Build Android App
13+
runs-on: ubuntu-latest
14+
timeout-minutes: 45
15+
16+
steps:
17+
- name: Checkout repository
18+
uses: actions/checkout@v4
19+
20+
- name: Set up Java
21+
uses: actions/setup-java@v4
22+
with:
23+
distribution: 'zulu'
24+
java-version: '17'
25+
cache: 'gradle'
26+
27+
- name: Set up Flutter
28+
uses: subosito/flutter-action@v2
29+
with:
30+
flutter-version: '3.24.5'
31+
channel: 'stable'
32+
cache: true
33+
34+
- name: Verify Flutter installation
35+
run: |
36+
flutter --version
37+
flutter doctor -v
38+
39+
- name: Install dependencies
40+
run: flutter pub get
41+
42+
- name: Run tests
43+
run: flutter test
44+
45+
- name: Analyze code
46+
run: flutter analyze
47+
48+
- name: Check formatting
49+
run: dart format --set-exit-if-changed .
50+
51+
- name: Build Android APK (Debug)
52+
run: flutter build apk --debug
53+
54+
- name: Build Android App Bundle (Release - Unsigned)
55+
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop')
56+
run: flutter build appbundle --release
57+
58+
- name: Build Android APK (Release - Unsigned)
59+
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop')
60+
run: flutter build apk --release
61+
62+
# Uncomment when you have Play Store signing configured
63+
# - name: Decode Keystore
64+
# if: github.event_name == 'push' && github.ref == 'refs/heads/main'
65+
# run: |
66+
# echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 --decode > android/app/release-keystore.jks
67+
68+
# - name: Create key.properties
69+
# if: github.event_name == 'push' && github.ref == 'refs/heads/main'
70+
# run: |
71+
# echo "storePassword=${{ secrets.ANDROID_KEYSTORE_PASSWORD }}" > android/key.properties
72+
# echo "keyPassword=${{ secrets.ANDROID_KEY_PASSWORD }}" >> android/key.properties
73+
# echo "keyAlias=${{ secrets.ANDROID_KEY_ALIAS }}" >> android/key.properties
74+
# echo "storeFile=release-keystore.jks" >> android/key.properties
75+
76+
# - name: Build Android App Bundle (Signed)
77+
# if: github.event_name == 'push' && github.ref == 'refs/heads/main'
78+
# run: flutter build appbundle --release
79+
80+
# - name: Upload to Play Store
81+
# if: github.event_name == 'push' && github.ref == 'refs/heads/main'
82+
# uses: r0adkll/upload-google-play@v1
83+
# with:
84+
# serviceAccountJsonPlainText: ${{ secrets.PLAY_STORE_SERVICE_ACCOUNT_JSON }}
85+
# packageName: com.evenrealities.flutter_helix
86+
# releaseFiles: build/app/outputs/bundle/release/app-release.aab
87+
# track: internal
88+
# status: draft
89+
90+
- name: Upload APK artifacts
91+
if: always()
92+
uses: actions/upload-artifact@v4
93+
with:
94+
name: android-apk-artifacts
95+
path: |
96+
build/app/outputs/flutter-apk/*.apk
97+
retention-days: 7
98+
99+
- name: Upload AAB artifacts
100+
if: always()
101+
uses: actions/upload-artifact@v4
102+
with:
103+
name: android-aab-artifacts
104+
path: |
105+
build/app/outputs/bundle/**/*.aab
106+
retention-days: 7
107+
108+
- name: Upload test results
109+
if: always()
110+
uses: actions/upload-artifact@v4
111+
with:
112+
name: android-test-results
113+
path: test-results/
114+
retention-days: 7
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
name: Cross-Platform CI
2+
3+
on:
4+
push:
5+
branches: [ "main", "develop", "claude/**" ]
6+
pull_request:
7+
branches: [ "main", "develop" ]
8+
workflow_dispatch:
9+
10+
jobs:
11+
# Run linting and formatting checks first
12+
code-quality:
13+
name: Code Quality Checks
14+
runs-on: ubuntu-latest
15+
timeout-minutes: 15
16+
17+
steps:
18+
- name: Checkout repository
19+
uses: actions/checkout@v4
20+
21+
- name: Set up Flutter
22+
uses: subosito/flutter-action@v2
23+
with:
24+
flutter-version: '3.24.5'
25+
channel: 'stable'
26+
cache: true
27+
28+
- name: Install dependencies
29+
run: flutter pub get
30+
31+
- name: Analyze code
32+
run: flutter analyze
33+
34+
- name: Check formatting
35+
run: dart format --set-exit-if-changed .
36+
37+
- name: Check for outdated dependencies
38+
run: flutter pub outdated
39+
40+
# Run all tests
41+
test:
42+
name: Run Tests
43+
runs-on: ubuntu-latest
44+
needs: code-quality
45+
timeout-minutes: 20
46+
47+
steps:
48+
- name: Checkout repository
49+
uses: actions/checkout@v4
50+
51+
- name: Set up Flutter
52+
uses: subosito/flutter-action@v2
53+
with:
54+
flutter-version: '3.24.5'
55+
channel: 'stable'
56+
cache: true
57+
58+
- name: Install dependencies
59+
run: flutter pub get
60+
61+
- name: Run unit tests
62+
run: flutter test --coverage
63+
64+
- name: Upload coverage to Codecov
65+
uses: codecov/codecov-action@v4
66+
with:
67+
files: ./coverage/lcov.info
68+
flags: unittests
69+
name: codecov-umbrella
70+
fail_ci_if_error: false
71+
72+
# Build for iOS
73+
build-ios:
74+
name: Build iOS
75+
needs: test
76+
uses: ./.github/workflows/ios-build.yml
77+
secrets: inherit
78+
79+
# Build for Android
80+
build-android:
81+
name: Build Android
82+
needs: test
83+
uses: ./.github/workflows/android-build.yml
84+
secrets: inherit
85+
86+
# Build for macOS
87+
build-macos:
88+
name: Build macOS
89+
needs: test
90+
uses: ./.github/workflows/macos-build.yml
91+
secrets: inherit
92+
93+
# Summary job that requires all builds to pass
94+
build-summary:
95+
name: Build Summary
96+
runs-on: ubuntu-latest
97+
needs: [build-ios, build-android, build-macos]
98+
if: always()
99+
100+
steps:
101+
- name: Check build results
102+
run: |
103+
echo "Build Summary:"
104+
echo "=============="
105+
echo "iOS Build: ${{ needs.build-ios.result }}"
106+
echo "Android Build: ${{ needs.build-android.result }}"
107+
echo "macOS Build: ${{ needs.build-macos.result }}"
108+
109+
if [ "${{ needs.build-ios.result }}" != "success" ] || \
110+
[ "${{ needs.build-android.result }}" != "success" ] || \
111+
[ "${{ needs.build-macos.result }}" != "success" ]; then
112+
echo "One or more builds failed!"
113+
exit 1
114+
fi
115+
116+
echo "All builds completed successfully!"
117+
118+
- name: Create success badge
119+
if: success()
120+
run: |
121+
echo "✅ All platform builds passed!"

.github/workflows/ios-build.yml

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
name: iOS Build
2+
3+
on:
4+
push:
5+
branches: [ "main", "develop", "claude/**" ]
6+
pull_request:
7+
branches: [ "main", "develop" ]
8+
workflow_dispatch:
9+
10+
jobs:
11+
build-ios:
12+
name: Build iOS App
13+
runs-on: macos-14
14+
timeout-minutes: 60
15+
16+
steps:
17+
- name: Checkout repository
18+
uses: actions/checkout@v4
19+
20+
- name: Set up Flutter
21+
uses: subosito/flutter-action@v2
22+
with:
23+
flutter-version: '3.24.5'
24+
channel: 'stable'
25+
cache: true
26+
27+
- name: Verify Flutter installation
28+
run: |
29+
flutter --version
30+
flutter doctor -v
31+
32+
- name: Install dependencies
33+
run: flutter pub get
34+
35+
- name: Run tests
36+
run: flutter test
37+
38+
- name: Analyze code
39+
run: flutter analyze
40+
41+
- name: Check formatting
42+
run: dart format --set-exit-if-changed .
43+
44+
- name: Install CocoaPods dependencies
45+
working-directory: ios
46+
run: |
47+
pod install --repo-update
48+
49+
- name: Build iOS app (Debug)
50+
run: |
51+
flutter build ios --debug --no-codesign
52+
env:
53+
FLUTTER_BUILD_MODE: debug
54+
55+
- name: Build iOS app (Release - No Codesign)
56+
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop')
57+
run: |
58+
flutter build ios --release --no-codesign
59+
env:
60+
FLUTTER_BUILD_MODE: release
61+
62+
# Uncomment when you have signing certificates configured
63+
# - name: Import Code Signing Certificates
64+
# if: github.event_name == 'push' && github.ref == 'refs/heads/main'
65+
# uses: apple-actions/import-codesign-certs@v2
66+
# with:
67+
# p12-file-base64: ${{ secrets.IOS_P12_BASE64 }}
68+
# p12-password: ${{ secrets.IOS_P12_PASSWORD }}
69+
70+
# - name: Install Provisioning Profile
71+
# if: github.event_name == 'push' && github.ref == 'refs/heads/main'
72+
# run: |
73+
# mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
74+
# echo "${{ secrets.IOS_PROVISION_PROFILE_BASE64 }}" | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/profile.mobileprovision
75+
76+
# - name: Build iOS app (Release - Signed)
77+
# if: github.event_name == 'push' && github.ref == 'refs/heads/main'
78+
# run: |
79+
# flutter build ipa --release --export-options-plist=ios/ExportOptions.plist
80+
81+
# - name: Upload IPA to App Store Connect
82+
# if: github.event_name == 'push' && github.ref == 'refs/heads/main'
83+
# uses: apple-actions/upload-testflight-build@v1
84+
# with:
85+
# app-path: build/ios/ipa/*.ipa
86+
# issuer-id: ${{ secrets.APPSTORE_ISSUER_ID }}
87+
# api-key-id: ${{ secrets.APPSTORE_API_KEY_ID }}
88+
# api-private-key: ${{ secrets.APPSTORE_API_PRIVATE_KEY }}
89+
90+
- name: Upload build artifacts
91+
if: always()
92+
uses: actions/upload-artifact@v4
93+
with:
94+
name: ios-build-artifacts
95+
path: |
96+
build/ios/
97+
!build/ios/**/*.framework
98+
!build/ios/**/*.dSYM
99+
retention-days: 7
100+
101+
- name: Upload test results
102+
if: always()
103+
uses: actions/upload-artifact@v4
104+
with:
105+
name: ios-test-results
106+
path: test-results/
107+
retention-days: 7

0 commit comments

Comments
 (0)