diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 9cea827df36..a70e1c40638 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -37,6 +37,7 @@ dependencies { implementation 'org.jsoup:jsoup:1.11.2' implementation 'digital.wup:android-maven-publish:3.6.2' implementation 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.20' + implementation 'org.json:json:20180813' implementation 'io.opencensus:opencensus-api:0.18.0' implementation 'io.opencensus:opencensus-exporter-stats-stackdriver:0.18.0' @@ -44,7 +45,6 @@ dependencies { implementation 'com.android.tools.build:gradle:3.2.1' testImplementation 'junit:junit:4.12' - testImplementation 'org.json:json:20180813' testImplementation('org.spockframework:spock-core:1.1-groovy-2.4') { exclude group: 'org.codehaus.groovy' } diff --git a/buildSrc/src/main/groovy/com/google/firebase/gradle/plugins/ci/AffectedProjectFinder.groovy b/buildSrc/src/main/groovy/com/google/firebase/gradle/plugins/ci/AffectedProjectFinder.groovy index d04607189e9..ffe1e43099c 100644 --- a/buildSrc/src/main/groovy/com/google/firebase/gradle/plugins/ci/AffectedProjectFinder.groovy +++ b/buildSrc/src/main/groovy/com/google/firebase/gradle/plugins/ci/AffectedProjectFinder.groovy @@ -25,6 +25,10 @@ class AffectedProjectFinder { Set changedPaths; @Builder + AffectedProjectFinder(Project project, List ignorePaths) { + this(project, changedPaths(project.rootDir), ignorePaths) + } + AffectedProjectFinder(Project project, Set changedPaths, List ignorePaths) { @@ -49,6 +53,13 @@ class AffectedProjectFinder { return project.subprojects } + private static Set changedPaths(File workDir) { + return 'git diff --name-only --submodule=diff HEAD@{0} HEAD@{1}' + .execute([], workDir) + .text + .readLines() + } + /** * Performs a post-order project tree traversal and returns a set of projects that own the * 'changedPaths'. diff --git a/buildSrc/src/main/groovy/com/google/firebase/gradle/plugins/ci/ContinuousIntegrationPlugin.groovy b/buildSrc/src/main/groovy/com/google/firebase/gradle/plugins/ci/ContinuousIntegrationPlugin.groovy index 95334ba6dbd..7c44748e6be 100644 --- a/buildSrc/src/main/groovy/com/google/firebase/gradle/plugins/ci/ContinuousIntegrationPlugin.groovy +++ b/buildSrc/src/main/groovy/com/google/firebase/gradle/plugins/ci/ContinuousIntegrationPlugin.groovy @@ -97,7 +97,6 @@ class ContinuousIntegrationPlugin implements Plugin { def affectedProjects = AffectedProjectFinder.builder() .project(project) - .changedPaths(changedPaths(project.rootDir)) .ignorePaths(extension.ignorePaths) .build() .find() @@ -143,13 +142,6 @@ class ContinuousIntegrationPlugin implements Plugin { } } - private static Set changedPaths(File workDir) { - return 'git diff --name-only --submodule=diff HEAD@{0} HEAD@{1}' - .execute([], workDir) - .text - .readLines() - } - private static final ANDROID_PLUGINS = ["com.android.application", "com.android.library", "com.android.test"] diff --git a/buildSrc/src/main/groovy/com/google/firebase/gradle/plugins/ci/SmokeTestsPlugin.groovy b/buildSrc/src/main/groovy/com/google/firebase/gradle/plugins/ci/SmokeTestsPlugin.groovy new file mode 100644 index 00000000000..853e845418d --- /dev/null +++ b/buildSrc/src/main/groovy/com/google/firebase/gradle/plugins/ci/SmokeTestsPlugin.groovy @@ -0,0 +1,105 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.firebase.gradle.plugins.ci + +import com.google.firebase.gradle.plugins.FirebaseLibraryExtension +import com.google.firebase.gradle.plugins.ci.AffectedProjectFinder +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.artifacts.ProjectDependency +import org.json.JSONArray +import org.json.JSONObject + +/** Builds Firebase libraries for consumption by the smoke tests. */ +class SmokeTestsPlugin implements Plugin { + @Override + public void apply(Project project) { + def assembleAllTask = project.task("assembleAllForSmokeTests") + + // Wait until after the projects have been evaluated or else we might skip projects. + project.gradle.projectsEvaluated { + def changedProjects = getChangedProjects(project) + def changedArtifacts = new HashSet() + def allArtifacts = new HashSet() + + // Visit each project and add the artifacts to the appropriate sets. + project.subprojects { + def firebaseLibrary = it.extensions.findByType(FirebaseLibraryExtension) + if (firebaseLibrary == null) { + return + } + + def groupId = firebaseLibrary.groupId.get() + def artifactId = firebaseLibrary.artifactId.get() + def artifact = "$groupId:$artifactId:$it.version-SNAPSHOT" + allArtifacts.add(artifact) + + if (changedProjects.contains(it)) { + changedArtifacts.add(artifact) + } + } + + // Reuse the publish task for building the libraries. + def publishAllTask = project.tasks.getByPath("publishAllToBuildDir") + assembleAllTask.dependsOn(publishAllTask) + + // Generate a JSON file listing the artifacts after everything is complete. + assembleAllTask.doLast { + def changed = new JSONArray() + changedArtifacts.each { changed.put(it) } + + def all = new JSONArray() + allArtifacts.each { all.put(it) } + + def json = new JSONObject() + json.put("all", all) + json.put("changed", changed) + + def path = project.buildDir.toPath() + path.resolve("m2repository/changed-artifacts.json").write(json.toString()) + } + } + } + + private static Set getChangedProjects(Project p) { + Set roots = new AffectedProjectFinder(p, []).find() + HashSet changed = new HashSet<>() + + getChangedProjectsLoop(roots, changed) + return changed + } + + private static void getChangedProjectsLoop(Collection projects, Set changed) { + for (Project p : projects) { + // Skip project if it is not a Firebase library. + if (p.extensions.findByType(FirebaseLibraryExtension) == null) { + continue; + } + + // Skip processing and recursion if this project has already been added to the set. + if (!changed.add(p)) { + continue; + } + + // Find all (head) dependencies to other projects in this respository. + def all = p.configurations.releaseRuntimeClasspath.allDependencies + def affected = + all.findAll { it instanceof ProjectDependency }.collect { it.getDependencyProject() } + + // Recurse with the new dependencies. + getChangedProjectsLoop(affected, changed) + } + } +} diff --git a/root-project.gradle b/root-project.gradle index 1d519f9278f..7ee1e9d0401 100644 --- a/root-project.gradle +++ b/root-project.gradle @@ -52,6 +52,7 @@ ext { apply plugin: com.google.firebase.gradle.plugins.publish.PublishingPlugin apply plugin: com.google.firebase.gradle.plugins.ci.ContinuousIntegrationPlugin +apply plugin: com.google.firebase.gradle.plugins.ci.SmokeTestsPlugin apply plugin: com.google.firebase.gradle.plugins.ci.metrics.MetricsPlugin firebaseContinuousIntegration {