From ea3cd46133186a1defaaef3bae500131ab70c7af Mon Sep 17 00:00:00 2001 From: Grisha Kruglov Date: Fri, 4 Oct 2019 16:01:12 -0700 Subject: [PATCH] Closes #1022: Auto-publication workflow for android-component This patch enabled support for an auto-publication workflow for android-components. It automates a common pattern seen in local development: Old way: - after every change in a-c, publish it locally with a unique version (bumping it manually) - manually modify Fenix to consume a custom version of a-c from a mavenLocal repository New way: - set a flag in fenix's local.properties to enable auto-publication - run Fenix builds after making changes to a-c. Changes in a-c will be automatically picked up. Note that no changes are necessary to any Fenix files other than a single flag in local.properties. Manually bumping android-components version is also not necessary. --- app/build.gradle | 5 +++++ settings.gradle | 57 +++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 54 insertions(+), 8 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 76fc0c109..f08ef3a49 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -633,3 +633,8 @@ if (gradle.hasProperty('localProperties.dependencySubstitutions.geckoviewTopsrcd ext.topsrcdir = gradle."localProperties.dependencySubstitutions.geckoviewTopsrcdir" apply from: "${topsrcdir}/substitute-local-geckoview.gradle" } + +if (gradle.hasProperty('localProperties.autoPublish.android-components.dir')) { + ext.acSrcDir = gradle."localProperties.autoPublish.android-components.dir" + apply from: "../${acSrcDir}/substitute-local-ac.gradle" +} diff --git a/settings.gradle b/settings.gradle index 730a05be1..e8aaca471 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,18 +1,38 @@ include ':app', ':architecture' +def log(message) { + logger.lifecycle("[settings] ${message}") +} + +def runCmd(cmd, workingDir, successMessage) { + def proc = cmd.execute(null, new File(workingDir)) + def standardOutput = new ByteArrayOutputStream() + def standardError = new ByteArrayOutputStream() + proc.consumeProcessOutput(standardOutput, standardError) + proc.waitFor() + + if (proc.exitValue() != 0) { + throw new GradleException("Process '${cmd}' finished with non-zero exit value ${proc.exitValue()}:\n\nstdout:\n${standardOutput.toString()}\n\nstderr:\n${standardError.toString()}") + } else { + log(successMessage) + } + return standardOutput +} + ////////////////////////////////////////////////////////////////////////// // Local Development overrides ////////////////////////////////////////////////////////////////////////// -Properties localProperties = null; -String settingAppServicesPath = "substitutions.application-services.dir"; +Properties localProperties = null +String settingAppServicesPath = "substitutions.application-services.dir" +String settingAndroidComponentsPath = "autoPublish.android-components.dir" if (file('local.properties').canRead()) { localProperties = new Properties() localProperties.load(file('local.properties').newDataInputStream()) - logger.lifecycle('Local configuration: loaded local.properties') + log('Loaded local.properties') } else { - logger.lifecycle('Local configuration: absent local.properties; proceeding as normal.') + log('Missing local.properties; see https://github.com/mozilla-mobile/fenix/blob/master/README.md#local-properties-helpers for instructions.') } if (localProperties != null) { @@ -20,12 +40,33 @@ if (localProperties != null) { gradle.ext.set("localProperties.${prop.key}", prop.value) } - String appServicesLocalPath = localProperties.getProperty(settingAppServicesPath); + String appServicesLocalPath = localProperties.getProperty(settingAppServicesPath) if (appServicesLocalPath != null) { - logger.lifecycle("Local configuration: substituting application-services modules from path: $appServicesLocalPath") + log("Enabling composite build with application-services modules from: $appServicesLocalPath") includeBuild(appServicesLocalPath) } else { - logger.lifecycle("Local configuration: application-services substitution path missing. Specify it via '$settingAppServicesPath' setting.") + log("Disabled composite builds with application-services. Enable them by settings '$settingAppServicesPath' in local.properties") } -} \ No newline at end of file + + String androidComponentsLocalPath = localProperties.getProperty(settingAndroidComponentsPath) + + if (androidComponentsLocalPath != null) { + log("Enabling automatic publication of android-components from: $androidComponentsLocalPath") + log("Determining if android-components are up-to-date...") + def compileAcCmd = ["${androidComponentsLocalPath}/gradlew", "compileReleaseKotlin"] + def compileOutput = runCmd(compileAcCmd, androidComponentsLocalPath, "Compiled android-components.") + // This is somewhat brittle: parse last line of gradle output, to fish out how many tasks were executed. + // One executed task means gradle didn't do any work other than executing the top-level 'compile' task. + def compileTasksExecuted = compileOutput.toString().split('\n').last().split(':')[1].split(' ')[1] + if (compileTasksExecuted.equals("1")) { + log("android-components are up-to-date, skipping publication.") + } else { + log("android-components changed, publishing locally...") + def publishAcCmd = ["${androidComponentsLocalPath}/gradlew", "publishToMavenLocal", "-Plocal=true"] + runCmd(publishAcCmd, androidComponentsLocalPath, "Published android-components.") + } + } else { + log("Disabled auto-publication of android-components. Enable it by settings '$settingAndroidComponentsPath' in local.properties") + } +}