Build pipeline for both platforms #42
@@ -39,11 +39,23 @@ jobs:
 | 
			
		||||
          # remove the 'v' prefix from the tag name
 | 
			
		||||
          echo "BUILD_NAME=${REF_NAME//v}" >> $GITHUB_ENV
 | 
			
		||||
 | 
			
		||||
      - name: Load secrets from github
 | 
			
		||||
      - name: Load secrets
 | 
			
		||||
        id: load-secrets
 | 
			
		||||
        uses: hashicorp/vault-action@v3
 | 
			
		||||
        with:
 | 
			
		||||
          url: https://api.hashicorp.com
 | 
			
		||||
          token: ${{ secrets.VAULT_TOKEN }}
 | 
			
		||||
          secrets: |
 | 
			
		||||
            secret/release GOOGLE_MAPS_API_KEY | GOOGLE_MAPS_API_KEY ;
 | 
			
		||||
            secret/release ANDROID_SECRET_PROPERTIES_BASE64 | ANDROID_SECRET_PROPERTIES_BASE64 ;
 | 
			
		||||
            secret/release ANDROID_GOOGLE_PLAY_JSON_BASE64 | ANDROID_GOOGLE_PLAY_JSON_BASE64 ;
 | 
			
		||||
            secret/release ANDROID_KEYSTORE_BASE64 | ANDROID_KEYSTORE_BASE64 ;
 | 
			
		||||
 | 
			
		||||
      - name: Put selected secrets into files
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "${{ secrets.ANDROID_SECRET_PROPERTIES_BASE64 }}" | base64 -d > secrets.properties
 | 
			
		||||
          echo "${{ secrets.ANDROID_GOOGLE_PLAY_JSON_BASE64 }}" | base64 -d > google-key.json
 | 
			
		||||
          echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 -d > release.keystore
 | 
			
		||||
          echo "${{ steps.load-secrets.outputs.ANDROID_SECRET_PROPERTIES_BASE64 }}" | base64 -d > secrets.properties
 | 
			
		||||
          echo "${{ steps.load-secrets.outputs.ANDROID_GOOGLE_PLAY_JSON_BASE64 }}" | base64 -d > google-key.json
 | 
			
		||||
          echo "${{ steps.load-secrets.outputs.ANDROID_KEYSTORE_BASE64 }}" | base64 -d > release.keystore
 | 
			
		||||
        working-directory: android
 | 
			
		||||
 | 
			
		||||
      - name: Install fastlane
 | 
			
		||||
@@ -56,4 +68,4 @@ jobs:
 | 
			
		||||
        env:
 | 
			
		||||
          BUILD_NUMBER: ${{ github.run_number }}
 | 
			
		||||
          # BUILD_NAME is implicitly available
 | 
			
		||||
          GOOGLE_MAPS_API_KEY: ${{ secrets.GOOGLE_MAPS_API_KEY }}
 | 
			
		||||
          GOOGLE_MAPS_API_KEY: ${{ steps.load-secrets.outputs.GOOGLE_MAPS_API_KEY }}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										25
									
								
								frontend/.github/workflows/build_app_ios.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										25
									
								
								frontend/.github/workflows/build_app_ios.yaml
									
									
									
									
										vendored
									
									
								
							@@ -30,12 +30,17 @@ jobs:
 | 
			
		||||
          # remove the 'v' prefix from the tag name
 | 
			
		||||
          echo "BUILD_NAME=${REF_NAME//v}" >> $GITHUB_ENV
 | 
			
		||||
 | 
			
		||||
      - name: Load secrets from github
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "${{ secrets.IOS_SECRET_PROPERTIES_BASE64 }}" | base64 -d > secrets.properties
 | 
			
		||||
          echo "${{ secrets.IOS_GOOGLE_PLAY_JSON_BASE64 }}" | base64 -d > google-key.json
 | 
			
		||||
          echo "${{ secrets.IOS_KEYSTORE_BASE64 }}" | base64 -d > release.keystore
 | 
			
		||||
        working-directory: ios
 | 
			
		||||
      - name: Load secrets
 | 
			
		||||
        id: load-secrets
 | 
			
		||||
        uses: hashicorp/vault-action@v3
 | 
			
		||||
        with:
 | 
			
		||||
          url: https://api.hashicorp.com
 | 
			
		||||
          token: ${{ secrets.VAULT_TOKEN }}
 | 
			
		||||
          secrets: |
 | 
			
		||||
            secret/release GOOGLE_MAPS_API_KEY | GOOGLE_MAPS_API_KEY ;
 | 
			
		||||
            secret/release IOS_ASC_KEY_ID | IOS_ASC_KEY_ID ;
 | 
			
		||||
            secret/release IOS_ASC_ISSUER_ID | IOS_ASC_ISSUER_ID ;
 | 
			
		||||
            secret/release IOS_ASC_KEY_P8 | IOS_ASC_KEY_P8 ;
 | 
			
		||||
 | 
			
		||||
      - name: Install fastlane
 | 
			
		||||
        run: bundle install
 | 
			
		||||
