Files
deflock-app/.github/workflows/workflow.yml
2026-02-07 22:31:48 -07:00

340 lines
12 KiB
YAML

name: Build and Release
on:
release:
types: [published]
permissions:
contents: write
jobs:
get-version:
name: Get Version and Release Info
runs-on: ubuntu-latest
outputs:
version: ${{ steps.set-version.outputs.version }}
is_prerelease: ${{ steps.set-info.outputs.is_prerelease }}
should_upload_to_stores: ${{ steps.set-info.outputs.should_upload_to_stores }}
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Get version from pubspec.yaml
id: set-version
run: |
echo version=$(grep "version:" pubspec.yaml | head -1 | cut -d ':' -f 2 | tr -d ' ' | cut -d '+' -f 1) >> $GITHUB_OUTPUT
- name: Determine release actions
id: set-info
run: |
echo "is_prerelease=${{ github.event.release.prerelease }}" >> $GITHUB_OUTPUT
if [ "${{ github.event.release.prerelease }}" = "true" ]; then
echo "should_upload_to_stores=false" >> $GITHUB_OUTPUT
echo "✅ Pre-release - will build and attach assets, no store uploads"
else
echo "should_upload_to_stores=true" >> $GITHUB_OUTPUT
echo "✅ Full release - will build, attach assets, and upload to stores"
fi
build-android-apk:
name: Build Android APK
needs: get-version
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Set up JDK 17
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '17'
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: 'stable'
- name: Install dependencies
run: flutter pub get
- name: Run tests
run: flutter test
- name: Generate icons and splash screens
run: |
dart run flutter_launcher_icons
dart run flutter_native_splash:create
- name: Decode Keystore
run: |
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode > android/app/keystore.jks
- name: Create key.properties
run: |
echo "storePassword=${{ secrets.KEYSTORE_PASSWORD }}" > android/key.properties
echo "keyPassword=${{ secrets.KEY_PASSWORD }}" >> android/key.properties
echo "keyAlias=${{ vars.KEY_ALIAS }}" >> android/key.properties
echo "storeFile=keystore.jks" >> android/key.properties
- name: Build Android .apk
run: flutter build apk --release --dart-define=OSM_PROD_CLIENTID='${{ secrets.OSM_PROD_CLIENTID }}' --dart-define=OSM_SANDBOX_CLIENTID='${{ secrets.OSM_SANDBOX_CLIENTID }}'
- name: Upload .apk artifact
uses: actions/upload-artifact@v4
with:
name: deflock_v${{ needs.get-version.outputs.version }}.apk
path: build/app/outputs/flutter-apk/app-release.apk
if-no-files-found: 'error'
build-android-aab:
name: Build Android AAB
needs: get-version
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Set up JDK 17
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '17'
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: 'stable'
- name: Install dependencies
run: flutter pub get
- name: Run tests
run: flutter test
- name: Generate icons and splash screens
run: |
dart run flutter_launcher_icons
dart run flutter_native_splash:create
- name: Decode Keystore
run: |
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode > android/app/keystore.jks
- name: Create key.properties
run: |
echo "storePassword=${{ secrets.KEYSTORE_PASSWORD }}" > android/key.properties
echo "keyPassword=${{ secrets.KEY_PASSWORD }}" >> android/key.properties
echo "keyAlias=${{ vars.KEY_ALIAS }}" >> android/key.properties
echo "storeFile=keystore.jks" >> android/key.properties
- name: Build Android appBundle
run: flutter build appbundle --dart-define=OSM_PROD_CLIENTID='${{ secrets.OSM_PROD_CLIENTID }}' --dart-define=OSM_SANDBOX_CLIENTID='${{ secrets.OSM_SANDBOX_CLIENTID }}'
- name: Upload .aab artifact
uses: actions/upload-artifact@v4
with:
name: deflock_v${{ needs.get-version.outputs.version }}.aab
path: build/app/outputs/bundle/release/app-release.aab
if-no-files-found: 'error'
build-ios:
name: Build iOS
needs: get-version
runs-on: macos-latest
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: 'stable'
- name: Install dependencies
run: flutter pub get
- name: Run tests
run: flutter test
- name: Generate icons and splash screens
run: |
dart run flutter_launcher_icons
dart run flutter_native_splash:create
- name: Install Apple certificate and provisioning profile
env:
BUILD_CERTIFICATE_BASE64: ${{ secrets.IOS_DISTRIBUTION_CERTIFICATE_BASE64 }}
P12_PASSWORD: ""
BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.IOS_APPSTORE_PROVISIONING_PROFILE_BASE64 }}
KEYCHAIN_PASSWORD: ${{ secrets.IOS_KEYCHAIN_PASSWORD }}
run: |
# create variables
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
PP_PATH=$RUNNER_TEMP/build_pp.mobileprovision
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
# import certificate and provisioning profile from secrets
echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_PATH
# create temporary keychain
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
# import certificate to keychain
security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
# Set this keychain as the default
security list-keychain -d user -s $KEYCHAIN_PATH
security default-keychain -s $KEYCHAIN_PATH
# install provisioning profile
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles/61f9fdb9-bf2d-4d94-b249-63155ee71e74.mobileprovision
# Also install using the profile's internal UUID for better compatibility
UUID=$(security cms -D -i $PP_PATH | plutil -extract UUID xml1 -o - - | xmllint --xpath "//string/text()" -)
cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles/$UUID.mobileprovision
# Debug: Check what we actually have
echo "=== Certificates in keychain ==="
security find-identity -v -p codesigning $KEYCHAIN_PATH
echo "=== Provisioning profiles ==="
ls -la ~/Library/MobileDevice/Provisioning\ Profiles/
echo "=== Profile UUID extracted: $UUID ==="
- name: Create export options
run: |
cat > ios/exportOptions.plist << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>destination</key>
<string>export</string>
<key>method</key>
<string>app-store</string>
<key>teamID</key>
<string>7XG8T28436</string>
<key>provisioningProfiles</key>
<dict>
<key>me.deflock.deflockapp</key>
<string>61f9fdb9-bf2d-4d94-b249-63155ee71e74</string>
</dict>
<key>signingStyle</key>
<string>manual</string>
<key>stripSwiftSymbols</key>
<true/>
</dict>
</plist>
EOF
- name: Build iOS .ipa
run: |
flutter build ipa --release \
--export-options-plist=ios/exportOptions.plist \
--dart-define=OSM_PROD_CLIENTID='${{ secrets.OSM_PROD_CLIENTID }}' \
--dart-define=OSM_SANDBOX_CLIENTID='${{ secrets.OSM_SANDBOX_CLIENTID }}'
cp build/ios/ipa/*.ipa Runner.ipa
- name: Clean up keychain and provisioning profile
run: |
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
rm ~/Library/MobileDevice/Provisioning\ Profiles/61f9fdb9-bf2d-4d94-b249-63155ee71e74.mobileprovision
- name: Upload IPA artifact
uses: actions/upload-artifact@v4
with:
name: deflock_v${{ needs.get-version.outputs.version }}.ipa
path: Runner.ipa
if-no-files-found: 'error'
attach-to-release:
name: Attach Assets to Release
needs: [get-version, build-android-apk, build-android-aab, build-ios]
runs-on: ubuntu-latest
steps:
- name: Download APK artifact
uses: actions/download-artifact@v4
with:
name: deflock_v${{ needs.get-version.outputs.version }}.apk
- name: Download AAB artifact
uses: actions/download-artifact@v4
with:
name: deflock_v${{ needs.get-version.outputs.version }}.aab
- name: Download IPA artifact
uses: actions/download-artifact@v4
with:
name: deflock_v${{ needs.get-version.outputs.version }}.ipa
- name: Rename files for release
run: |
mv app-release.apk deflock_v${{ needs.get-version.outputs.version }}.apk
mv app-release.aab deflock_v${{ needs.get-version.outputs.version }}.aab
mv Runner.ipa deflock_v${{ needs.get-version.outputs.version }}.ipa
- name: Attach assets to release
uses: softprops/action-gh-release@v2
with:
files: |
deflock_v${{ needs.get-version.outputs.version }}.apk
deflock_v${{ needs.get-version.outputs.version }}.aab
deflock_v${{ needs.get-version.outputs.version }}.ipa
upload-to-stores:
name: Upload to App Stores
needs: [get-version, build-android-aab, build-ios]
runs-on: macos-latest # Need macOS for iOS uploads
if: needs.get-version.outputs.should_upload_to_stores == 'true'
steps:
- name: Download AAB artifact for Google Play
uses: actions/download-artifact@v4
with:
name: deflock_v${{ needs.get-version.outputs.version }}.aab
- name: Download IPA artifact for App Store
uses: actions/download-artifact@v4
with:
name: deflock_v${{ needs.get-version.outputs.version }}.ipa
# Temporarily disabled - uncomment when Google Play service account is ready
# - name: Upload to Google Play Store
# uses: r0adkll/upload-google-play@v1
# with:
# serviceAccountJsonPlainText: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON }}
# packageName: me.deflock.deflockapp
# releaseFiles: app-release.aab
# track: internal # Uploads to Internal Testing track for review before production
# status: completed
# inAppUpdatePriority: 0
- name: Upload to App Store Connect
env:
APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}
APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}
APP_STORE_CONNECT_API_KEY_BASE64: ${{ secrets.APP_STORE_CONNECT_API_KEY_BASE64 }}
run: |
# Create the private keys directory and decode API key
mkdir -p ~/private_keys
echo -n "$APP_STORE_CONNECT_API_KEY_BASE64" | base64 --decode > ~/private_keys/AuthKey_${APP_STORE_CONNECT_API_KEY_ID}.p8
# Upload to App Store Connect / TestFlight
xcrun altool --upload-app \
--type ios \
--file Runner.ipa \
--apiKey $APP_STORE_CONNECT_API_KEY_ID \
--apiIssuer $APP_STORE_CONNECT_ISSUER_ID
# Clean up sensitive files
rm -rf ~/private_keys
- name: Clean up artifacts
run: |
rm -f app-release.aab Runner.ipa