Build release bundles and publish to Firebase (#50)

This commit is contained in:
Patrick Honkonen 2024-05-02 10:24:37 -04:00 committed by GitHub
parent 26c22295fc
commit d32ed06516
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 276 additions and 8 deletions

View File

@ -76,6 +76,9 @@ jobs:
needs:
- check
runs-on: ubuntu-22.04
strategy:
matrix:
variant: [ "aab", "apk" ]
steps:
- name: Checkout
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
@ -169,6 +172,7 @@ jobs:
shell: bash
- name: Assemble Release APK
if: ${{ matrix.variant == 'apk' }}
run: |
bundle exec fastlane buildRelease \
storeFile:${{ github.workspace }}/keystores/authenticator_apk-keystore.jks \
@ -178,11 +182,13 @@ jobs:
shell: bash
- name: Create checksum file for Release APK
if: ${{ matrix.variant == 'apk' }}
run: |
sha256sum "app/build/outputs/apk/release/com.bitwarden.authenticator-release.apk" \
> ./authenticator-android-apk-sha256.txt
- name: Upload release APK to GitHub
if: ${{ matrix.variant == 'apk' }}
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
with:
name: com.bitwarden.authenticator.apk
@ -190,6 +196,7 @@ jobs:
if-no-files-found: error
- name: Upload checksum file for Release .apk
if: ${{ matrix.variant == 'apk' }}
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
with:
name: authenticator-android-apk-sha256.txt
@ -201,10 +208,61 @@ jobs:
run: bundle exec fastlane add_plugin firebase_app_distribution
- name: Publish release APK to Firebase
if: ${{ github.ref_name == 'main' }}
if: ${{ github.ref_name == 'main' && matrix.variant == 'apk' }}
env:
FIREBASE_CREDS_PATH: ${{ github.workspace }}/secrets/authenticator_play_firebase-creds.json
run: |
bundle exec fastlane distributeReleaseToFirebase \
serviceCredentialsFile:${{ env.FIREBASE_CREDS_PATH }}
shell: bash
- name: Bundle release AAB
if: ${{ matrix.variant == 'aab' }}
run: |
bundle exec fastlane bundleRelease \
storeFile:${{ github.workspace }}/keystores/authenticator_aab-keystore.jks \
storePassword:'${{ secrets.AAB_KEYSTORE_STORE_PASSWORD }}' \
keyAlias:authenticatorupload \
keyPassword:'${{ secrets.AAB_KEYSTORE_KEY_PASSWORD }}'
shell: bash
- name: Create checksum file for Release AAB
if: ${{ matrix.variant == 'aab' }}
run: |
sha256sum "app/build/outputs/bundle/release/com.bitwarden.authenticator-release.aab" \
> ./authenticator-android-aab-sha256.txt
shell: bash
- name: Upload release AAB to GitHub
if: ${{ matrix.variant == 'aab' }}
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: com.bitwarden.authenticator.aab
path: app/build/outputs/bundle/release/com.bitwarden.authenticator-release.aab
if-no-files-found: error
- name: Upload checksum file for Release .aab
if: ${{ matrix.variant == 'aab' }}
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: authenticator-android-aab-sha256.txt
path: ./authenticator-android-aab-sha256.txt
if-no-files-found: error
- name: Publish release AAB to Firebase
if: ${{ github.ref_name == 'main' && matrix.variant == 'aab' }}
env:
FIREBASE_CREDS_PATH: ${{ github.workspace }}/secrets/authenticator_play_firebase-creds.json
run: |
bundle exec fastlane distributeReleaseBundleToFirebase \
serviceCredentialsFile:${{ env.FIREBASE_CREDS_PATH }}
shell: bash
# - name: Publish release AAB to Google Play Store
# if: ${{ github.ref_name == 'main' && matrix.variant == 'aab'}}
# env:
# PLAY_STORE_CREDS_FILE: ${{ github.workspace }}/secrets/authenticator_play_firebase-creds.json
# run: |
# bundle exec fastlane publishReleaseToGooglePlayStore \
# serviceCredentialsFile:${{ env.PLAY_STORE_CREDS_FILE }} \
# shell: bash

View File

@ -61,7 +61,7 @@ android {
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
excludes += "/META-INF/{AL2.0,LGPL2.1,LICENSE*.md}"
}
}
}
@ -124,4 +124,6 @@ dependencies {
testImplementation(libs.robolectric.robolectric)
testImplementation(libs.square.okhttp.mockwebserver)
testImplementation(libs.square.turbine)
androidTestImplementation(libs.bundles.tests.instrumented)
}

View File