@@ -47,7 +52,7 @@ jobs:
 | 
			
		||||
        env:
 | 
			
		||||
          BUILD_NUMBER: ${{ github.run_number }}
 | 
			
		||||
          # BUILD_NAME is implicitly available
 | 
			
		||||
          GOOGLE_MAPS_API_KEY: ${{ secrets.GOOGLE_MAPS_API_KEY }}
 | 
			
		||||
          IOS_ASC_KEY_ID: ${{ secrets.IOS_ASC_KEY_ID }}
 | 
			
		||||
          IOS_ASC_ISSUER_ID: ${{ secrets.IOS_ASC_ISSUER_ID }}
 | 
			
		||||
          IOS_ASC_KEY_P8: ${{ secrets.IOS_ASC_KEY_P8 }}
 | 
			
		||||
          GOOGLE_MAPS_API_KEY: ${{ steps.load-secrets.outputs.GOOGLE_MAPS_API_KEY }}
 | 
			
		||||
          IOS_ASC_KEY_ID: ${{ GOOGLE_MAPS_API_KEY.IOS_ASC_KEY_ID }}
 | 
			
		||||
          IOS_ASC_ISSUER_ID: ${{ GOOGLE_MAPS_API_KEY.IOS_ASC_ISSUER_ID }}
 | 
			
		||||
          IOS_ASC_KEY_P8: ${{ GOOGLE_MAPS_API_KEY.IOS_ASC_KEY_P8 }}
 | 
			
		||||
 
 | 
			
		||||
@@ -46,12 +46,17 @@ bundle exec fastlane <lane>
 | 
			
		||||
```
 | 
			
		||||
This is reused in the CI/CD pipeline to automate the deployment process.
 | 
			
		||||
 | 
			
		||||
Fastlane assumes mutliple secrets to be present as files in the platform directories. These are:
 | 
			
		||||
- for android:
 | 
			
		||||
    - `secrets.properties` used by gradle to load secrets needed at execution time
 | 
			
		||||
    - `release.keystore` used by gradle to sign the apk
 | 
			
		||||
    - `google-key.json` used by fastlane to authenticate with the Google Play Store
 | 
			
		||||
- for ios:
 | 
			
		||||
    - TODO
 | 
			
		||||
Secrets used by fastlane are stored on hashicorp vault and are fetched by the CI/CD pipeline. See below.
 | 
			
		||||
 | 
			
		||||
These files are stored as secrets in the GitHub repository so that the CI pipeline can access them.
 | 
			
		||||
## Secrets
 | 
			
		||||
These are mostly used by the CI/CD pipeline to deploy the application. The main usage for github actions is documented under [https://github.com/hashicorp/vault-action](https://github.com/hashicorp/vault-action).
 | 
			
		||||
**Global secrets** are used for both versions of the app (android and ios). 
 | 
			
		||||
- `GOOGLE_MAPS_API_KEY` is used to authenticate with the Google Maps API
 | 
			
		||||
 | 
			
		||||
**Platform-specific secrets** are used by the CI/CD pipeline to deploy to the respective app stores.
 | 
			
		||||
- `ANDROID_KEYSTORE` is used to sign the android apk
 | 
			
		||||
- `ANDROID_GOOGLE_KEY` is used to authenticate with the Google Play Store api
 | 
			
		||||
- `IOS_GOOGLE_...`
 | 
			
		||||
- `IOS_GOOGLE_...`
 | 
			
		||||
- `IOS_GOOGLE_...`
 | 
			
		||||
- `IOS_GOOGLE_...`
 | 
			
		||||
@@ -63,11 +63,3 @@ Compared to the flutter template application, a few changes have to be made:
 | 
			
		||||
        }
 | 
			
		||||
    ```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Using the credentials in CI
 | 
			
		||||
- Add the secret files to the repository secrets (e.g. `ANDROID_SECRETS_PROPERTIES`).
 | 
			
		||||
 | 
			
		||||
- temporarily write them back to files during the CI execution:
 | 
			
		||||
    ```bash
 | 
			
		||||
    echo {{ secrets.ANDROID_SECRETS }} >> android/secrets.properties
 | 
			
		||||
    ```
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,7 @@
 | 
			
		||||
default_platform(:ios)
 | 
			
		||||
 | 
			
		||||
