Skip to content

Commit

Permalink
Merge pull request #249 from bugsnag/v5-auto-update-build-uuid
Browse files Browse the repository at this point in the history
Add autoUpdateBuildUuid flag to prevent manifest UUID generation
  • Loading branch information
fractalwrench authored Aug 4, 2020
2 parents 3962b46 + 56177ca commit 44e4672
Show file tree
Hide file tree
Showing 17 changed files with 138 additions and 41 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
## 5.0.0 (TBD)

Add autoUpdateBuildUuid flag to prevent manifest UUID generation
[#249](https://github.com/bugsnag/bugsnag-android-gradle-plugin/pull/249)

Switch to OkHttp for networking
[#247](https://github.com/bugsnag/bugsnag-android-gradle-plugin/pull/247)

Expand Down
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
source "https://rubygems.org"

gem "bugsnag-maze-runner", git: 'https://github.com/bugsnag/maze-runner', :tag => 'v1.2.0'
gem "bugsnag-maze-runner", git: 'https://github.com/bugsnag/maze-runner', :branch => 'v1'
4 changes: 2 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
GIT
remote: https://github.com/bugsnag/maze-runner
revision: 5df4754e63555507d468d94f33afeb37b1d5bd7c
tag: v1.2.0
revision: 7377529a77eb7585afc66cd2080fcdc4eea3306a
branch: v1
specs:
bugsnag-maze-runner (1.1.0)
cucumber (~> 3.1.0)
Expand Down
3 changes: 1 addition & 2 deletions detekt-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@
<SmellBaseline>
<Blacklist></Blacklist>
<Whitelist>
<ID>ComplexCondition:AndroidManifestParser.kt$AndroidManifestParser$apiKey == null || "" == apiKey || versionCode == null || buildUUID == null || versionName == null || applicationId == null</ID>
<ID>ComplexCondition:AndroidManifestParser.kt$AndroidManifestParser$apiKey == null || "" == apiKey || versionCode == null || versionName == null || applicationId == null</ID>
<ID>LongParameterList:BugsnagPlugin.kt$BugsnagPlugin$(task: Task, variant: ApkVariant, output: ApkVariantOutput, project: Project, bugsnag: BugsnagPluginExtension, autoUpload: Boolean)</ID>
<ID>MagicNumber:BugsnagMultiPartUploadRequest.kt$BugsnagMultiPartUploadRequest$200</ID>
<ID>MagicNumber:BugsnagPluginExtension.kt$BugsnagPluginExtension$60000</ID>
<ID>MagicNumber:BugsnagReleasesTask.kt$BugsnagReleasesTask$200</ID>
<ID>MagicNumber:BugsnagUploadNdkTask.kt$BugsnagUploadNdkTask.Companion$8192</ID>
<ID>MaxLineLength:BugsnagManifestUuidTask.kt$BugsnagManifestUuidTask$private</ID>
<ID>MaxLineLength:BugsnagUploadNdkTask.kt$BugsnagUploadNdkTask.Companion$return File("$ndkDir/toolchains/${abi.toolchainPrefix}-4.9/prebuilt/$osName/bin/${abi.objdumpPrefix}-$executable")</ID>
<ID>ReturnCount:BugsnagManifestUuidTask.kt$BugsnagManifestUuidTask$private fun getManifestOutputDir(processManifest: ManifestProcessorTask, project: Project): File?</ID>
Expand Down
31 changes: 31 additions & 0 deletions features/auto_update_build_uuid.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
Feature: Auto update build UUID flag

Scenario: Build UUID excluded from request when set to false
When I build "default_app" using the "auto_update_build_uuid" bugsnag config
Then I should receive 2 requests

And the request 0 is valid for the Android Mapping API
And the field "apiKey" for multipart request 0 equals "TEST_API_KEY"
And the field "versionCode" for multipart request 0 equals "1"
And the field "versionName" for multipart request 0 equals "1.0"
And the field "appId" for multipart request 0 equals "com.bugsnag.android.example"
And the field "overwrite" for multipart request 0 is null
And the field "buildUuid" for multipart request 0 is null

And the request 1 is valid for the Build API
And the payload field "appVersion" equals "1.0" for request 1
And the payload field "apiKey" equals "TEST_API_KEY" for request 1
And the payload field "builderName" is not null for request 1
And the payload field "buildTool" equals "gradle-android" for request 1
And the payload field "appVersionCode" equals "1" for request 1
And the payload field "buildUuid" is null for request 1

And the payload field "sourceControl.provider" equals "github" for request 1
And the payload field "sourceControl.repository" equals "https://github.com/bugsnag/bugsnag-android-gradle-plugin.git" for request 1
And the payload field "sourceControl.revision" is not null for request 1
And the payload field "metadata.os_arch" is not null for request 1
And the payload field "metadata.os_name" is not null for request 1
And the payload field "metadata.os_version" is not null for request 1
And the payload field "metadata.java_version" is not null for request 1
And the payload field "metadata.gradle_version" is not null for request 1
And the payload field "metadata.git_version" is not null for request 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
project.afterEvaluate {
project.bugsnag.endpoint = "http://localhost:${System.env.MOCK_API_PORT}"
project.bugsnag.releasesEndpoint = "http://localhost:${System.env.MOCK_API_PORT}"
project.bugsnag.autoUpdateBuildUuid = false
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import java.io.File
data class AndroidManifestInfo(
var apiKey: String,
var versionCode: String,
var buildUUID: String,
var buildUUID: String?,
var versionName: String,
var applicationId: String
) {
Expand Down
30 changes: 17 additions & 13 deletions src/main/kotlin/com.bugsnag.android.gradle/AndroidManifestParser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class AndroidManifestParser {
// Uniquely identify the build so that we can identify the proguard file.
val buildUUID = getManifestMetaData(metadataTags, TAG_BUILD_UUID)
if (buildUUID == null) {
logger.warn("Bugsnag: Could not find '$TAG_BUILD_UUID'" +
logger.info("Bugsnag: Could not find '$TAG_BUILD_UUID'" +
" <meta-data> tag in your AndroidManifest.xml")
}

Expand All @@ -56,13 +56,11 @@ class AndroidManifestParser {
logger.warn("Bugsnag: Could not find 'package' value in your AndroidManifest.xml")
}

if (apiKey == null || "" == apiKey || versionCode == null ||
buildUUID == null || versionName == null || applicationId == null) {
if (apiKey == null || "" == apiKey || versionCode == null || versionName == null || applicationId == null) {
throw IllegalStateException(
"""Bugsnag: Missing apiKey/versionCode/buildUuid/versionName/package, required to upload to bugsnag.
|apiKey=$apiKey
|versionCode=$versionCode
|buildUUID=$buildUUID
|versionName=$versionName
|applicationId=$applicationId
""".trimMargin())
Expand All @@ -81,20 +79,19 @@ class AndroidManifestParser {
val application = (root[TAG_APPLICATION] as NodeList)[0] as Node
val metadataTags = findMetadataTags(application)

// If the current manifest does not contain the build ID then try the next manifest in the list (if any)
if (!hasBuildUuid(metadataTags)) {
// Add the new BUILD_UUID_TAG element
// Add the new BUILD_UUID_TAG element
if (!hasBuildUuid(metadataTags) && IGNORE_BUILD_UUID != buildUuid) {
application.appendNode(TAG_META_DATA, hashMapOf(
namespace.get(ATTR_NAME) to TAG_BUILD_UUID,
namespace.get(ATTR_VALUE) to buildUuid
))
}

// Write the manifest file
FileWriter(outputPath).use {
val printer = XmlNodePrinter(PrintWriter(it))
printer.isPreserveWhitespace = true
printer.print(root)
}
// Write the manifest file
FileWriter(outputPath).use {
val printer = XmlNodePrinter(PrintWriter(it))
printer.isPreserveWhitespace = true
printer.print(root)
}
}

Expand Down Expand Up @@ -133,6 +130,13 @@ class AndroidManifestParser {
}

companion object {

/**
* Used as a predictable task input when autoUpdateBuildUuid is set to false,
* as the versionName/versionCode/package fields should be used instead.
*/
const val IGNORE_BUILD_UUID = "IGNORE_BUILD_UUID"

private const val TAG_APPLICATION = "application"
private const val TAG_META_DATA = "meta-data"
private const val TAG_API_KEY = "com.bugsnag.android.API_KEY"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,9 @@ class BugsnagMultiPartUploadRequest(
parts["apiKey"] = manifestInfo.apiKey.toTextRequestBody()
parts["appId"] = manifestInfo.applicationId.toTextRequestBody()
parts["versionCode"] = manifestInfo.versionCode.toTextRequestBody()
parts["buildUUID"] = manifestInfo.buildUUID.toTextRequestBody()
if (manifestInfo.buildUUID != null) {
parts["buildUUID"] = manifestInfo.buildUUID!!.toTextRequestBody()
}
parts["versionName"] = manifestInfo.versionName.toTextRequestBody()
if (overwrite) {
parts["overwrite"] = "true".toTextRequestBody()
Expand Down
14 changes: 7 additions & 7 deletions src/main/kotlin/com.bugsnag.android.gradle/BugsnagPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,12 @@ import com.android.build.gradle.api.ApkVariant
import com.android.build.gradle.api.ApkVariantOutput
import com.android.build.gradle.api.ApplicationVariant
import com.android.build.gradle.tasks.ExternalNativeBuildTask
import com.bugsnag.android.gradle.BugsnagReleasesTask.Companion
import org.gradle.api.DomainObjectSet
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.file.RegularFile
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.TaskProvider
import java.util.UUID

Expand Down Expand Up @@ -352,10 +348,14 @@ class BugsnagPlugin : Plugin<Project> {
return layout.buildDirectory.file(path)
}



private fun Project.newUuidProvider(): Provider<String> {
return provider { UUID.randomUUID().toString() }
val bugsnag = extensions.findByType(BugsnagPluginExtension::class.java)!!
return provider {
when {
bugsnag.autoUpdateBuildUuid.get() -> UUID.randomUUID().toString()
else -> AndroidManifestParser.IGNORE_BUILD_UUID
}
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import org.gradle.api.provider.MapProperty
import org.gradle.api.provider.Property
import org.gradle.util.ConfigureUtil
import java.io.File
import javax.inject.Inject

// To make kotlin happy with gradle's nullability
private val NULL_STRING: String? = null
Expand All @@ -25,6 +24,8 @@ open class BugsnagPluginExtension(objects: ObjectFactory) {
var isUploadNdkMappings: Boolean? = null
var isReportBuilds = true
var isUploadDebugBuildMappings = false
val autoUpdateBuildUuid: Property<Boolean> = objects.property(Boolean::class.javaObjectType)
.convention(true)
val endpoint: Property<String> = objects.property(String::class.javaObjectType)
.convention("https://upload.bugsnag.com")
val releasesEndpoint = objects.property(String::class.javaObjectType)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.bugsnag.android.gradle

import org.gradle.api.logging.Logger
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.junit.MockitoJUnitRunner
import java.io.File

@RunWith(MockitoJUnitRunner::class)
class AndroidManifestParseNoUuidTest {

private val info = AndroidManifestInfo(
"api-key",
"12",
null,
"5.2",
"com.example"
)

@Mock
lateinit var logger: Logger

private lateinit var manifestFile: File

@Before
fun setUp() {
manifestFile = File.createTempFile("manifest_no_uuid", ".xml")
val classLoader = AndroidManifestParseNoUuidTest::class.java.classLoader
val res = classLoader.getResource("manifest_no_uuid.xml")!!
File(res.file).copyTo(manifestFile, true)
}

@After
fun tearDown() {
manifestFile.delete()
}

@Test
fun readManifest() {
val read = AndroidManifestParser().readManifest(manifestFile, logger)
assertEquals(info, read)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import org.mockito.junit.MockitoJUnitRunner
import java.io.File

@RunWith(MockitoJUnitRunner::class)
class AndroidManifestParseTest {
class AndroidManifestParseUuidTest {

private val info = AndroidManifestInfo(
"api-key",
Expand All @@ -29,7 +29,7 @@ class AndroidManifestParseTest {
@Before
fun setUp() {
manifestFile = File.createTempFile("AndroidManifest", ".xml")
val classLoader = AndroidManifestParseTest::class.java.classLoader
val classLoader = AndroidManifestParseUuidTest::class.java.classLoader
val res = classLoader.getResource("AndroidManifest.xml")!!
File(res.file).copyTo(manifestFile, true)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import org.junit.Before
import org.junit.Test
import java.io.File

class AndroidManifestWriteUuidTest {
class AndroidManifestWriteTest {

private val classLoader = AndroidManifestWriteUuidTest::class.java.classLoader
private val classLoader = AndroidManifestWriteTest::class.java.classLoader

private lateinit var manifestFile: File
private lateinit var outputFile: File
Expand All @@ -34,4 +34,12 @@ class AndroidManifestWriteUuidTest {
val expected = classLoader.getResource("AndroidManifest.xml")!!.readText()
assertEquals(expected, obs)
}

@Test
fun writeNoBuildUuid() {
AndroidManifestParser().writeBuildUuid(manifestFile, outputFile, AndroidManifestParser.IGNORE_BUILD_UUID)
val obs = outputFile.readText()
val expected = classLoader.getResource("manifest_no_uuid.xml")!!.readText()
assertEquals(expected, obs)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ class BugsnagServiceTest {
parts["apiKey"] = manifestInfo.apiKey.toTextRequestBody()
parts["appId"] = manifestInfo.applicationId.toTextRequestBody()
parts["versionCode"] = manifestInfo.versionCode.toTextRequestBody()
parts["buildUUID"] = manifestInfo.buildUUID.toTextRequestBody()
if (manifestInfo.buildUUID != null) {
parts["buildUUID"] = manifestInfo.buildUUID!!.toTextRequestBody()
}
parts["versionName"] = manifestInfo.versionName.toTextRequestBody()

val mappingFile = tmpFolder.newFile()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class PluginExtensionTest {
fun ensureExtensionDefaults() {
val bugsnag = proj.extensions.getByType(BugsnagPluginExtension::class.java)
assertEquals("https://upload.bugsnag.com", bugsnag.endpoint.get())
assertTrue(bugsnag.autoUpdateBuildUuid.get())
assertTrue(bugsnag.isUploadJvmMappings)
assertTrue(bugsnag.isReportBuilds)
assertFalse(bugsnag.isUploadDebugBuildMappings)
Expand Down
10 changes: 2 additions & 8 deletions src/test/resources/manifest_no_uuid.xml
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example"
android:versionCode="12"
android:versionName="5.2">
<manifest package="com.example" android:versionCode="12" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="5.2">
<application android:name="com.example.android.gradle.plugin.FooApp">

<meta-data
android:name="com.bugsnag.android.API_KEY"
android:value="api-key"/>
<meta-data android:name="com.bugsnag.android.API_KEY" android:value="api-key"/>
</application>
</manifest>

0 comments on commit 44e4672

Please sign in to comment.