Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/actions/build-setup/action.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: Copyright 2025 Opal Health Informatics Group at the Research Institute of the McGill University Health Centre <john.kildea@mcgill.ca>
# SPDX-FileCopyrightText: Copyright (C) 2025 Opal Health Informatics Group at the Research Institute of the McGill University Health Centre <john.kildea@mcgill.ca>
#
# SPDX-License-Identifier: Apache-2.0

Expand Down
37 changes: 37 additions & 0 deletions .github/actions/deploy-app-setup/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# SPDX-FileCopyrightText: Copyright (C) 2025 Opal Health Informatics Group at the Research Institute of the McGill University Health Centre <john.kildea@mcgill.ca>
#
# SPDX-License-Identifier: Apache-2.0

name: Deploy App Setup
description: Setup before deploying the mobile app to Firebase

inputs:
ENVIRONMENT:
description: 'Environment in which to deploy the app'
required: true
GOOGLE_APPLICATION_CREDENTIALS:
description: 'Contents of the service account file used to access the Firebase project for the given environment'
required: true

runs:
using: "composite"
steps:
- name: Prepare Firebase release notes
# Save release notes as a multiline string: https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#multiline-strings
run: |
{
echo 'RELEASE_NOTES<<EOF'
echo "Build created and deployed by GitHub Actions for environment '$ENVIRONMENT' on $(git log --format=medium -n 1)"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on $(git log --format=medium -n 1)

Is the intention to have the date?

If the full commit is intended maybe "on commit ...`?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The full commit is intended, so yes I can add "on commit".

echo EOF
} >> "$GITHUB_ENV"
shell: bash
env:
ENVIRONMENT: ${{ inputs.ENVIRONMENT }}

- name: Load service account used to access Firebase
run: |
echo "$GOOGLE_APPLICATION_CREDENTIALS" > service-account.txt
echo GOOGLE_APPLICATION_CREDENTIALS=service-account.txt >> "$GITHUB_ENV"
shell: bash
env:
GOOGLE_APPLICATION_CREDENTIALS: ${{ inputs.GOOGLE_APPLICATION_CREDENTIALS }}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# SPDX-FileCopyrightText: Copyright 2025 Opal Health Informatics Group at the Research Institute of the McGill University Health Centre <john.kildea@mcgill.ca>
# SPDX-FileCopyrightText: Copyright (C) 2025 Opal Health Informatics Group at the Research Institute of the McGill University Health Centre <john.kildea@mcgill.ca>
#
# SPDX-License-Identifier: Apache-2.0

# This workflow is explained in `docs/deployment/ci-cd.md`; please keep that documentation file up to date when making changes here.

name: Build App
name: Build and Deploy App
# Default to dev when running automatically (see also "env" below)
run-name: Building the app for ${{ inputs.ENVIRONMENT || 'dev' }} 📦
run-name: Building and (optionally) deploying the mobile app for ${{ inputs.ENVIRONMENT || 'dev' }} 📦🚀
on:
# When pushing to main, automatically build for dev
push:
Expand All @@ -24,10 +24,16 @@ on:
options:
- dev
- prod
DEPLOY:
description: 'Deploy the resulting mobile app'
required: true
default: true
type: boolean

# Read the target environment from workflow_dispatch inputs, or default to dev
env:
# Read the target environment from workflow_dispatch inputs, or default to dev
ENVIRONMENT: ${{ inputs.ENVIRONMENT || 'dev' }}
FIREBASE_GROUP: "general" # The name of the group to which the app is deployed (via Firebase App Distribution)

permissions:
contents: read
Expand All @@ -37,63 +43,59 @@ jobs:
runs-on: macos-latest
steps:
# Setup
- name: Convert environment to all caps
run: echo ENVIRONMENT_CAPS="$(echo "$ENVIRONMENT" | tr '[:lower:]' '[:upper:]')" >> "$GITHUB_ENV"
- name: Print environment
run: |
echo "Environment: $ENVIRONMENT ($ENVIRONMENT_CAPS)"
run: echo "Environment = $ENVIRONMENT"
- uses: actions/checkout@v4.2.2
with:
persist-credentials: false

- name: Set up build
uses: ./.github/actions/build-setup
with:
NPMRC_FILE: ${{ secrets.NPMRC_FILE }}
ENV_CONFIG_JS: ${{ vars[format('{0}_CONFIG_JS', env.ENVIRONMENT_CAPS)] }}
ENV_GOOGLE_SERVICES: ${{ vars[format('{0}_GOOGLE_SERVICES', env.ENVIRONMENT_CAPS)] }}
ENV_CONFIG_JS: ${{ vars[format('{0}_CONFIG_JS', env.ENVIRONMENT)] }}
ENV_GOOGLE_SERVICES: ${{ vars[format('{0}_GOOGLE_SERVICES', env.ENVIRONMENT)] }}