@ -0,0 +1,136 @@
package com.x8bit.bitwarden.android.authenticator
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.isDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import com.bitwarden.authenticator.ui.platform.feature.settings.appearance.model.AppTheme
import com.bitwarden.authenticator.ui.platform.feature.tutorial.TutorialScreen
import com.bitwarden.authenticator.ui.platform.feature.tutorial.TutorialViewModel
import com.bitwarden.authenticator.ui.platform.theme.AuthenticatorTheme
import org.junit.ClassRule
import org.junit.Rule
import org.junit.Test
import tools.fastlane.screengrab.Screengrab
import tools.fastlane.screengrab.locale.LocaleTestRule
class ExampleInstrumentedTest {
@get:Rule
val composeTestRule = createComposeRule()
@Test
fun screenshotTutorialSlides_Dark() {
val viewModel = TutorialViewModel()
composeTestRule.setContent {
AuthenticatorTheme(theme = AppTheme.DARK) {
TutorialScreen(
viewModel = viewModel,
onTutorialFinished = {},
)
}
}
composeTestRule.waitForIdle()
composeTestRule
.onNodeWithText("Continue")
.isDisplayed()
composeTestRule
.onNodeWithText("Secure your accounts with Bitwarden Authenticator")
.isDisplayed()
Screengrab.screenshot("IntroSlide_Dark")
composeTestRule
.onNodeWithText("Continue")
.performClick()
composeTestRule
.onNodeWithText("Use your device camera to scan codes")
.assertIsDisplayed()
Screengrab.screenshot("QrCodeSlide_Dark")
composeTestRule
.onNodeWithText("Continue")
.performClick()
composeTestRule
.onNodeWithText("Sign in using unique codes")
.assertIsDisplayed()
composeTestRule
.onNodeWithText("Continue")
.assertDoesNotExist()
composeTestRule
.onNodeWithText("Get started")
.isDisplayed()
Screengrab.screenshot("UniqueCodesSlide_Dark")
}
@Test
fun screenshotTutorialSlides_Light() {
val viewModel = TutorialViewModel()
composeTestRule.setContent {
AuthenticatorTheme(theme = AppTheme.LIGHT) {
TutorialScreen(
viewModel = viewModel,
onTutorialFinished = {},
)
}
}
composeTestRule.waitForIdle()
composeTestRule
.onNodeWithText("Continue")
.isDisplayed()
composeTestRule
.onNodeWithText("Secure your accounts with Bitwarden Authenticator")
.isDisplayed()
Screengrab.screenshot("IntroSlide_Light")
composeTestRule
.onNodeWithText("Continue")
.performClick()
composeTestRule
.onNodeWithText("Use your device camera to scan codes")
.assertIsDisplayed()
Screengrab.screenshot("QrCodeSlide_Light")
composeTestRule
.onNodeWithText("Continue")
.performClick()
composeTestRule
.onNodeWithText("Sign in using unique codes")
.assertIsDisplayed()
composeTestRule
.onNodeWithText("Continue")
.assertDoesNotExist()
composeTestRule
.onNodeWithText("Get started")
.isDisplayed()
Screengrab.screenshot("UniqueCodesSlide_Light")
}
companion object {
@JvmField
@ClassRule
val localeTestRule: LocaleTestRule = LocaleTestRule()
}
}

View File

@ -2,6 +2,14 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- Allows unlocking your device and activating its screen so UI tests can succeed -->
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- Allows changing locales -->
<uses-permission
android:name="android.permission.CHANGE_CONFIGURATION"
tools:ignore="ProtectedPermissions" />
<application tools:ignore="MissingApplicationIcon">
<!-- Disable Crashlytics for debug builds -->
<meta-data

View File

@ -1,2 +1 @@
json_key_file("secrets/authenticator_play_firebase-creds.json") # Path to the json secret file
package_name("com.bitwarden.authenticator")

View File