platform :ios do
 | 
			
		||||
  before_all do
 | 
			
		||||
    load_asc_api_token
 | 
			
		||||
  end
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  desc "Load the App Store Connect API token"
 | 
			
		||||
  lane :load_asc_api_token do
 | 
			
		||||
    app_store_connect_api_key(
 | 
			
		||||
@@ -16,17 +13,66 @@ platform :ios do
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  desc "Installs signing certificate in the keychain and downloads provisioning profiles from App Store Connect"
 | 
			
		||||
  lane :prepare_signing do |options|
 | 
			
		||||
    team_id = CredentialsManager::AppfileConfig.try_fetch_value(:team_id)
 | 
			
		||||
    api_key = lane_context[SharedValues::APP_STORE_CONNECT_API_KEY]
 | 
			
		||||
 | 
			
		||||
    keychain_name = "signing"
 | 
			
		||||
    keychain_password = "temp"
 | 
			
		||||
 | 
			
		||||
    delete_keychain(
 | 
			
		||||
      name: keychain_name
 | 
			
		||||
    ) if File.exist? File.expand_path("~/Library/Keychains/#{keychain_name}-db")
 | 
			
		||||
 | 
			
		||||
    create_keychain(
 | 
			
		||||
      name: keychain_name,
 | 
			
		||||
      password: keychain_password,
 | 
			
		||||
      default_keychain: true,
 | 
			
		||||
      unlock: true,
 | 
			
		||||
      timeout: 3600
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    import_certificate(
 | 
			
		||||
      certificate_path: ENV["SIGNING_KEY_FILE_PATH"],
 | 
			
		||||
      certificate_password: ENV["SIGNING_KEY_PASSWORD"],
 | 
			
		||||
      keychain_name: keychain_name,
 | 
			
		||||
      keychain_password: keychain_password
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    # fetches and installs provisioning profiles from ASC
 | 
			
		||||
    sigh(
 | 
			
		||||
      adhoc: options[:adhoc],
 | 
			
		||||
      api_key: api_key,
 | 
			
		||||
      readonly: true
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  desc "Deploy a new version to closed testing (testflight)"
 | 
			
		||||
  lane :deploy_testing do
 | 
			
		||||
    build_name = ENV["BUILD_NAME"]
 | 
			
		||||
    build_number = ENV["BUILD_NUMBER"]
 | 
			
		||||
 | 
			
		||||
    api_key = lane_context[SharedValues::APP_STORE_CONNECT_API_KEY]
 | 
			
		||||
    sync_code_signing(
 | 
			
		||||
      api_key: api_key,
 | 
			
		||||
      type: "appstore",
 | 
			
		||||
      readonly: true,
 | 
			
		||||
    app_identifier = CredentialsManager::AppfileConfig.try_fetch_value(:app_identifier)
 | 
			
		||||
    
 | 
			
		||||
    load_asc_api_token
 | 
			
		||||
    prepare_signing
 | 
			
		||||
 | 
			
		||||
    profile_name = "App Provisioning Profile" # replace with the name of the profile to use for the build
 | 
			
		||||
    output_name = "example-iOS" # specify the name of the .ipa file to generate
 | 
			
		||||
    export_method = "app-store" # specify the export method
 | 
			
		||||
    
 | 
			
		||||
    # turn off automatic signing during build so correct code signing identity is guaranteed to be used
 | 
			
		||||
    update_code_signing_settings(
 | 
			
		||||
      use_automatic_signing: false,
 | 
			
		||||
      targets: ["main-target"], # specify which targets to update code signing settings for
 | 
			
		||||
      code_sign_identity: "Apple Distribution", # replace with name of code signing identity if different
 | 
			
		||||
      bundle_identifier: app_identifier,
 | 
			
		||||
      profile_name: profile_name,
 | 
			
		||||
      build_configurations: ["Release"] # only toggle code signing settings for Release configurations
 | 
			
		||||
    )
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    sh(
 | 
			
		||||
      "flutter",
 | 
			
		||||
@@ -40,7 +86,11 @@ platform :ios do
 | 
			
		||||
    # sign the app (whithout rebuilding it)
 | 
			
		||||
    build_app(
 | 
			
		||||
      skip_build_archive: true,
 | 
			
		||||
      archive_path: "../build/ios/archive/Runner.xarchive"
 | 
			
		||||
      archive_path: "../build/ios/archive/Runner.xcarchive"
 | 
			
		||||
      provisioningProfiles: {
 | 
			
		||||
        app_identifier => profile_name
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    upload_to_testflight
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								frontend/ios/local.env.sample
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								frontend/ios/local.env.sample
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
# SAMPLE env file that replicates the env in the CI/CD pipeline
 | 
			
		||||
# DO NOT EDIT THIS FILE
 | 
			
		||||
# Copy this file to local.env and edit the values to match your local environment
 | 
			
		||||
IOS_ASC_KEY_ID="sample"
 | 
			
		||||
IOS_ASC_ISSUER_ID="sample"
 | 
			
		||||
IOS_ASC_KEY_P8="sample"
 | 
			
		||||
SIGNING_KEY_FILE_PATH="sample"
 | 
			
		||||
SIGNING_KEY_PASSWORD="sample"
 | 
			
		||||
BUILD_NAME="sample"
 | 
			
		||||
BUILD_NUMBER="sample"
 | 
			
		||||
		Reference in New Issue
	
	Block a user