Files
deflock-app/.github/workflows/pr.yml
Doug Borg 348256270d Cache Flutter SDK, Gradle, and CocoaPods in CI
Cold Gradle builds were taking ~8.5 min for the APK job. Add
caching for Flutter/pub (via flutter-action), Gradle deps, and
CocoaPods to speed up subsequent runs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 18:29:02 -07:00

168 lines
4.9 KiB
YAML

name: Validate PR
on:
pull_request:
branches: [main]
push:
branches: [main]
jobs:
validate:
name: Analyze & Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: subosito/flutter-action@v2
with:
channel: 'stable'
cache: true
- run: flutter pub get
- name: Analyze
run: flutter analyze
- name: Test
run: flutter test
build-debug-apk:
name: Build Debug APK
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v5
- uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '17'
- uses: subosito/flutter-action@v2
with:
channel: 'stable'
cache: true
- uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: gradle-${{ runner.os }}-
- run: flutter pub get
- name: Generate icons and splash screens
run: |
dart run flutter_launcher_icons
dart run flutter_native_splash:create
- name: Build debug APK
run: flutter build apk --debug
- name: Upload debug APK
uses: actions/upload-artifact@v4
with:
name: debug-apk
path: build/app/outputs/flutter-apk/app-debug.apk
if-no-files-found: error
retention-days: 14
build-ios-simulator:
name: Build iOS Simulator
runs-on: macos-26
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v5
- uses: subosito/flutter-action@v2
with:
channel: 'stable'
cache: true
- uses: actions/cache@v4
with:
path: ios/Pods
key: pods-${{ runner.os }}-${{ hashFiles('ios/Podfile.lock') }}
restore-keys: pods-${{ runner.os }}-
- run: flutter pub get
- name: Generate icons and splash screens
run: |
dart run flutter_launcher_icons
dart run flutter_native_splash:create
- name: Build iOS simulator app
run: flutter build ios --debug --simulator
- name: Zip Runner.app
run: cd build/ios/iphonesimulator && zip -r "$GITHUB_WORKSPACE/Runner.app.zip" Runner.app
- name: Upload simulator build
uses: actions/upload-artifact@v4
with:
name: ios-simulator
path: Runner.app.zip
if-no-files-found: error
retention-days: 14
comment-artifacts:
name: Post Artifact Links
needs: [build-debug-apk, build-ios-simulator]
runs-on: ubuntu-latest
if: github.event_name == 'pull_request' && !cancelled()
permissions:
pull-requests: write
steps:
- uses: actions/github-script@v7
continue-on-error: true
env:
APK_RESULT: ${{ needs.build-debug-apk.result }}
IOS_RESULT: ${{ needs.build-ios-simulator.result }}
with:
script: |
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}#artifacts`;
const apkOk = process.env.APK_RESULT === 'success';
const iosOk = process.env.IOS_RESULT === 'success';
const lines = ['## Debug builds', ''];
if (apkOk || iosOk) {
lines.push(`Download from the [artifacts page](${runUrl}):`);
if (apkOk) lines.push('- **debug-apk** — install on Android device/emulator');
if (iosOk) lines.push('- **ios-simulator** — unzip and install with `xcrun simctl install booted Runner.app`');
}
if (!apkOk || !iosOk) {
const failed = [];
if (!apkOk) failed.push('Android APK');
if (!iosOk) failed.push('iOS simulator');
lines.push('', `**Failed:** ${failed.join(', ')} — check the [workflow run](${runUrl}) for details.`);
}
const body = lines.join('\n');
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const existing = comments.find(c => c.body.startsWith('## Debug builds'));
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
}