@ -42,7 +42,7 @@ platform :android do
# Current date used to derive next version name.
currentDate = Time.new
major = currentDate.year.to_s
minor = currentDate.strftime "%m"
minor = "5"
# Determine the next revision number to apply.
revision = 0
@ -94,8 +94,42 @@ platform :android do
)
end
desc "Bundle and sign release AAB"
lane :bundleRelease do |options|
gradle(
task: "bundle",
build_type: "Release",
properties: {
"android.injected.signing.store.file" => options[:storeFile],
"android.injected.signing.store.password" => options[:storePassword],
"android.injected.signing.key.alias" => options[:keyAlias],
"android.injected.signing.key.password" => options[:keyPassword]
},
print_command: false,
)
end
desc "Publish release to Firebase"
lane :distributeReleaseToFirebase do |options|
lane :distributeReleaseToFirebase do |options|
release_notes = changelog_from_git_commits(
commits_count: 1,
pretty: "- %s"
)
puts "Release notes #{release_notes}"
firebase_app_distribution(
app: "1:867301491091:android:50b626dba42a361651e866",
android_artifact_type: "APK",
android_artifact_path: "app/build/outputs/apk/release/com.bitwarden.authenticator-release.apk",
service_credentials_file: options[:serviceCredentialsFile],
groups: "internal-prod-group",
release_notes: release_notes,
)
end
desc "Publish release AAB to Firebase"
lane :distributeReleaseBundleToFirebase do |options|
release_notes = changelog_from_git_commits(
commits_count: 1,
pretty: "- %s"
@ -105,11 +139,21 @@ platform :android do
firebase_app_distribution(
app: "1:867301491091:android:50b626dba42a361651e866",
android_artifact_type: "APK",
android_artifact_path: "app/build/outputs/apk/release/com.bitwarden.authenticator-release.apk",
android_artifact_type: "AAB",
android_artifact_path: "app/build/outputs/bundle/release/com.bitwarden.authenticator-release.aab",
service_credentials_file: options[:serviceCredentialsFile],
groups: "internal-prod-group",
release_notes: release_notes,
)
end
desc "Publish release to Google Play Store"
lane :publishReleaseToGooglePlayStore do |options|
upload_to_play_store(
json_key: options[:serviceCredentialsFile],
track: "internal",
aab: "app/build/outputs/bundle/release/com.bitwarden.authenticator-release.aab",
mapping: "app/build/outputs/mapping/release/mapping.txt",
)
end
end

View File

@ -13,6 +13,7 @@ androidXBiometrics = "1.2.0-alpha05"
androidxBrowser = "1.8.0"
androidxCamera = "1.3.2"
androidxComposeBom = "2024.04.01"
androidxComposeUiTest = "1.6.6"
androidxCore = "1.12.0"
androidxHiltNavigationCompose = "1.2.0"
androidxLifecycle = "2.7.0"
@ -20,11 +21,14 @@ androidxNavigation = "2.7.7"
androidxRoom = "2.6.1"
androidXSecurityCrypto = "1.1.0-alpha06"
androidxSplash = "1.1.0-rc01"
androidxTest = "1.5.0"
androidXAppCompat = "1.6.1"
androdixAutofill = "1.1.0"
androidxWork = "2.9.0"
bitwardenSdk = "0.4.0-20240314.115913-173"
crashlytics = "2.9.9"
espresso = "3.5.1"
fastlaneScreengrab = "2.1.1"
firebaseBom = "32.8.0"
glide = "1.0.0-beta01"
googleServices = "4.4.1"
@ -67,7 +71,7 @@ androidx-compose-material3 = { module = "androidx.compose.material3:material3" }
androidx-compose-runtime = { module = "androidx.compose.runtime:runtime" }
androidx-compose-ui = { module = "androidx.compose.ui:ui" }
androidx-compose-ui-graphics = { module = "androidx.compose.ui:ui-graphics" }
androidx-compose-ui-test = { module = "androidx.compose.ui:ui-test-junit4" }
androidx-compose-ui-test = { module = "androidx.compose.ui:ui-test-junit4", version.ref = "androidxComposeUiTest" }
androidx-compose-ui-test-manifest = { module = "androidx.compose.ui:ui-test-manifest" }
androidx-compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" }
androidx-compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" }
@ -82,9 +86,13 @@ androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "androidx
androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "androidxRoom" }
androidx-security-crypto = { module = "androidx.security:security-crypto", version.ref = "androidXSecurityCrypto" }
androidx-splashscreen = { module = "androidx.core:core-splashscreen", version.ref = "androidxSplash" }
androidx-test-runner = { module = "androidx.test:runner", version.ref = "androidxTest" }
androidx-test-rules = { module = "androidx.test:rules", version.ref = "androidxTest" }
androidx-test-espresso = { module = "androidx.test.espresso:espresso-core", version.ref = "espresso" }
androidx-work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version.ref = "androidxWork" }
bitwarden-sdk = { module = "com.bitwarden:sdk-android", version.ref = "bitwardenSdk" }
bumptech-glide = { module = "com.github.bumptech.glide:compose", version.ref = "glide" }
fastlane-screengrab = { module = "tools.fastlane:screengrab", version.ref = "fastlaneScreengrab"}
google-firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebaseBom" }
google-firebase-cloud-messaging = { module = "com.google.firebase:firebase-messaging-ktx" }
google-firebase-crashlytics = { module = "com.google.firebase:firebase-crashlytics-ktx" }
@ -98,6 +106,7 @@ kotlinx-collections-immutable = { module = "org.jetbrains.kotlinx:kotlinx-collec
kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinxCoroutines" }
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinxCoroutines" }
kotlinx-serialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerialization" }
mockk-android = { module = "io.mockk:mockk-android", version.ref = "mockk" }
mockk-mockk = { module = "io.mockk:mockk", version.ref = "mockk" }
robolectric-robolectric = { module = "org.robolectric:robolectric", version.ref = "roboelectric" }
square-okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
@ -117,3 +126,15 @@ kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref =
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
kotlinx-kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kotlinxKover" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
[bundles]
tests-instrumented = [
"androidx-compose-ui-test",
"androidx-test-espresso",
"androidx-test-runner",
"androidx-test-rules",
"fastlane-screengrab",
"junit-junit5",
"junit-vintage",
"mockk-android",
]