# Build the app
- name: Build the app
run: npm run build:app:android --env="$ENVIRONMENT"
- name: Rename build output
id: rename-output
id: rename-android
run: |
mv "./platforms/android/app/build/outputs/apk/debug/app-debug.apk" "opal-${ENVIRONMENT}.apk"
echo "ARTIFACT_NAME=opal-${ENVIRONMENT}.apk" >> "$GITHUB_OUTPUT"
- name: Archive build output
uses: actions/upload-artifact@v4.6.2
with:
name: Android app
path: ${{ steps.rename-output.outputs.ARTIFACT_NAME }}
name: android-app
path: ${{ steps.rename-android.outputs.ARTIFACT_NAME }}

outputs:
ARTIFACT_NAME: ${{ steps.rename-android.outputs.ARTIFACT_NAME }}


build-ios:
runs-on: macos-latest
steps:
# Setup
- name: Convert environment to all caps
run: echo ENVIRONMENT_CAPS="$(echo "$ENVIRONMENT" | tr '[:lower:]' '[:upper:]')" >> "$GITHUB_ENV"
- name: Print environment
run: |
echo "Environment: $ENVIRONMENT ($ENVIRONMENT_CAPS)"
run: echo "Environment = $ENVIRONMENT"
- uses: actions/checkout@v4.2.2
with:
persist-credentials: false

- name: Set up build
uses: ./.github/actions/build-setup
with:
NPMRC_FILE: ${{ secrets.NPMRC_FILE }}
ENV_CONFIG_JS: ${{ vars[format('{0}_CONFIG_JS', env.ENVIRONMENT_CAPS)] }}
ENV_GOOGLE_SERVICES: ${{ vars[format('{0}_GOOGLE_SERVICES', env.ENVIRONMENT_CAPS)] }}
ENV_CONFIG_JS: ${{ vars[format('{0}_CONFIG_JS', env.ENVIRONMENT)] }}
ENV_GOOGLE_SERVICES: ${{ vars[format('{0}_GOOGLE_SERVICES', env.ENVIRONMENT)] }}

