Skip to content

Develop Deploy

Develop Deploy #70

name: Develop Deploy
on:
workflow_dispatch:
inputs:
platform:
description: "Platform to deploy"
required: true
type: choice
options:
- android
- ios
- macos
- windows
- both
- all
default: both
concurrency:
group: develop-deploy-${{ inputs.platform }}
cancel-in-progress: false
jobs:
deploy-ios:
if: inputs.platform == 'ios' || inputs.platform == 'both' || inputs.platform == 'all'
name: Deploy to TestFlight
runs-on: [self-hosted, macOS]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Configure SSH for private dependency
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Add hosts to known_hosts
run: |
ssh-keyscan -p 2822 git.techstackapps.com >> ~/.ssh/known_hosts
ssh-keyscan github.com >> ~/.ssh/known_hosts
- name: Restore API key from secret
env:
ASC_KEY_CONTENT: ${{ secrets.ASC_KEY_CONTENT }}
run: |
mkdir -p ios/fastlane/private_keys
printf '%s\n' "$ASC_KEY_CONTENT" > ios/fastlane/private_keys/AuthKey.p8
- name: Create .env file
run: echo "${{ secrets.ENV_FILE_CONTENT }}" > .env
- name: Restore Apple Wallet certificates
run: |
mkdir -p assets/certs
echo "${{ secrets.APPLE_PASS_CERTIFICATE_BASE64 }}" | base64 --decode > assets/certs/pass_certificate.pem
echo "${{ secrets.APPLE_PASS_PRIVATE_KEY_BASE64 }}" | base64 --decode > assets/certs/private_key.pem
- name: Install dependencies
run: fvm flutter pub get
- name: Run code generation
run: fvm dart run build_runner build --delete-conflicting-outputs
- name: Install CocoaPods dependencies
run: cd ios && rm -rf Podfile.lock Pods && pod install --repo-update
- name: Install Fastlane dependencies
run: cd ios && bundle install
- name: Setup CI keychain
run: |
security create-keychain -p "ci" ci_build.keychain-db || true
security unlock-keychain -p "ci" ci_build.keychain-db
security set-keychain-settings -t 3600 -u ci_build.keychain-db
security list-keychains -d user -s ci_build.keychain-db login.keychain-db
security default-keychain -s ci_build.keychain-db
- name: Setup Shorebird
uses: shorebirdtech/setup-shorebird@v1
with:
cache: true
env:
SHOREBIRD_TOKEN: ${{ secrets.SHOREBIRD_TOKEN }}
- name: Deploy to TestFlight
env:
SHOREBIRD_TOKEN: ${{ secrets.SHOREBIRD_TOKEN }}
ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
ASC_KEY_PATH: ./private_keys/AuthKey.p8
MATCH_GIT_URL: ${{ secrets.MATCH_GIT_URL }}
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
MATCH_KEYCHAIN_NAME: ci_build.keychain-db
MATCH_KEYCHAIN_PASSWORD: ci
run: |
cd ios
bundle exec fastlane beta
- name: Cleanup
if: always()
run: |
security delete-keychain ci_build.keychain-db || true
security list-keychains -d user -s login.keychain-db
security default-keychain -s login.keychain-db
rm -rf ios/fastlane/private_keys
deploy-android:
if: inputs.platform == 'android' || inputs.platform == 'both' || inputs.platform == 'all'
name: Deploy to Play Store
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Configure SSH for private dependency
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Add private dependency host to known_hosts
run: ssh-keyscan -p 2822 git.techstackapps.com >> ~/.ssh/known_hosts
- name: Setup Java 17
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "17"
- name: Install Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: "3.38.7"
cache: true
- name: Create .env file
run: echo "${{ secrets.ENV_FILE_CONTENT }}" > .env
- name: Restore Apple Wallet certificates
run: |
mkdir -p assets/certs
echo "${{ secrets.APPLE_PASS_CERTIFICATE_BASE64 }}" | base64 --decode > assets/certs/pass_certificate.pem
echo "${{ secrets.APPLE_PASS_PRIVATE_KEY_BASE64 }}" | base64 --decode > assets/certs/private_key.pem
- name: Restore Google Wallet service account
run: |
mkdir -p assets/certs/android
echo "${{ secrets.GOOGLE_WALLET_SERVICE_ACCOUNT_BASE64 }}" | base64 --decode > assets/certs/android/service-account.json
- name: Decode keystore
run: echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 --decode > android/app/upload-keystore.jks
- name: Write key.properties
run: |
cat > android/key.properties << EOF
storePassword=${{ secrets.ANDROID_STORE_PASSWORD }}
keyPassword=${{ secrets.ANDROID_KEY_PASSWORD }}
keyAlias=${{ secrets.ANDROID_KEY_ALIAS }}
storeFile=upload-keystore.jks
EOF
- name: Install dependencies
run: flutter pub get
- name: Run code generation
run: dart run build_runner build --delete-conflicting-outputs
- name: Reduce Gradle heap for CI
run: sed -i 's/-Xmx8G/-Xmx4G/' android/gradle.properties
- name: Decode service account JSON
run: echo "${{ secrets.PLAY_STORE_SERVICE_ACCOUNT_BASE64 }}" | base64 --decode > android/fastlane/service-account.json
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.1"
bundler-cache: true
working-directory: android
- name: Setup Shorebird
uses: shorebirdtech/setup-shorebird@v1
with:
cache: true
env:
SHOREBIRD_TOKEN: ${{ secrets.SHOREBIRD_TOKEN }}
- name: Deploy to Google Play
env:
SHOREBIRD_TOKEN: ${{ secrets.SHOREBIRD_TOKEN }}
run: |
cd android
bundle exec fastlane beta
- name: Cleanup sensitive files
if: always()
run: |
rm -f android/app/upload-keystore.jks
rm -f android/key.properties
rm -f android/fastlane/service-account.json
rm -f assets/certs/android/service-account.json
deploy-macos:
if: inputs.platform == 'macos' || inputs.platform == 'all'
name: Deploy macOS to TestFlight
runs-on: [self-hosted, macOS]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Configure SSH for private dependency
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Add hosts to known_hosts
run: |
ssh-keyscan -p 2822 git.techstackapps.com >> ~/.ssh/known_hosts
ssh-keyscan github.com >> ~/.ssh/known_hosts
- name: Restore API key from secret
env:
ASC_KEY_CONTENT: ${{ secrets.ASC_KEY_CONTENT }}
run: |
mkdir -p macos/fastlane/private_keys
printf '%s\n' "$ASC_KEY_CONTENT" > macos/fastlane/private_keys/AuthKey.p8
- name: Create .env file
run: echo "${{ secrets.ENV_FILE_CONTENT }}" > .env
- name: Install dependencies
run: fvm flutter pub get
- name: Run code generation
run: fvm dart run build_runner build --delete-conflicting-outputs
- name: Precache macOS engine
run: fvm flutter precache --macos
- name: Install CocoaPods dependencies
run: cd macos && rm -rf Podfile.lock Pods && pod install --repo-update
- name: Install Fastlane dependencies
run: cd macos && bundle install
- name: Setup CI keychain
run: |
security delete-keychain ci_build.keychain-db || true
security create-keychain -p "ci" ci_build.keychain-db
security unlock-keychain -p "ci" ci_build.keychain-db
security set-keychain-settings -t 3600 -u ci_build.keychain-db
security list-keychains -d user -s ci_build.keychain-db login.keychain-db
security default-keychain -s ci_build.keychain-db
- name: Deploy macOS to TestFlight
env:
ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
ASC_KEY_PATH: ./private_keys/AuthKey.p8
MATCH_GIT_URL: ${{ secrets.MATCH_GIT_URL }}
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
MATCH_KEYCHAIN_NAME: ci_build.keychain-db
MATCH_KEYCHAIN_PASSWORD: ci
run: |
cd macos
bundle exec fastlane beta
- name: Cleanup
if: always()
run: |
security delete-keychain ci_build.keychain-db || true
security list-keychains -d user -s login.keychain-db
security default-keychain -s login.keychain-db
rm -rf macos/fastlane/private_keys
deploy-windows:
if: inputs.platform == 'windows' || inputs.platform == 'all'
name: Build Windows Release
runs-on: windows-latest
defaults:
run:
shell: bash
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Configure SSH for private dependency
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Add hosts to known_hosts
run: |
mkdir -p ~/.ssh
ssh-keyscan -p 2822 git.techstackapps.com >> ~/.ssh/known_hosts 2>/dev/null
ssh-keyscan github.com >> ~/.ssh/known_hosts 2>/dev/null
- name: Install Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: "3.38.7"
cache: true
- name: Enable Windows desktop
run: flutter config --enable-windows-desktop
- name: Create .env file
run: echo "${{ secrets.ENV_FILE_CONTENT }}" > .env
- name: Install dependencies
run: flutter pub get
- name: Run code generation
run: dart run build_runner build --delete-conflicting-outputs
- name: Build Windows release
run: flutter build windows --release --target lib/main_desktop.dart
- name: Get version from pubspec
id: version
run: |
VERSION=$(grep '^version:' pubspec.yaml | sed 's/version: //' | sed 's/+.*//')
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Package portable zip
shell: pwsh
run: |
Compress-Archive -Path "build\windows\x64\runner\Release\*" -DestinationPath "HealthWallet-Windows-v${{ steps.version.outputs.version }}-portable.zip"
- name: Create MSIX installer
run: dart run msix:create --version ${{ steps.version.outputs.version }}.0
- name: Copy MSIX to workspace root
shell: pwsh
run: |
$msix = Get-ChildItem -Path "build\windows\x64\runner\Release" -Filter "*.msix" -Recurse | Select-Object -First 1
if ($msix) {
Copy-Item $msix.FullName "HealthWallet-Windows-v${{ steps.version.outputs.version }}-setup.msix"
}
- name: Upload to GitHub Pre-release
uses: softprops/action-gh-release@v2
with:
tag_name: "v${{ steps.version.outputs.version }}-dev.${{ github.run_number }}"
name: "v${{ steps.version.outputs.version }}-dev.${{ github.run_number }}"
files: |
HealthWallet-Windows-v${{ steps.version.outputs.version }}-portable.zip
HealthWallet-Windows-v${{ steps.version.outputs.version }}-setup.msix
prerelease: true
generate_release_notes: false
body: |
## Dev Build (Windows)
**Branch:** `${{ github.ref_name }}`
**Commit:** `${{ github.sha }}`
### Downloads
- **Portable (.zip):** Extract and run `health_wallet.exe`
- **Installer (.msix):** Double-click to install (Windows 10+)
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Cleanup
if: always()
run: rm -f .env