PM-5154 Implement iOS passkey add login #6274
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
name: Build | |
on: | |
push: | |
branches-ignore: | |
- "l10n_master" | |
- "gh-pages" | |
paths-ignore: | |
- ".github/workflows/**" | |
workflow_dispatch: | |
env: | |
main_app_folder_path: src/App | |
main_app_project_path: src/App/App.csproj | |
target-net-version: net8.0 | |
jobs: | |
cloc: | |
name: CLOC | |
runs-on: ubuntu-22.04 | |
steps: | |
- name: Checkout repo | |
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 | |
- name: Set up CLOC | |
run: | | |
sudo apt-get update | |
sudo apt-get -y install cloc | |
- name: Print lines of code | |
run: cloc --vcs git --exclude-dir Resources,store,test,Properties --include-lang C#,XAML | |
setup: | |
name: Setup | |
runs-on: ubuntu-22.04 | |
outputs: | |
rc_branch_exists: ${{ steps.branch-check.outputs.rc_branch_exists }} | |
hotfix_branch_exists: ${{ steps.branch-check.outputs.hotfix_branch_exists }} | |
steps: | |
- name: Checkout repo | |
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 | |
with: | |
submodules: 'true' | |
- name: Check if special branches exist | |
id: branch-check | |
run: | | |
if [[ $(git ls-remote --heads origin rc) ]]; then | |
echo "rc_branch_exists=1" >> $GITHUB_OUTPUT | |
else | |
echo "rc_branch_exists=0" >> $GITHUB_OUTPUT | |
fi | |
if [[ $(git ls-remote --heads origin hotfix-rc) ]]; then | |
echo "hotfix_branch_exists=1" >> $GITHUB_OUTPUT | |
else | |
echo "hotfix_branch_exists=0" >> $GITHUB_OUTPUT | |
fi | |
android: | |
name: Android | |
runs-on: windows-2022 | |
needs: setup | |
strategy: | |
fail-fast: false | |
matrix: | |
variant: ["prod", "qa"] | |
env: | |
android_folder_path: src/App/Platforms/Android | |
steps: | |
- name: Setup NuGet | |
uses: nuget/setup-nuget@296fd3ccf8528660c91106efefe2364482f86d6f # v1.2.0 | |
with: | |
nuget-version: 6.4.0 | |
- name: Set up .NET | |
uses: actions/setup-dotnet@4d6c8fcf3c8f7a60068d26b594648e99df24cee3 # v4.0.0 | |
with: | |
dotnet-version: '8.0.x' | |
- name: Set up MSBuild | |
uses: microsoft/setup-msbuild@ede762b26a2de8d110bb5a3db4d7e0e080c0e917 # v1.3.3 | |
# This step might be obsolete at some point as .NET MAUI workloads | |
# are starting to come pre-installed on the GH Actions build agents. | |
- name: Install MAUI Workload | |
run: dotnet workload install maui --ignore-failed-sources | |
- name: Setup Windows builder | |
run: choco install checksum --no-progress | |
- name: Install Microsoft OpenJDK 11 | |
run: | | |
choco install microsoft-openjdk11 --no-progress | |
Write-Output "JAVA_HOME=$(Get-ChildItem -Path 'C:\Program Files\Microsoft\jdk*' | Select -First 1 -ExpandProperty FullName)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append | |
Write-Output "Java Home: $env:JAVA_HOME" | |
- name: Print environment | |
run: | | |
nuget help | grep Version | |
msbuild -version | |
dotnet --info | |
echo "GitHub ref: $GITHUB_REF" | |
echo "GitHub event: $GITHUB_EVENT" | |
- name: Checkout repo | |
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 | |
with: | |
fetch-depth: 0 | |
- name: Decrypt secrets | |
env: | |
DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }} | |
run: | | |
mkdir -p ~/secrets | |
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ | |
--output ./${{ env.main_app_folder_path }}/app_play-keystore.jks ./.github/secrets/app_play-keystore.jks.gpg | |
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ | |
--output ./${{ env.main_app_folder_path }}/app_upload-keystore.jks ./.github/secrets/app_upload-keystore.jks.gpg | |
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ | |
--output $HOME/secrets/play_creds.json ./.github/secrets/play_creds.json.gpg | |
shell: bash | |
- name: Decrypt secrets - Google Services | |
if: ${{ matrix.variant == 'prod' }} | |
env: | |
DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }} | |
run: | | |
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ | |
--output ./${{ env.android_folder_path }}/google-services.json ./.github/secrets/google-services.json.gpg | |
shell: bash | |
- name: Increment version | |
run: | | |
BUILD_NUMBER=$((3000 + $GITHUB_RUN_NUMBER)) | |
echo "########################################" | |
echo "##### Setting Version Code $BUILD_NUMBER" | |
echo "########################################" | |
sed -i "s/android:versionCode=\"1\"/android:versionCode=\"$BUILD_NUMBER\"/" \ | |
./${{ env.android_folder_path }}/AndroidManifest.xml | |
shell: bash | |
- name: Restore packages | |
run: nuget restore | |
- name: Restore tools | |
run: dotnet tool restore | |
# - name: Verify Format | |
# run: dotnet tool run dotnet-format --check | |
- name: Run Core tests | |
run: dotnet test test/Core.Test/Core.Test.csproj --logger "trx;LogFileName=test-results.trx" /p:CustomConstants=UT | |
- name: Report test results | |
uses: dorny/test-reporter@eaa763f6ffc21c7a37837f56cd5f9737f27fc6c8 # v1.8.0 | |
if: always() | |
with: | |
name: Test Results | |
path: "**/test-results.trx" | |
reporter: dotnet-trx | |
fail-on-error: true | |
- name: Build Play Store publisher | |
if: ${{ matrix.variant == 'prod' }} | |
run: dotnet build ./store/google/Publisher/Publisher.csproj -p:Configuration=Release | |
- name: Setup Android build (${{ matrix.variant }}) | |
run: dotnet cake build.cake --target Android --variant ${{ matrix.variant }} | |
- name: Build Android | |
run: | | |
$configuration = "Release"; | |
$projToBuild = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_project_path }}"); | |
Write-Output "########################################" | |
Write-Output "##### Build $configuration Configuration" | |
Write-Output "########################################" | |
dotnet build $projToBuild -c $configuration -f ${{ env.target-net-version }}-android | |
- name: Sign Android Build | |
env: | |
PLAY_KEYSTORE_PASSWORD: ${{ secrets.PLAY_KEYSTORE_PASSWORD }} | |
UPLOAD_KEYSTORE_PASSWORD: ${{ secrets.UPLOAD_KEYSTORE_PASSWORD }} | |
run: | | |
$projToBuild = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_project_path }}"); | |
$packageName = "com.x8bit.bitwarden"; | |
if ("${{ matrix.variant }}" -ne "prod") | |
{ | |
$packageName = "com.x8bit.bitwarden.${{ matrix.variant }}"; | |
} | |
Write-Output "########################################" | |
Write-Output "##### Sign Google Play Bundle Release Configuration" | |
Write-Output "########################################" | |
dotnet publish $projToBuild -c Release -f ${{ env.target-net-version }}-android /p:AndroidPackageFormats=aab /p:AndroidKeyStore=true /p:AndroidSigningKeyStore=$("app_upload-keystore.jks") /p:AndroidSigningKeyAlias=upload /p:AndroidSigningKeyPass="$($env:UPLOAD_KEYSTORE_PASSWORD)" /p:AndroidSigningStorePass="$($env:UPLOAD_KEYSTORE_PASSWORD)" --no-restore | |
Write-Output "########################################" | |
Write-Output "##### Copy Google Play Bundle to project root" | |
Write-Output "########################################" | |
$signedAabPath = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_folder_path }}/bin/Release/${{ env.target-net-version }}-android/publish/$($packageName)-Signed.aab"); | |
$signedAabDestPath = $($env:GITHUB_WORKSPACE + "/$($packageName).aab"); | |
Copy-Item $signedAabPath $signedAabDestPath | |
Write-Output "########################################" | |
Write-Output "##### Sign APK Release Configuration" | |
Write-Output "########################################" | |
dotnet publish $projToBuild -c Release -f ${{ env.target-net-version }}-android /p:AndroidKeyStore=true /p:AndroidSigningKeyStore=$("app_play-keystore.jks") /p:AndroidSigningKeyAlias=bitwarden /p:AndroidSigningKeyPass="$($env:PLAY_KEYSTORE_PASSWORD)" /p:AndroidSigningStorePass="$($env:PLAY_KEYSTORE_PASSWORD)" --no-restore | |
Write-Output "########################################" | |
Write-Output "##### Copy Release APK to project root" | |
Write-Output "########################################" | |
$signedApkPath = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_folder_path }}/bin/Release/${{ env.target-net-version }}-android/publish/$($packageName)-Signed.apk"); | |
$signedApkDestPath = $($env:GITHUB_WORKSPACE + "/$($packageName).apk"); | |
Copy-Item $signedApkPath $signedApkDestPath | |
- name: Upload Prod .aab artifact | |
if: ${{ matrix.variant == 'prod' }} | |
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 | |
with: | |
name: com.x8bit.bitwarden.aab | |
path: ./com.x8bit.bitwarden.aab | |
if-no-files-found: error | |
- name: Upload Prod .apk artifact | |
if: ${{ matrix.variant == 'prod' }} | |
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 | |
with: | |
name: com.x8bit.bitwarden.apk | |
path: ./com.x8bit.bitwarden.apk | |
if-no-files-found: error | |
- name: Upload Other .apk artifact | |
if: ${{ matrix.variant != 'prod' }} | |
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 | |
with: | |
name: com.x8bit.bitwarden.${{ matrix.variant }}.apk | |
path: ./com.x8bit.bitwarden.${{ matrix.variant }}.apk | |
if-no-files-found: error | |
- name: Create checksum for Prod .apk artifact | |
if: ${{ matrix.variant == 'prod' }} | |
run: | | |
checksum -f="./com.x8bit.bitwarden.apk" ` | |
-t sha256 | Out-File -Encoding ASCII ./bw-android-apk-sha256.txt | |
- name: Create checksum for Other .apk artifact | |
if: ${{ matrix.variant != 'prod' }} | |
run: | | |
checksum -f="./com.x8bit.bitwarden.${{ matrix.variant }}.apk" ` | |
-t sha256 | Out-File -Encoding ASCII ./bw-android-${{ matrix.variant }}-apk-sha256.txt | |
- name: Upload .apk sha file for prod | |
if: ${{ matrix.variant == 'prod' }} | |
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 | |
with: | |
name: bw-android-apk-sha256.txt | |
path: ./bw-android-apk-sha256.txt | |
if-no-files-found: error | |
- name: Upload .apk sha file for other | |
if: ${{ matrix.variant != 'prod' }} | |
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 | |
with: | |
name: bw-android-${{ matrix.variant }}-apk-sha256.txt | |
path: ./bw-android-${{ matrix.variant }}-apk-sha256.txt | |
if-no-files-found: error | |
- name: Deploy to Play Store | |
if: ${{ matrix.variant == 'prod' && (( github.ref == 'refs/heads/main' | |
&& needs.setup.outputs.rc_branch_exists == 0 | |
&& needs.setup.outputs.hotfix_branch_exists == 0) | |
|| (github.ref == 'refs/heads/rc' && needs.setup.outputs.hotfix_branch_exists == 0) | |
|| github.ref == 'refs/heads/hotfix-rc' ) }} | |
run: | | |
PUBLISHER_PATH="$GITHUB_WORKSPACE/store/google/Publisher/bin/Release/net7.0/Publisher.dll" | |
CREDS_PATH="$HOME/secrets/play_creds.json" | |
AAB_PATH="$GITHUB_WORKSPACE/com.x8bit.bitwarden.aab" | |
TRACK="internal" | |
dotnet $PUBLISHER_PATH $CREDS_PATH $AAB_PATH $TRACK | |
shell: bash | |
f-droid: | |
name: F-Droid Build | |
runs-on: windows-2022 | |
env: | |
android_folder_path: src/App/Platforms/Android | |
android_manifest_path: src/App/Platforms/Android/AndroidManifest.xml | |
steps: | |
- name: Setup NuGet | |
uses: nuget/setup-nuget@296fd3ccf8528660c91106efefe2364482f86d6f # v1.2.0 | |
with: | |
nuget-version: 6.4.0 | |
- name: Set up .NET | |
uses: actions/setup-dotnet@3447fd6a9f9e57506b15f895c5b76d3b197dc7c2 # v3.2.0 | |
with: | |
dotnet-version: '8.0.x' | |
- name: Set up MSBuild | |
uses: microsoft/setup-msbuild@ede762b26a2de8d110bb5a3db4d7e0e080c0e917 # v1.3.3 | |
# This step might be obsolete at some point as .NET MAUI workloads | |
# are starting to come pre-installed on the GH Actions build agents. | |
- name: Install MAUI Workload | |
run: dotnet workload install maui --ignore-failed-sources | |
- name: Setup Windows builder | |
run: choco install checksum --no-progress | |
- name: Install Microsoft OpenJDK 11 | |
run: | | |
choco install microsoft-openjdk11 --no-progress | |
Write-Output "JAVA_HOME=$(Get-ChildItem -Path 'C:\Program Files\Microsoft\jdk*' | Select -First 1 -ExpandProperty FullName)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append | |
Write-Output "Java Home: $env:JAVA_HOME" | |
- name: Print environment | |
run: | | |
nuget help | grep Version | |
msbuild -version | |
dotnet --info | |
echo "GitHub ref: $GITHUB_REF" | |
echo "GitHub event: $GITHUB_EVENT" | |
- name: Checkout repo | |
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 | |
- name: Decrypt secrets | |
env: | |
DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }} | |
run: | | |
mkdir -p ~/secrets | |
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ | |
--output ./${{ env.main_app_folder_path }}/app_fdroid-keystore.jks ./.github/secrets/app_fdroid-keystore.jks.gpg | |
shell: bash | |
- name: Increment version | |
run: | | |
BUILD_NUMBER=$((3000 + $GITHUB_RUN_NUMBER)) | |
echo "########################################" | |
echo "##### Setting Version Code $BUILD_NUMBER" | |
echo "########################################" | |
sed -i "s/android:versionCode=\"1\"/android:versionCode=\"$BUILD_NUMBER\"/" \ | |
./${{ env.android_manifest_path }} | |
shell: bash | |
- name: Clean for F-Droid | |
run: | | |
$appPath = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_project_path }}"); | |
$corePath = $($env:GITHUB_WORKSPACE + "/src/Core/Core.csproj"); | |
$androidManifest = $($env:GITHUB_WORKSPACE + "/${{ env.android_manifest_path }}"); | |
Write-Output "########################################" | |
Write-Output "##### Backup project files" | |
Write-Output "########################################" | |
Copy-Item $androidManifest $($androidManifest + ".original"); | |
Copy-Item $appPath $($appPath + ".original"); | |
Write-Output "########################################" | |
Write-Output "##### Cleanup Android Manifest" | |
Write-Output "########################################" | |
$xml=New-Object XML; | |
$xml.Load($androidManifest); | |
$nsAndroid=New-Object System.Xml.XmlNamespaceManager($xml.NameTable); | |
$nsAndroid.AddNamespace("android", "http://schemas.android.com/apk/res/android"); | |
$xml.Save($androidManifest); | |
- name: Restore packages | |
run: dotnet restore | |
- name: Build for F-Droid | |
run: | | |
$configuration = "Release"; | |
$projToBuild = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_project_path }}"); | |
Write-Output "########################################" | |
Write-Output "##### Build $configuration FDROID | |
Write-Output "########################################" | |
dotnet build $projToBuild -c $configuration -f ${{ env.target-net-version }}-android /p:CustomConstants="FDROID" | |
- name: Sign for F-Droid | |
env: | |
FDROID_KEYSTORE_PASSWORD: ${{ secrets.FDROID_KEYSTORE_PASSWORD }} | |
run: | | |
$projToBuild = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_project_path }}"); | |
$packageName = "com.x8bit.bitwarden"; | |
Write-Output "########################################" | |
Write-Output "##### Sign FDroid" | |
Write-Output "########################################" | |
dotnet publish $projToBuild -c Release -f ${{ env.target-net-version }}-android /p:AndroidKeyStore=true /p:AndroidSigningKeyStore=$("app_fdroid-keystore.jks") /p:AndroidSigningKeyAlias=bitwarden /p:AndroidSigningKeyPass="$($env:FDROID_KEYSTORE_PASSWORD)" /p:AndroidSigningStorePass="$($env:FDROID_KEYSTORE_PASSWORD)" /p:CustomConstants="FDROID" --no-restore | |
Write-Output "########################################" | |
Write-Output "##### Copy FDroid apk to project root" | |
Write-Output "########################################" | |
$signedApkPath = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_folder_path }}/bin/Release/${{ env.target-net-version }}-android/publish/$($packageName)-Signed.apk"); | |
$signedApkDestPath = $($env:GITHUB_WORKSPACE + "/com.x8bit.bitwarden-fdroid.apk"); | |
Copy-Item $signedApkPath $signedApkDestPath | |
- name: Upload F-Droid .apk artifact | |
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 | |
with: | |
name: com.x8bit.bitwarden-fdroid.apk | |
path: ./com.x8bit.bitwarden-fdroid.apk | |
if-no-files-found: error | |
- name: Create checksum for F-Droid artifact | |
run: | | |
checksum -f="./com.x8bit.bitwarden-fdroid.apk" ` | |
-t sha256 | Out-File -Encoding ASCII ./bw-fdroid-apk-sha256.txt | |
- name: Upload F-Droid sha file | |
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 | |
with: | |
name: bw-fdroid-apk-sha256.txt | |
path: ./bw-fdroid-apk-sha256.txt | |
if-no-files-found: error | |
ios: | |
name: Apple iOS | |
runs-on: macos-13 | |
needs: setup | |
env: | |
ios_folder_path: src/App/Platforms/iOS | |
app_output_name: App | |
app_ci_output_filename: App_x64_Debug | |
steps: | |
- name: Set XCode version | |
uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0 | |
with: | |
xcode-version: 15.1 | |
- name: Setup NuGet | |
uses: nuget/setup-nuget@296fd3ccf8528660c91106efefe2364482f86d6f # v1.2.0 | |
with: | |
nuget-version: 6.4.0 | |
- name: Set up .NET | |
uses: actions/setup-dotnet@3447fd6a9f9e57506b15f895c5b76d3b197dc7c2 # v3.2.0 | |
with: | |
dotnet-version: '8.0.x' | |
# This step might be obsolete at some point as .NET MAUI workloads | |
# are starting to come pre-installed on the GH Actions build agents. | |
- name: Install MAUI Workload | |
run: dotnet workload install maui --ignore-failed-sources | |
- name: Print environment | |
run: | | |
nuget help | grep Version | |
dotnet --info | |
echo "GitHub ref: $GITHUB_REF" | |
echo "GitHub event: $GITHUB_EVENT" | |
- name: Checkout repo | |
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 | |
with: | |
submodules: 'true' | |
- name: Login to Azure - CI Subscription | |
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 | |
with: | |
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} | |
- name: Retrieve secrets | |
id: retrieve-secrets | |
uses: bitwarden/gh-actions/get-keyvault-secrets@main | |
with: | |
keyvault: "bitwarden-ci" | |
secrets: "appcenter-ios-token" | |
- name: Decrypt secrets | |
env: | |
DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }} | |
run: | | |
mkdir -p ~/secrets | |
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ | |
--output $HOME/secrets/bitwarden-mobile-key.p12 ./.github/secrets/bitwarden-mobile-key.p12.gpg | |
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ | |
--output $HOME/secrets/iphone-distribution-cert.p12 ./.github/secrets/iphone-distribution-cert.p12.gpg | |
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ | |
--output $HOME/secrets/dist_autofill.mobileprovision ./.github/secrets/dist_autofill.mobileprovision.gpg | |
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ | |
--output $HOME/secrets/dist_bitwarden.mobileprovision ./.github/secrets/dist_bitwarden.mobileprovision.gpg | |
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ | |
--output $HOME/secrets/dist_extension.mobileprovision ./.github/secrets/dist_extension.mobileprovision.gpg | |
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ | |
--output $HOME/secrets/dist_share_extension.mobileprovision \ | |
./.github/secrets/dist_share_extension.mobileprovision.gpg | |
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ | |
--output $HOME/secrets/dist_watch_app.mobileprovision \ | |
./.github/secrets/dist_watch_app.mobileprovision.gpg | |
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ | |
--output $HOME/secrets/dist_watch_app_extension.mobileprovision \ | |
./.github/secrets/dist_watch_app_extension.mobileprovision.gpg | |
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \ | |
--output ./src/watchOS/bitwarden/GoogleService-Info.plist ./.github/secrets/GoogleService-Info.plist.gpg | |
- name: Increment version | |
run: | | |
BUILD_NUMBER=$((100 + $GITHUB_RUN_NUMBER)) | |
echo "########################################" | |
echo "##### Setting CFBundleVersion $BUILD_NUMBER" | |
echo "########################################" | |
echo "### CFBundleVersion $BUILD_NUMBER" >> $GITHUB_STEP_SUMMARY | |
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./${{ env.ios_folder_path }}/Info.plist | |
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.Extension/Info.plist | |
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.Autofill/Info.plist | |
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.ShareExtension/Info.plist | |
cd src/watchOS/bitwarden | |
agvtool new-version -all $BUILD_NUMBER | |
- name: Update Entitlements | |
run: | | |
echo "########################################" | |
echo "##### Updating Entitlements" | |
echo "########################################" | |
perl -0777 -pi.bak -e 's/<key>aps-environment<\/key>\s*<string>development<\/string>/<key>aps-environment<\/key>\n\t<string>production<\/string>/' ./${{ env.ios_folder_path }}/Entitlements.plist | |
- name: Set up Keychain | |
env: | |
KEYCHAIN_PASSWORD: ${{ secrets.IOS_KEYCHAIN_PASSWORD }} | |
MOBILE_KEY_PASSWORD: ${{ secrets.IOS_KEY_PASSWORD }} | |
DIST_CERT_PASSWORD: ${{ secrets.IOS_DIST_CERT_PASSWORD }} | |
run: | | |
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 -lut 1200 build.keychain | |
security import ~/secrets/bitwarden-mobile-key.p12 -k build.keychain -P $MOBILE_KEY_PASSWORD \ | |
-T /usr/bin/codesign -T /usr/bin/security | |
security import ~/secrets/iphone-distribution-cert.p12 -k build.keychain -P $DIST_CERT_PASSWORD \ | |
-T /usr/bin/codesign -T /usr/bin/security | |
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $KEYCHAIN_PASSWORD build.keychain | |
- name: Set up provisioning profiles | |
run: | | |
AUTOFILL_PROFILE_PATH=$HOME/secrets/dist_autofill.mobileprovision | |
BITWARDEN_PROFILE_PATH=$HOME/secrets/dist_bitwarden.mobileprovision | |
EXTENSION_PROFILE_PATH=$HOME/secrets/dist_extension.mobileprovision | |
SHARE_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_share_extension.mobileprovision | |
WATCH_APP_PROFILE_PATH=$HOME/secrets/dist_watch_app.mobileprovision | |
WATCH_APP_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_watch_app_extension.mobileprovision | |
PROFILES_DIR_PATH=$HOME/Library/MobileDevice/Provisioning\ Profiles | |
mkdir -p "$PROFILES_DIR_PATH" | |
AUTOFILL_UUID=$(grep UUID -A1 -a $AUTOFILL_PROFILE_PATH | grep -io "[-A-F0-9]\{36\}") | |
cp $AUTOFILL_PROFILE_PATH "$PROFILES_DIR_PATH/$AUTOFILL_UUID.mobileprovision" | |
BITWARDEN_UUID=$(grep UUID -A1 -a $BITWARDEN_PROFILE_PATH | grep -io "[-A-F0-9]\{36\}") | |
cp $BITWARDEN_PROFILE_PATH "$PROFILES_DIR_PATH/$BITWARDEN_UUID.mobileprovision" | |
EXTENSION_UUID=$(grep UUID -A1 -a $EXTENSION_PROFILE_PATH | grep -io "[-A-F0-9]\{36\}") | |
cp $EXTENSION_PROFILE_PATH "$PROFILES_DIR_PATH/$EXTENSION_UUID.mobileprovision" | |
SHARE_EXTENSION_UUID=$(grep UUID -A1 -a $SHARE_EXTENSION_PROFILE_PATH | grep -io "[-A-F0-9]\{36\}") | |
cp $SHARE_EXTENSION_PROFILE_PATH "$PROFILES_DIR_PATH/$SHARE_EXTENSION_UUID.mobileprovision" | |
WATCH_APP_UUID=$(grep UUID -A1 -a $WATCH_APP_PROFILE_PATH | grep -io "[-A-F0-9]\{36\}") | |
cp $WATCH_APP_PROFILE_PATH "$PROFILES_DIR_PATH/$WATCH_APP_UUID.mobileprovision" | |
WATCH_APP_EXTENSION_UUID=$(grep UUID -A1 -a $WATCH_APP_EXTENSION_PROFILE_PATH | grep -io "[-A-F0-9]\{36\}") | |
cp $WATCH_APP_EXTENSION_PROFILE_PATH "$PROFILES_DIR_PATH/$WATCH_APP_EXTENSION_UUID.mobileprovision" | |
- name: Restore packages | |
run: dotnet restore | |
- name: Bulid WatchApp | |
run: | | |
echo "########################################" | |
echo "##### Build WatchApp with Release Configuration" | |
echo "########################################" | |
xcodebuild archive -workspace ./src/watchOS/bitwarden/bitwarden.xcodeproj/project.xcworkspace -configuration Release -scheme bitwarden\ WatchKit\ App -archivePath ./src/watchOS/bitwarden | |
echo "########################################" | |
echo "##### Done" | |
echo "########################################" | |
- name: Archive Build for App Store | |
run: | | |
Write-Output "########################################" | |
Write-Output "##### Archive for Release ios-arm64 | |
Write-Output "########################################" | |
dotnet publish ${{ env.main_app_project_path }} -c Release -f ${{ env.target-net-version }}-ios /p:RuntimeIdentifier=ios-arm64 /p:ArchiveOnBuild=true /p:MtouchUseLlvm=false | |
Write-Output "########################################" | |
Write-Output "##### Done" | |
Write-Output "########################################" | |
shell: pwsh | |
- name: Archive Build for Mobile Automation | |
run: | | |
Write-Output "########################################" | |
Write-Output "##### Archive Debug for iossimulator-x64 | |
Write-Output "########################################" | |
dotnet build ${{ env.main_app_project_path }} -c Debug -f ${{ env.target-net-version }}-ios /p:RuntimeIdentifier=iossimulator-x64 /p:ArchiveOnBuild=true /p:MtouchUseLlvm=false | |
Write-Output "########################################" | |
Write-Output "##### Done" | |
Write-Output "########################################" | |
ls ~/Library/Developer/Xcode/Archives | |
shell: pwsh | |
- name: Export .ipa for App Store | |
run: | | |
EXPORT_OPTIONS_PATH="./.github/resources/export-options-app-store.plist" | |
ARCHIVE_PATH="$HOME/Library/Developer/Xcode/Archives/*/*.xcarchive" | |
EXPORT_PATH="./bitwarden-export" | |
xcodebuild -exportArchive -archivePath $ARCHIVE_PATH -exportPath $EXPORT_PATH \ | |
-exportOptionsPlist $EXPORT_OPTIONS_PATH | |
- name: Export .app for Automation CI | |
run: | | |
ARCHIVE_PATH="./${{ env.main_app_folder_path }}/bin/Debug/${{ env.target-net-version }}-ios/iossimulator-x64" | |
EXPORT_PATH="./bitwarden-export" | |
zip -r -q ${{ env.app_ci_output_filename }}.app.zip $ARCHIVE_PATH | |
mv ${{ env.app_ci_output_filename }}.app.zip $EXPORT_PATH | |
- name: Copy all dSYMs files to upload | |
run: | | |
ARCHIVE_DSYMS_PATH="$HOME/Library/Developer/Xcode/Archives/*/*.xcarchive/dSYMs" | |
EXPORT_PATH="./bitwarden-export" | |
WATCH_ARCHIVE_DSYMS_PATH="./src/watchOS/bitwarden.xcarchive/dSYMs/" | |
WATCH_DSYMS_EXPORT_PATH="$EXPORT_PATH/Watch_dSYMs" | |
cp -r -v $ARCHIVE_DSYMS_PATH $EXPORT_PATH | |
mkdir $WATCH_DSYMS_EXPORT_PATH | |
cp -r -v $WATCH_ARCHIVE_DSYMS_PATH $WATCH_DSYMS_EXPORT_PATH | |
- name: Upload App Store .ipa & dSYMs artifacts | |
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 | |
with: | |
name: Bitwarden iOS | |
path: | | |
./bitwarden-export/Bitwarden.ipa | |
./bitwarden-export/dSYMs/*.* | |
if-no-files-found: error | |
- name: Upload .app file for Automation CI | |
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 | |
with: | |
name: ${{ env.app_ci_output_filename }}.app.zip | |
path: ./bitwarden-export/${{ env.app_ci_output_filename }}.app.zip | |
if-no-files-found: error | |
- name: Install AppCenter CLI | |
if: | | |
(github.ref == 'refs/heads/main' | |
&& needs.setup.outputs.rc_branch_exists == 0 | |
&& needs.setup.outputs.hotfix_branch_exists == 0) | |
|| (github.ref == 'refs/heads/rc' && needs.setup.outputs.hotfix_branch_exists == 0) | |
|| github.ref == 'refs/heads/hotfix-rc' | |
run: npm install -g appcenter-cli | |
- name: Upload dSYMs to App Center | |
if: | | |
(github.ref == 'refs/heads/main' | |
&& needs.setup.outputs.rc_branch_exists == 0 | |
&& needs.setup.outputs.hotfix_branch_exists == 0) | |
|| (github.ref == 'refs/heads/rc' && needs.setup.outputs.hotfix_branch_exists == 0) | |
|| github.ref == 'refs/heads/hotfix-rc' | |
env: | |
APPCENTER_IOS_TOKEN: ${{ steps.retrieve-secrets.outputs.appcenter-ios-token }} | |
run: appcenter crashes upload-symbols -a bitwarden/bitwarden -s "./bitwarden-export/dSYMs" --token $APPCENTER_IOS_TOKEN | |
- name: Upload Watch dSYMs to Firebase Crashlytics | |
if: | | |
(github.ref == 'refs/heads/main' | |
&& needs.setup.outputs.rc_branch_exists == 0 | |
&& needs.setup.outputs.hotfix_branch_exists == 0) | |
|| (github.ref == 'refs/heads/rc' && needs.setup.outputs.hotfix_branch_exists == 0) | |
|| github.ref == 'refs/heads/hotfix-rc' | |
run: | | |
echo "########################################" | |
echo "##### Uploading Watch dSYMs to Firebase" | |
echo "########################################" | |
find "$HOME/Library/Developer/XCode/DerivedData" -name "upload-symbols" -exec chmod +x {} \; -exec {} -gsp "./src/watchOS/bitwarden/GoogleService-Info.plist" -p ios "./bitwarden-export/Watch_dSYMs" \; | |
- name: Validate app in App Store | |
if: | | |
(github.ref == 'refs/heads/master' | |
&& needs.setup.outputs.rc_branch_exists == 0 | |
&& needs.setup.outputs.hotfix_branch_exists == 0) | |
|| (github.ref == 'refs/heads/rc' && needs.setup.outputs.hotfix_branch_exists == 0) | |
|| github.ref == 'refs/heads/hotfix-rc' | |
env: | |
APPLE_ID_USERNAME: ${{ secrets.APPLE_ID_USERNAME }} | |
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} | |
run: | | |
xcrun altool --validate-app --type ios --file "./bitwarden-export/Bitwarden.ipa" \ | |
--username "$APPLE_ID_USERNAME" --password "$APPLE_ID_PASSWORD" | |
shell: bash | |
- name: Deploy to App Store | |
if: | | |
(github.ref == 'refs/heads/main' | |
&& needs.setup.outputs.rc_branch_exists == 0 | |
&& needs.setup.outputs.hotfix_branch_exists == 0) | |
|| (github.ref == 'refs/heads/rc' && needs.setup.outputs.hotfix_branch_exists == 0) | |
|| github.ref == 'refs/heads/hotfix-rc' | |
env: | |
APPLE_ID_USERNAME: ${{ secrets.APPLE_ID_USERNAME }} | |
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} | |
run: | | |
xcrun altool --upload-app --type ios --file "./bitwarden-export/Bitwarden.ipa" \ | |
--username "$APPLE_ID_USERNAME" --password "$APPLE_ID_PASSWORD" | |
crowdin-push: | |
name: Crowdin Push | |
if: github.ref == 'refs/heads/main' | |
needs: | |
- android | |
- f-droid | |
- ios | |
runs-on: ubuntu-22.04 | |
env: | |
_CROWDIN_PROJECT_ID: "269690" | |
steps: | |
- name: Checkout repo | |
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 | |
- name: Login to Azure - CI Subscription | |
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 | |
with: | |
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} | |
- name: Retrieve secrets | |
id: retrieve-secrets | |
uses: bitwarden/gh-actions/get-keyvault-secrets@main | |
with: | |
keyvault: "bitwarden-ci" | |
secrets: "crowdin-api-token" | |
- name: Upload Sources | |
uses: crowdin/github-action@198daeb2d30636c4608d6a6bb96c009dbefc02a2 # v1.18.0 | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }} | |
with: | |
config: crowdin.yml | |
crowdin_branch_name: main | |
upload_sources: true | |
upload_translations: false | |
check-failures: | |
name: Check for failures | |
if: always() | |
runs-on: ubuntu-22.04 | |
needs: | |
- cloc | |
- android | |
- f-droid | |
- ios | |
- crowdin-push | |
steps: | |
- name: Check if any job failed | |
if: | | |
(github.ref == 'refs/heads/main') | |
|| (github.ref == 'refs/heads/rc') | |
|| (github.ref == 'refs/heads/hotfix-rc') | |
env: | |
CLOC_STATUS: ${{ needs.cloc.result }} | |
ANDROID_STATUS: ${{ needs.android.result }} | |
F_DROID_STATUS: ${{ needs.f-droid.result }} | |
IOS_STATUS: ${{ needs.ios.result }} | |
CROWDIN_PUSH_STATUS: ${{ needs.crowdin-push.result }} | |
run: | | |
if [ "$CLOC_STATUS" = "failure" ]; then | |
exit 1 | |
elif [ "$ANDROID_STATUS" = "failure" ]; then | |
exit 1 | |
elif [ "$F_DROID_STATUS" = "failure" ]; then | |
exit 1 | |
elif [ "$IOS_STATUS" = "failure" ]; then | |
exit 1 | |
elif [ "$CROWDIN_PUSH_STATUS" = "failure" ]; then | |
exit 1 | |
fi | |
- name: Login to Azure - CI Subscription | |
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 | |
if: failure() | |
with: | |
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} | |
- name: Retrieve secrets | |
id: retrieve-secrets | |
uses: bitwarden/gh-actions/get-keyvault-secrets@main | |
if: failure() | |
with: | |
keyvault: "bitwarden-ci" | |
secrets: "devops-alerts-slack-webhook-url" | |
- name: Notify Slack on failure | |
uses: act10ns/slack@ed1309ab9862e57e9e583e51c7889486b9a00b0f # v2.0.0 | |
if: failure() | |
env: | |
SLACK_WEBHOOK_URL: ${{ steps.retrieve-secrets.outputs.devops-alerts-slack-webhook-url }} | |
with: | |
status: ${{ job.status }} |