# Install an Apple certificate and provisioning profile used to build the app for iOS
# See: https://docs.github.com/en/actions/use-cases-and-examples/deploying/installing-an-apple-certificate-on-macos-runners-for-xcode-development
- name: Install the Apple certificate and provisioning profile
env:
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64_FILE }}
P12_PASSWORD: ${{ secrets.BUILD_CERTIFICATE_PASSWORD }}
BUILD_PROVISION_PROFILE_BASE64: ${{ secrets[format('{0}_PROVISIONING_PROFILE_BASE64_FILE', env.ENVIRONMENT_CAPS)] }} # zizmor: ignore[overprovisioned-secrets]
BUILD_PROVISION_PROFILE_BASE64: ${{ secrets[format('{0}_PROVISIONING_PROFILE_BASE64_FILE', env.ENVIRONMENT)] }} # zizmor: ignore[overprovisioned-secrets]
KEYCHAIN_PASSWORD: ${{ secrets.TEMPORARY_KEYCHAIN_PASSWORD }}
run: |
# Create variables
Expand Down Expand Up @@ -128,14 +130,83 @@ jobs:
run: npm run build:app:ios:ci --env="$ENVIRONMENT" --devteam="$IOS_DEVELOPMENT_TEAM" --provisioningprofile="$PROVISIONING_PROFILE_UUID"
env:
IOS_DEVELOPMENT_TEAM: ${{ secrets.IOS_DEVELOPMENT_TEAM }}
PROVISIONING_PROFILE_UUID: ${{ secrets[format('{0}_PROVISIONING_PROFILE_UUID', env.ENVIRONMENT_CAPS)] }} # zizmor: ignore[overprovisioned-secrets]
PROVISIONING_PROFILE_UUID: ${{ secrets[format('{0}_PROVISIONING_PROFILE_UUID', env.ENVIRONMENT)] }} # zizmor: ignore[overprovisioned-secrets]
- name: Rename build output
id: rename-output
id: rename-ios
run: |
mv ./platforms/ios/build/Debug-iphoneos/*.ipa "opal-${ENVIRONMENT}.ipa"
echo "ARTIFACT_NAME=opal-${ENVIRONMENT}.ipa" >> "$GITHUB_OUTPUT"
- name: Archive build output
uses: actions/upload-artifact@v4.6.2
with:
name: iOS app
path: ${{ steps.rename-output.outputs.ARTIFACT_NAME }}
name: ios-app
path: ${{ steps.rename-ios.outputs.ARTIFACT_NAME }}

outputs:
ARTIFACT_NAME: ${{ steps.rename-ios.outputs.ARTIFACT_NAME }}


deploy-android:
needs: build-android
runs-on: ubuntu-latest
# Deploy manually via inputs, or automatically (to dev) when building on main
if: ${{ inputs.DEPLOY || github.ref == 'refs/heads/main' }}
steps:
# Setup
- uses: actions/checkout@v4.2.2
with:
persist-credentials: false
- name: Download Android build artifact
uses: actions/download-artifact@v4.3.0
with:
name: android-app
run-id: ${{ github.run_id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Set up deployment
uses: ./.github/actions/deploy-app-setup
with:
ENVIRONMENT: ${{ env.ENVIRONMENT }}
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets[format('{0}_FIREBASE_SERVICE_ACCOUNT', env.ENVIRONMENT)] }} # zizmor: ignore[overprovisioned-secrets]

# Deploy the app
# Deployment via firebase-tools implicitly uses a service account assigned to $GOOGLE_APPLICATION_CREDENTIALS (from values defined in the GitHub project settings)
# This service account provides permissions for Firebase app distribution
# See: https://firebase.google.com/docs/admin/setup#initialize_the_sdk_in_non-google_environments
- name: Deploy the app
run: npx firebase-tools appdistribution:distribute "$ARTIFACT_NAME" --app "$FIREBASE_APP_ANDROID" --release-notes "$RELEASE_NOTES" --groups "$FIREBASE_GROUP"
env:
ARTIFACT_NAME: ${{ needs.build-android.outputs.ARTIFACT_NAME }}
FIREBASE_APP_ANDROID: ${{ vars[format('{0}_FIREBASE_APP_ANDROID', env.ENVIRONMENT)] }}
FIREBASE_GROUP: ${{ env.FIREBASE_GROUP }}


deploy-ios:
needs: build-ios
runs-on: ubuntu-latest
# Deploy manually via inputs, or automatically (to dev) when building on main
if: ${{ inputs.DEPLOY || github.ref == 'refs/heads/main' }}
steps:
# Setup
- uses: actions/checkout@v4.2.2
with:
persist-credentials: false
- name: Download iOS build artifact
uses: actions/download-artifact@v4.3.0
with:
name: ios-app
run-id: ${{ github.run_id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Set up deployment
uses: ./.github/actions/deploy-app-setup
with:
ENVIRONMENT: ${{ env.ENVIRONMENT }}
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets[format('{0}_FIREBASE_SERVICE_ACCOUNT', env.ENVIRONMENT)] }} # zizmor: ignore[overprovisioned-secrets]

# Deploy the app
# Deployment implicitly uses $GOOGLE_APPLICATION_CREDENTIALS; see deploy-android above for more details
- name: Deploy the app
run: npx firebase-tools appdistribution:distribute "$ARTIFACT_NAME" --app "$FIREBASE_APP_IOS" --release-notes "$RELEASE_NOTES" --groups "$FIREBASE_GROUP"
env:
ARTIFACT_NAME: ${{ needs.build-ios.outputs.ARTIFACT_NAME }}
FIREBASE_APP_IOS: ${{ vars[format('{0}_FIREBASE_APP_IOS', env.ENVIRONMENT)] }}
FIREBASE_GROUP: ${{ env.FIREBASE_GROUP }}
4 changes: 2 additions & 2 deletions .github/workflows/build-web.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: Copyright 2025 Opal Health Informatics Group at the Research Institute of the McGill University Health Centre <john.kildea@mcgill.ca>
# SPDX-FileCopyrightText: Copyright (C) 2025 Opal Health Informatics Group at the Research Institute of the McGill University Health Centre <john.kildea@mcgill.ca>
#
# SPDX-License-Identifier: Apache-2.0

Expand Down Expand Up @@ -79,7 +79,7 @@ jobs:
outputs:
ENVIRONMENT: ${{ env.ENVIRONMENT }}

# Call another workflow if applicable to deploy the app
# Call another workflow if applicable to deploy the web app
deploy-web:
needs: build-web
# Deploy manually via inputs, or automatically (to dev) when building on main
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: Copyright 2025 Opal Health Informatics Group at the Research Institute of the McGill University Health Centre <john.kildea@mcgill.ca>
# SPDX-FileCopyrightText: Copyright (C) 2025 Opal Health Informatics Group at the Research Institute of the McGill University Health Centre <john.kildea@mcgill.ca>
#
# SPDX-License-Identifier: Apache-2.0

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/deploy-web.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: Copyright 2025 Opal Health Informatics Group at the Research Institute of the McGill University Health Centre <john.kildea@mcgill.ca>
# SPDX-FileCopyrightText: Copyright (C) 2025 Opal Health Informatics Group at the Research Institute of the McGill University Health Centre <john.kildea@mcgill.ca>
#
# SPDX-License-Identifier: Apache-2.0

Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: Copyright 2025 Opal Health Informatics Group at the Research Institute of the McGill University Health Centre <john.kildea@mcgill.ca>
# SPDX-FileCopyrightText: Copyright (C) 2025 Opal Health Informatics Group at the Research Institute of the McGill University Health Centre <john.kildea@mcgill.ca>
#
# SPDX-License-Identifier: Apache-2.0

Expand Down
2 changes: 1 addition & 1 deletion .typos.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: Copyright 2025 Opal Health Informatics Group at the Research Institute of the McGill University Health Centre <john.kildea@mcgill.ca>
# SPDX-FileCopyrightText: Copyright (C) 2025 Opal Health Informatics Group at the Research Institute of the McGill University Health Centre <john.kildea@mcgill.ca>
#
# SPDX-License-Identifier: Apache-2.0

Expand Down