diff --git a/.github/workflows/deploy_github_releases.yml b/.github/workflows/deploy_github_releases.yml index 90282840c..4952f3754 100644 --- a/.github/workflows/deploy_github_releases.yml +++ b/.github/workflows/deploy_github_releases.yml @@ -31,6 +31,8 @@ jobs: uses: gradle/gradle-build-action@v2.1.3 with: arguments: --no-configuration-cache :app:assembleFreeRelease :app:assembleNonFreeRelease :app:bundleNonFreeRelease + env: + SENTRY_DSN: ${{ secrets.SENTRY_DSN }} - name: Upload non-free release APK uses: actions/upload-artifact@v2.3.1 diff --git a/.github/workflows/deploy_snapshot.yml b/.github/workflows/deploy_snapshot.yml index 3a0bb6515..a055c0b23 100644 --- a/.github/workflows/deploy_snapshot.yml +++ b/.github/workflows/deploy_snapshot.yml @@ -31,6 +31,7 @@ jobs: uses: gradle/gradle-build-action@v2.1.3 env: SNAPSHOT: "true" + SENTRY_DSN: ${{ secrets.SENTRY_DSN }} with: arguments: --no-configuration-cache :app:assembleFreeRelease :app:assembleNonFreeRelease diff --git a/CHANGELOG.md b/CHANGELOG.md index 83fdffe0f..68db6e4a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ All notable changes to this project will be documented in this file. - Allow importing QR code from images - Introduce a new opt-in PGP backend powered by [PGPainless](https://github.com/pgpainless/pgpainless) that does not require OpenKeychain - Add the ability to run garbage collection on the internal Git repository +- Introduce crash reporting backed by Sentry ### Fixed diff --git a/app/build.gradle.kts b/app/build.gradle.kts index df8b281b8..ebf9a98ca 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -10,6 +10,7 @@ plugins { id("com.github.android-password-store.kotlin-android") id("com.github.android-password-store.kotlin-kapt") id("com.github.android-password-store.versioning-plugin") + id("com.github.android-password-store.sentry") id("dagger.hilt.android.plugin") } @@ -106,6 +107,7 @@ dependencies { debugImplementation(libs.thirdparty.leakcanary) add("nonFreeImplementation", libs.thirdparty.nonfree.googlePlayAuthApiPhone) + add("nonFreeImplementation", libs.thirdparty.nonfree.sentry) androidTestImplementation(libs.bundles.testDependencies) androidTestImplementation(libs.bundles.androidTestDependencies) diff --git a/app/src/nonFree/AndroidManifest.xml b/app/src/nonFree/AndroidManifest.xml new file mode 100644 index 000000000..2f8d27460 --- /dev/null +++ b/app/src/nonFree/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/build-logic/android-plugins/src/main/kotlin/com.github.android-password-store.sentry.gradle.kts b/build-logic/android-plugins/src/main/kotlin/com.github.android-password-store.sentry.gradle.kts new file mode 100644 index 000000000..3648ccf0e --- /dev/null +++ b/build-logic/android-plugins/src/main/kotlin/com.github.android-password-store.sentry.gradle.kts @@ -0,0 +1,29 @@ +@file:Suppress("PropertyName") + +import flavors.FlavorDimensions +import flavors.ProductFlavors + +plugins { id("com.android.application") } + +val SENTRY_DSN_PROPERTY = "SENTRY_DSN" +val INVOKED_FROM_IDE_PROPERTY = "android.injected.invoked.from.ide" + +android { + androidComponents { + onVariants(selector().withFlavor(FlavorDimensions.FREE to ProductFlavors.NON_FREE)) { variant -> + val sentryDsn = + project + .providers + .environmentVariable(SENTRY_DSN_PROPERTY) + .orElse("https://public_key@example.com/project_id") + if (sentryDsn.isPresent) { + variant.manifestPlaceholders.put("sentryDsn", sentryDsn.get()) + } else if (project.providers.gradleProperty(INVOKED_FROM_IDE_PROPERTY).orNull != "true") { + // Checking for 'INVOKED_FROM_IDE_PROPERTY' prevents failures during Gradle sync by the IDE + throw GradleException( + "The '${SENTRY_DSN_PROPERTY}' environment variable must be set when building the ${ProductFlavors.NON_FREE} flavor" + ) + } + } + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b31fa3b3a..11ffad886 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -83,6 +83,7 @@ thirdparty-plumber = { module = "com.squareup.leakcanary:plumber-android", versi thirdparty-logcat = "com.squareup.logcat:logcat:0.1" thirdparty-modernAndroidPrefs = "de.maxr1998:modernandroidpreferences:2.3.0" thirdparty-nonfree-googlePlayAuthApiPhone = "com.google.android.gms:play-services-auth-api-phone:18.0.1" +thirdparty-nonfree-sentry = "io.sentry:sentry-android:5.6.1" thirdparty-pgpainless = "org.pgpainless:pgpainless-core:1.1.0" thirdparty-sshauth = "com.github.open-keychain.open-keychain:sshauthentication-api:5.7.5" thirdparty-sshj = "com.hierynomus:sshj:0.32.0"