mirror of
https://github.com/zebrajr/immich.git
synced 2025-12-06 00:20:20 +01:00
300 lines
11 KiB
YAML
300 lines
11 KiB
YAML
name: Build Mobile
|
|
|
|
on:
|
|
workflow_call:
|
|
inputs:
|
|
ref:
|
|
required: false
|
|
type: string
|
|
environment:
|
|
description: 'Target environment'
|
|
required: true
|
|
default: 'development'
|
|
type: string
|
|
secrets:
|
|
KEY_JKS:
|
|
required: true
|
|
ALIAS:
|
|
required: true
|
|
ANDROID_KEY_PASSWORD:
|
|
required: true
|
|
ANDROID_STORE_PASSWORD:
|
|
required: true
|
|
pull_request:
|
|
push:
|
|
branches: [main]
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
permissions: {}
|
|
|
|
jobs:
|
|
pre-job:
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
outputs:
|
|
should_run: ${{ steps.check.outputs.should_run }}
|
|
steps:
|
|
- id: token
|
|
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
|
|
with:
|
|
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
|
|
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
|
|
|
|
- name: Check what should run
|
|
id: check
|
|
uses: immich-app/devtools/actions/pre-job@08bac802a312fc89808e0dd589271ca0974087b5 # pre-job-action-v2.0.0
|
|
with:
|
|
github-token: ${{ steps.token.outputs.token }}
|
|
filters: |
|
|
mobile:
|
|
- 'mobile/**'
|
|
force-filters: |
|
|
- '.github/workflows/build-mobile.yml'
|
|
force-events: 'workflow_call,workflow_dispatch'
|
|
|
|
build-sign-android:
|
|
name: Build and sign Android
|
|
needs: pre-job
|
|
permissions:
|
|
contents: read
|
|
# Skip when PR from a fork
|
|
if: ${{ !github.event.pull_request.head.repo.fork && github.actor != 'dependabot[bot]' && fromJSON(needs.pre-job.outputs.should_run).mobile == true }}
|
|
runs-on: mich
|
|
|
|
steps:
|
|
- id: token
|
|
uses: immich-app/devtools/actions/create-workflow-token@da177fa133657503ddb7503f8ba53dccefec5da1 # create-workflow-token-action-v1.0.0
|
|
with:
|
|
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
|
|
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
|
|
|
|
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
|
with:
|
|
ref: ${{ inputs.ref || github.sha }}
|
|
persist-credentials: false
|
|
token: ${{ steps.token.outputs.token }}
|
|
|
|
- name: Create the Keystore
|
|
env:
|
|
KEY_JKS: ${{ secrets.KEY_JKS }}
|
|
working-directory: ./mobile
|
|
run: printf "%s" $KEY_JKS | base64 -d > android/key.jks
|
|
|
|
- uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
|
|
with:
|
|
distribution: 'zulu'
|
|
java-version: '17'
|
|
|
|
- name: Restore Gradle Cache
|
|
id: cache-gradle-restore
|
|
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
|
with:
|
|
path: |
|
|
~/.gradle/caches
|
|
~/.gradle/wrapper
|
|
~/.android/sdk
|
|
mobile/android/.gradle
|
|
mobile/.dart_tool
|
|
key: build-mobile-gradle-${{ runner.os }}-main
|
|
|
|
- name: Setup Flutter SDK
|
|
uses: subosito/flutter-action@fd55f4c5af5b953cc57a2be44cb082c8f6635e8e # v2.21.0
|
|
with:
|
|
channel: 'stable'
|
|
flutter-version-file: ./mobile/pubspec.yaml
|
|
cache: true
|
|
|
|
- name: Setup Android SDK
|
|
uses: android-actions/setup-android@9fc6c4e9069bf8d3d10b2204b1fb8f6ef7065407 # v3.2.2
|
|
with:
|
|
packages: ''
|
|
|
|
- name: Get Packages
|
|
working-directory: ./mobile
|
|
run: flutter pub get
|
|
|
|
- name: Generate translation file
|
|
run: dart run easy_localization:generate -S ../i18n && dart run bin/generate_keys.dart
|
|
working-directory: ./mobile
|
|
|
|
- name: Generate platform APIs
|
|
run: make pigeon
|
|
working-directory: ./mobile
|
|
|
|
- name: Build Android App Bundle
|
|
working-directory: ./mobile
|
|
env:
|
|
ALIAS: ${{ secrets.ALIAS }}
|
|
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
|
|
ANDROID_STORE_PASSWORD: ${{ secrets.ANDROID_STORE_PASSWORD }}
|
|
IS_MAIN: ${{ github.ref == 'refs/heads/main' }}
|
|
run: |
|
|
if [[ $IS_MAIN == 'true' ]]; then
|
|
flutter build apk --release
|
|
flutter build apk --release --split-per-abi --target-platform android-arm,android-arm64,android-x64
|
|
else
|
|
flutter build apk --debug --split-per-abi --target-platform android-arm64
|
|
fi
|
|
|
|
- name: Publish Android Artifact
|
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
with:
|
|
name: release-apk-signed
|
|
path: mobile/build/app/outputs/flutter-apk/*.apk
|
|
|
|
- name: Save Gradle Cache
|
|
id: cache-gradle-save
|
|
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
|
if: github.ref == 'refs/heads/main'
|
|
with:
|
|
path: |
|
|
~/.gradle/caches
|
|
~/.gradle/wrapper
|
|
~/.android/sdk
|
|
mobile/android/.gradle
|
|
mobile/.dart_tool
|
|
key: ${{ steps.cache-gradle-restore.outputs.cache-primary-key }}
|
|
|
|
build-sign-ios:
|
|
name: Build and sign iOS
|
|
needs: pre-job
|
|
permissions:
|
|
contents: read
|
|
# Run on main branch or workflow_dispatch
|
|
if: ${{ !github.event.pull_request.head.repo.fork && fromJSON(needs.pre-job.outputs.should_run).mobile == true && github.ref == 'refs/heads/main' }}
|
|
runs-on: macos-latest
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
|
|
with:
|
|
ref: ${{ inputs.ref || github.sha }}
|
|
persist-credentials: false
|
|
|
|
- name: Setup Flutter SDK
|
|
uses: subosito/flutter-action@fd55f4c5af5b953cc57a2be44cb082c8f6635e8e # v2
|
|
with:
|
|
channel: 'stable'
|
|
flutter-version-file: ./mobile/pubspec.yaml
|
|
cache: true
|
|
|
|
- name: Install Flutter dependencies
|
|
working-directory: ./mobile
|
|
run: flutter pub get
|
|
|
|
- name: Generate translation files
|
|
run: dart run easy_localization:generate -S ../i18n && dart run bin/generate_keys.dart
|
|
working-directory: ./mobile
|
|
|
|
- name: Generate platform APIs
|
|
run: make pigeon
|
|
working-directory: ./mobile
|
|
|
|
- name: Setup Ruby
|
|
uses: ruby/setup-ruby@v1
|
|
with:
|
|
ruby-version: '3.3'
|
|
working-directory: ./mobile/ios
|
|
|
|
- name: Install CocoaPods dependencies
|
|
working-directory: ./mobile/ios
|
|
run: |
|
|
pod install
|
|
|
|
- name: Install Fastlane
|
|
working-directory: ./mobile/ios
|
|
run: |
|
|
gem install bundler
|
|
bundle config set --local path 'vendor/bundle'
|
|
bundle install
|
|
|
|
- name: Create API Key
|
|
env:
|
|
API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}
|
|
API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
|
|
API_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_API_KEY }}
|
|
working-directory: ./mobile/ios
|
|
run: |
|
|
mkdir -p ~/.appstoreconnect/private_keys
|
|
echo "$API_KEY_CONTENT" | base64 --decode > ~/.appstoreconnect/private_keys/AuthKey_${API_KEY_ID}.p8
|
|
|
|
- name: Import Certificate and Provisioning Profiles
|
|
env:
|
|
IOS_CERTIFICATE_P12: ${{ secrets.IOS_CERTIFICATE_P12 }}
|
|
IOS_CERTIFICATE_PASSWORD: ${{ secrets.IOS_CERTIFICATE_PASSWORD }}
|
|
IOS_PROVISIONING_PROFILE: ${{ secrets.IOS_PROVISIONING_PROFILE }}
|
|
IOS_PROVISIONING_PROFILE_SHARE_EXTENSION: ${{ secrets.IOS_PROVISIONING_PROFILE_SHARE_EXTENSION }}
|
|
IOS_PROVISIONING_PROFILE_WIDGET_EXTENSION: ${{ secrets.IOS_PROVISIONING_PROFILE_WIDGET_EXTENSION }}
|
|
IOS_DEVELOPMENT_PROVISIONING_PROFILE: ${{ secrets.IOS_DEVELOPMENT_PROVISIONING_PROFILE }}
|
|
IOS_DEVELOPMENT_PROVISIONING_PROFILE_SHARE_EXTENSION: ${{ secrets.IOS_DEVELOPMENT_PROVISIONING_PROFILE_SHARE_EXTENSION }}
|
|
IOS_DEVELOPMENT_PROVISIONING_PROFILE_WIDGET_EXTENSION: ${{ secrets.IOS_DEVELOPMENT_PROVISIONING_PROFILE_WIDGET_EXTENSION }}
|
|
ENVIRONMENT: ${{ inputs.environment || 'development' }}
|
|
working-directory: ./mobile/ios
|
|
run: |
|
|
# Decode certificate
|
|
echo "$IOS_CERTIFICATE_P12" | base64 --decode > certificate.p12
|
|
|
|
# Decode provisioning profiles based on environment
|
|
if [[ "$ENVIRONMENT" == "development" ]]; then
|
|
echo "$IOS_DEVELOPMENT_PROVISIONING_PROFILE" | base64 --decode > profile_dev.mobileprovision
|
|
echo "$IOS_DEVELOPMENT_PROVISIONING_PROFILE_SHARE_EXTENSION" | base64 --decode > profile_dev_share.mobileprovision
|
|
echo "$IOS_DEVELOPMENT_PROVISIONING_PROFILE_WIDGET_EXTENSION" | base64 --decode > profile_dev_widget.mobileprovision
|
|
ls -lh profile_dev*.mobileprovision
|
|
else
|
|
echo "$IOS_PROVISIONING_PROFILE" | base64 --decode > profile.mobileprovision
|
|
echo "$IOS_PROVISIONING_PROFILE_SHARE_EXTENSION" | base64 --decode > profile_share.mobileprovision
|
|
echo "$IOS_PROVISIONING_PROFILE_WIDGET_EXTENSION" | base64 --decode > profile_widget.mobileprovision
|
|
ls -lh profile*.mobileprovision
|
|
fi
|
|
|
|
- name: Create keychain and import certificate
|
|
env:
|
|
KEYCHAIN_PASSWORD: ${{ secrets.IOS_CERTIFICATE_PASSWORD }}
|
|
CERTIFICATE_PASSWORD: ${{ secrets.IOS_CERTIFICATE_PASSWORD }}
|
|
working-directory: ./mobile/ios
|
|
run: |
|
|
# Create keychain
|
|
security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
|
|
security default-keychain -s build.keychain
|
|
security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
|
|
security set-keychain-settings -t 3600 -u build.keychain
|
|
|
|
# Import certificate
|
|
security import certificate.p12 -k build.keychain -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign -T /usr/bin/security
|
|
security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" build.keychain
|
|
|
|
# Verify certificate was imported
|
|
security find-identity -v -p codesigning build.keychain
|
|
|
|
- name: Build and deploy to TestFlight
|
|
env:
|
|
FASTLANE_TEAM_ID: ${{ secrets.FASTLANE_TEAM_ID }}
|
|
IOS_CERTIFICATE_PASSWORD: ${{ secrets.IOS_CERTIFICATE_PASSWORD }}
|
|
KEYCHAIN_NAME: build.keychain
|
|
KEYCHAIN_PASSWORD: ${{ secrets.IOS_CERTIFICATE_PASSWORD }}
|
|
APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}
|
|
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
|
|
ENVIRONMENT: ${{ inputs.environment || 'development' }}
|
|
working-directory: ./mobile/ios
|
|
run: |
|
|
if [[ "$ENVIRONMENT" == "development" ]]; then
|
|
bundle exec fastlane gha_testflight_dev
|
|
else
|
|
bundle exec fastlane gha_release_prod
|
|
fi
|
|
|
|
- name: Clean up keychain
|
|
if: always()
|
|
run: |
|
|
security delete-keychain build.keychain || true
|
|
|
|
- name: Upload IPA artifact
|
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
|
with:
|
|
name: ios-release-ipa
|
|
path: mobile/ios/Runner.ipa
|