diff --git a/buildSrc/src/main/java/com/google/firebase/gradle/plugins/BaseFirebaseLibraryPlugin.kt b/buildSrc/src/main/java/com/google/firebase/gradle/plugins/BaseFirebaseLibraryPlugin.kt new file mode 100644 index 00000000000..0815b135053 --- /dev/null +++ b/buildSrc/src/main/java/com/google/firebase/gradle/plugins/BaseFirebaseLibraryPlugin.kt @@ -0,0 +1,106 @@ +// Copyright 2023 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 + +import com.google.firebase.gradle.plugins.ci.Coverage +import java.io.File +import java.nio.file.Paths +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.publish.PublishingExtension +import org.gradle.api.publish.maven.MavenPublication +import org.gradle.api.publish.maven.plugins.MavenPublishPlugin +import org.gradle.api.tasks.TaskProvider +import org.gradle.kotlin.dsl.apply +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.create +import org.gradle.kotlin.dsl.register + +abstract class BaseFirebaseLibraryPlugin : Plugin { + + protected fun kotlinModuleName(project: Project): String { + val fullyQualifiedProjectPath = project.path.replace(":".toRegex(), "-") + return project.rootProject.name + fullyQualifiedProjectPath + } + + protected fun setupStaticAnalysis(project: Project, library: FirebaseLibraryExtension) { + project.afterEvaluate { + configurations.all { + if ("lintChecks" == name) { + for (checkProject in library.staticAnalysis.androidLintCheckProjects) { + project.dependencies.add("lintChecks", project.project(checkProject!!)) + } + } + } + } + project.tasks.register("firebaseLint") { dependsOn("lint") } + Coverage.apply(library) + } + + protected fun getApiInfo(project: Project, srcDirs: Set): TaskProvider { + val outputFile = + project.rootProject.file( + Paths.get( + project.rootProject.buildDir.path, + "apiinfo", + project.path.substring(1).replace(":", "_") + ) + ) + val outputApiFile = File(outputFile.absolutePath + "_api.txt") + val apiTxt = + project.file("api.txt").takeIf { it.exists() } ?: project.rootProject.file("empty-api.txt") + val apiInfo = + project.tasks.register("apiInformation") { + sources.value(project.provider { srcDirs }) + apiTxtFile.set(apiTxt) + baselineFile.set(project.file("baseline.txt")) + this.outputFile.set(outputFile) + this.outputApiFile.set(outputApiFile) + updateBaseline.set(project.hasProperty("updateBaseline")) + } + return apiInfo + } + + protected fun getGenerateApiTxt(project: Project, srcDirs: Set) = + project.tasks.register("generateApiTxtFile") { + sources.value(project.provider { srcDirs }) + apiTxtFile.set(project.file("api.txt")) + baselineFile.set(project.file("baseline.txt")) + updateBaseline.set(project.hasProperty("updateBaseline")) + } + + protected fun getDocStubs(project: Project, srcDirs: Set) = + project.tasks.register("docStubs") { + sources.value(project.provider { srcDirs }) + } + + protected fun configurePublishing(project: Project, firebaseLibrary: FirebaseLibraryExtension) { + project.afterEvaluate { + project.apply() + project.extensions.configure { + repositories.maven { + val s = project.rootProject.buildDir.toString() + "/m2repository" + url = File(s).toURI() + name = "BuildDir" + } + publications.create("mavenAar") { + from(project.components.findByName(firebaseLibrary.type.componentName)) + artifactId = firebaseLibrary.artifactId.get() + groupId = firebaseLibrary.groupId.get() + firebaseLibrary.applyPomCustomization(pom) + } + } + } + } +} diff --git a/buildSrc/src/main/java/com/google/firebase/gradle/plugins/FirebaseJavaLibraryPlugin.java b/buildSrc/src/main/java/com/google/firebase/gradle/plugins/FirebaseJavaLibraryPlugin.java deleted file mode 100644 index 2e2438a3fbc..00000000000 --- a/buildSrc/src/main/java/com/google/firebase/gradle/plugins/FirebaseJavaLibraryPlugin.java +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright 2019 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; - -import com.github.sherter.googlejavaformatgradleplugin.GoogleJavaFormatExtension; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.firebase.gradle.plugins.ci.Coverage; -import java.io.File; -import java.nio.file.Paths; -import org.gradle.api.Plugin; -import org.gradle.api.Project; -import org.gradle.api.attributes.Attribute; -import org.gradle.api.file.FileCollection; -import org.gradle.api.plugins.JavaPluginConvention; -import org.gradle.api.publish.PublishingExtension; -import org.gradle.api.publish.maven.MavenPublication; -import org.gradle.api.tasks.SourceSet; -import org.gradle.api.tasks.TaskProvider; -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile; - -// TODO(vkryachko): extract functionality common across Firebase{,Java}LibraryPlugin plugins. -public class FirebaseJavaLibraryPlugin implements Plugin { - - @Override - public void apply(Project project) { - project.apply(ImmutableMap.of("plugin", "java-library")); - project.apply(ImmutableMap.of("plugin", "com.github.sherter.google-java-format")); - project.getExtensions().getByType(GoogleJavaFormatExtension.class).setToolVersion("1.10.0"); - - FirebaseLibraryExtension firebaseLibrary = - project - .getExtensions() - .create("firebaseLibrary", FirebaseLibraryExtension.class, project, LibraryType.JAVA); - - // reduce the likelihood of kotlin module files colliding. - project - .getTasks() - .withType( - KotlinCompile.class, - kotlin -> - kotlin - .getKotlinOptions() - .setFreeCompilerArgs( - ImmutableList.of("-module-name", kotlinModuleName(project)))); - - setupStaticAnalysis(project, firebaseLibrary); - configurePublishing(project, firebaseLibrary); - project.getTasks().register("kotlindoc"); - } - - private static void setupStaticAnalysis(Project project, FirebaseLibraryExtension library) { - project.afterEvaluate( - p -> - project - .getConfigurations() - .all( - c -> { - if ("lintChecks".equals(c.getName())) { - for (String checkProject : - library.staticAnalysis.androidLintCheckProjects) { - project - .getDependencies() - .add("lintChecks", project.project(checkProject)); - } - } - })); - - setupApiInformationAnalysis(project); - - project.getTasks().register("firebaseLint", task -> task.dependsOn("lint")); - Coverage.apply(library); - } - - private static void setupApiInformationAnalysis(Project project) { - SourceSet mainSourceSet = - project - .getConvention() - .getPlugin(JavaPluginConvention.class) - .getSourceSets() - .getByName("main"); - File outputFile = - project - .getRootProject() - .file( - Paths.get( - project.getRootProject().getBuildDir().getPath(), - "apiinfo", - project.getPath().substring(1).replace(":", "_"))); - File outputApiFile = new File(outputFile.getAbsolutePath() + "_api.txt"); - - File apiTxt = - project.file("api.txt").exists() - ? project.file("api.txt") - : project.file(project.getRootDir() + "/empty-api.txt"); - TaskProvider apiInfo = - project - .getTasks() - .register( - "apiInformation", - ApiInformationTask.class, - task -> { - task.getSources() - .value(project.provider(() -> mainSourceSet.getJava().getSrcDirs())); - task.getApiTxtFile().set(apiTxt); - task.getBaselineFile().set(project.file("baseline.txt")); - task.getOutputFile().set(outputFile); - task.getOutputApiFile().set(outputApiFile); - task.getUpdateBaseline().set(project.hasProperty("updateBaseline")); - }); - - TaskProvider generateApiTxt = - project - .getTasks() - .register( - "generateApiTxtFile", - GenerateApiTxtTask.class, - task -> { - task.getSources() - .value(project.provider(() -> mainSourceSet.getJava().getSrcDirs())); - task.getApiTxtFile().set(project.file("api.txt")); - task.getBaselineFile().set(project.file("baseline.txt")); - task.getUpdateBaseline().set(project.hasProperty("updateBaseline")); - }); - - TaskProvider docStubs = - project - .getTasks() - .register( - "docStubs", - GenerateStubsTask.class, - task -> - task.getSources() - .value(project.provider(() -> mainSourceSet.getJava().getSrcDirs()))); - project.getTasks().getByName("check").dependsOn(docStubs); - - project.afterEvaluate( - p -> { - FileCollection classpath = - project - .getConfigurations() - .getByName("runtimeClasspath") - .getIncoming() - .artifactView( - config -> - config.attributes( - container -> - container.attribute( - Attribute.of("artifactType", String.class), "jar"))) - .getArtifacts() - .getArtifactFiles(); - - apiInfo.configure(t -> t.setClassPath(classpath)); - generateApiTxt.configure(t -> t.setClassPath(classpath)); - docStubs.configure(t -> t.setClassPath(classpath)); - }); - } - - private static String kotlinModuleName(Project project) { - - String fullyQualifiedProjectPath = project.getPath().replaceAll(":", "-"); - - return project.getRootProject().getName() + fullyQualifiedProjectPath; - } - - private static void configurePublishing( - Project project, FirebaseLibraryExtension firebaseLibrary) { - project.apply(ImmutableMap.of("plugin", "maven-publish")); - PublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class); - publishing.repositories( - repos -> - repos.maven( - repo -> { - String s = project.getRootProject().getBuildDir() + "/m2repository"; - File file = new File(s); - repo.setUrl(file.toURI()); - repo.setName("BuildDir"); - })); - publishing.publications( - publications -> - publications.create( - "mavenAar", - MavenPublication.class, - publication -> { - publication.from( - project.getComponents().findByName(firebaseLibrary.type.getComponentName())); - project.afterEvaluate( - p -> { - publication.setArtifactId(firebaseLibrary.artifactId.get()); - publication.setGroupId(firebaseLibrary.groupId.get()); - firebaseLibrary.applyPomCustomization(publication.getPom()); - }); - })); - } -} diff --git a/buildSrc/src/main/java/com/google/firebase/gradle/plugins/FirebaseJavaLibraryPlugin.kt b/buildSrc/src/main/java/com/google/firebase/gradle/plugins/FirebaseJavaLibraryPlugin.kt new file mode 100644 index 00000000000..2ffec857609 --- /dev/null +++ b/buildSrc/src/main/java/com/google/firebase/gradle/plugins/FirebaseJavaLibraryPlugin.kt @@ -0,0 +1,76 @@ +// Copyright 2023 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 + +import com.github.sherter.googlejavaformatgradleplugin.GoogleJavaFormatExtension +import com.github.sherter.googlejavaformatgradleplugin.GoogleJavaFormatPlugin +import com.google.common.collect.ImmutableList +import com.google.firebase.gradle.plugins.LibraryType.JAVA +import org.gradle.api.Project +import org.gradle.api.attributes.Attribute +import org.gradle.api.plugins.JavaLibraryPlugin +import org.gradle.api.plugins.JavaPluginConvention +import org.gradle.kotlin.dsl.* +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +class FirebaseJavaLibraryPlugin : BaseFirebaseLibraryPlugin() { + + override fun apply(project: Project) { + project.apply() + project.apply() + project.extensions.getByType().toolVersion = "1.10.0" + + setupFirebaseLibraryExtension(project) + + // reduce the likelihood of kotlin module files colliding. + project.tasks.withType { + kotlinOptions.freeCompilerArgs = ImmutableList.of("-module-name", kotlinModuleName(project)) + } + } + + private fun setupFirebaseLibraryExtension(project: Project) { + val firebaseLibrary = + project.extensions.create("firebaseLibrary", project, JAVA) + + setupStaticAnalysis(project, firebaseLibrary) + setupApiInformationAnalysis(project) + configurePublishing(project, firebaseLibrary) + } + + private fun setupApiInformationAnalysis(project: Project) { + val srcDirs = + project.convention.getPlugin().sourceSets.getByName("main").java.srcDirs + + val apiInfo = getApiInfo(project, srcDirs) + val generateApiTxt = getGenerateApiTxt(project, srcDirs) + val docStubs = getDocStubs(project, srcDirs) + + project.tasks.getByName("check").dependsOn(docStubs) + project.afterEvaluate { + val classpath = + configurations + .getByName("runtimeClasspath") + .incoming + .artifactView { + attributes { attribute(Attribute.of("artifactType", String::class.java), "jar") } + } + .artifacts + .artifactFiles + apiInfo.configure { classPath = classpath } + generateApiTxt.configure { classPath = classpath } + docStubs.configure { classPath = classpath } + } + } +} diff --git a/buildSrc/src/main/java/com/google/firebase/gradle/plugins/FirebaseLibraryPlugin.java b/buildSrc/src/main/java/com/google/firebase/gradle/plugins/FirebaseLibraryPlugin.java deleted file mode 100644 index 03c239cf69e..00000000000 --- a/buildSrc/src/main/java/com/google/firebase/gradle/plugins/FirebaseLibraryPlugin.java +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright 2019 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; - -import static com.google.firebase.gradle.plugins.ClosureUtil.closureOf; - -import com.android.build.gradle.LibraryExtension; -import com.android.build.gradle.api.AndroidSourceSet; -import com.android.build.gradle.internal.dsl.BuildType; -import com.android.build.gradle.internal.dsl.TestOptions; -import com.github.sherter.googlejavaformatgradleplugin.GoogleJavaFormatExtension; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.firebase.gradle.plugins.ci.Coverage; -import com.google.firebase.gradle.plugins.ci.device.FirebaseTestServer; -import com.google.firebase.gradle.plugins.license.LicenseResolverPlugin; -import java.io.File; -import java.nio.file.Paths; -import kotlin.Unit; -import org.gradle.api.JavaVersion; -import org.gradle.api.NamedDomainObjectContainer; -import org.gradle.api.Plugin; -import org.gradle.api.Project; -import org.gradle.api.attributes.Attribute; -import org.gradle.api.file.FileCollection; -import org.gradle.api.publish.PublishingExtension; -import org.gradle.api.publish.maven.MavenPublication; -import org.gradle.api.publish.tasks.GenerateModuleMetadata; -import org.gradle.api.tasks.TaskProvider; -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile; - -public class FirebaseLibraryPlugin implements Plugin { - - @Override - public void apply(Project project) { - project.apply(ImmutableMap.of("plugin", "com.android.library")); - project.apply(ImmutableMap.of("plugin", LicenseResolverPlugin.class)); - project.apply(ImmutableMap.of("plugin", "com.github.sherter.google-java-format")); - project.getExtensions().getByType(GoogleJavaFormatExtension.class).setToolVersion("1.10.0"); - - FirebaseLibraryExtension firebaseLibrary = - project - .getExtensions() - .create( - "firebaseLibrary", FirebaseLibraryExtension.class, project, LibraryType.ANDROID); - - LibraryExtension android = project.getExtensions().getByType(LibraryExtension.class); - - android.compileOptions( - options -> { - options.setSourceCompatibility(JavaVersion.VERSION_1_8); - options.setTargetCompatibility(JavaVersion.VERSION_1_8); - }); - - // In the case of and android library signing config only affects instrumentation test APK. - // We need it signed with default debug credentials in order for FTL to accept the APK. - android.buildTypes( - (NamedDomainObjectContainer types) -> - types - .getByName("release") - .setSigningConfig(types.getByName("debug").getSigningConfig())); - android.defaultConfig( - cfg -> { - cfg.buildConfigField("String", "VERSION_NAME", "\"" + project.getVersion() + "\""); - }); - - // see https://github.com/robolectric/robolectric/issues/5456 - android.testOptions( - (TestOptions options) -> - options - .getUnitTests() - .all( - closureOf( - test -> { - test.systemProperty("robolectric.dependency.repo.id", "central"); - test.systemProperty( - "robolectric.dependency.repo.url", "https://repo1.maven.org/maven2"); - test.systemProperty("javax.net.ssl.trustStoreType", "JKS"); - }))); - - // skip debug tests in CI - // TODO(vkryachko): provide ability for teams to control this if needed - if (System.getenv().containsKey("FIREBASE_CI")) { - android.setTestBuildType("release"); - project - .getTasks() - .all( - task -> { - if ("testDebugUnitTest".equals(task.getName())) { - task.setEnabled(false); - } - }); - } - - setupApiInformationAnalysis(project, android); - android.testServer(new FirebaseTestServer(project, firebaseLibrary.testLab, android)); - - setupStaticAnalysis(project, firebaseLibrary); - - configurePublishing(project, firebaseLibrary, android); - - // reduce the likelihood of kotlin module files colliding. - project - .getTasks() - .withType( - KotlinCompile.class, - kotlin -> - kotlin - .getKotlinOptions() - .setFreeCompilerArgs( - ImmutableList.of("-module-name", kotlinModuleName(project)))); - - project.getPluginManager().apply(DackkaPlugin.class); - project.getPluginManager().apply(GitSubmodulePlugin.class); - project.getTasks().getByName("preBuild").dependsOn("updateGitSubmodules"); - } - - private static void setupApiInformationAnalysis(Project project, LibraryExtension android) { - AndroidSourceSet mainSourceSet = android.getSourceSets().getByName("main"); - File outputFile = - project - .getRootProject() - .file( - Paths.get( - project.getRootProject().getBuildDir().getPath(), - "apiinfo", - project.getPath().substring(1).replace(":", "_"))); - File outputApiFile = new File(outputFile.getAbsolutePath() + "_api.txt"); - - File apiTxt = - project.file("api.txt").exists() - ? project.file("api.txt") - : project.file(project.getRootDir() + "/empty-api.txt"); - TaskProvider apiInfo = - project - .getTasks() - .register( - "apiInformation", - ApiInformationTask.class, - task -> { - task.getSources() - .value(project.provider(() -> mainSourceSet.getJava().getSrcDirs())); - task.getApiTxtFile().set(apiTxt); - task.getBaselineFile().set(project.file("baseline.txt")); - task.getOutputFile().set(outputFile); - task.getOutputApiFile().set(outputApiFile); - task.getUpdateBaseline().set(project.hasProperty("updateBaseline")); - }); - - TaskProvider generateApiTxt = - project - .getTasks() - .register( - "generateApiTxtFile", - GenerateApiTxtTask.class, - task -> { - task.getSources() - .value(project.provider(() -> mainSourceSet.getJava().getSrcDirs())); - task.getApiTxtFile().set(project.file("api.txt")); - task.getBaselineFile().set(project.file("baseline.txt")); - task.getUpdateBaseline().set(project.hasProperty("updateBaseline")); - }); - - TaskProvider docStubs = - project - .getTasks() - .register( - "docStubs", - GenerateStubsTask.class, - task -> - task.getSources() - .value(project.provider(() -> mainSourceSet.getJava().getSrcDirs()))); - project.getTasks().getByName("check").dependsOn(docStubs); - - android - .getLibraryVariants() - .all( - v -> { - if (v.getName().equals("release")) { - FileCollection jars = - v.getCompileConfiguration() - .getIncoming() - .artifactView( - config -> - config.attributes( - container -> - container.attribute( - Attribute.of("artifactType", String.class), - "android-classes"))) - .getArtifacts() - .getArtifactFiles(); - apiInfo.configure(t -> t.setClassPath(jars)); - generateApiTxt.configure(t -> t.setClassPath(jars)); - docStubs.configure(t -> t.setClassPath(jars)); - } - }); - } - - private static void setupStaticAnalysis(Project project, FirebaseLibraryExtension library) { - project.afterEvaluate( - p -> - project - .getConfigurations() - .all( - c -> { - if ("lintChecks".equals(c.getName())) { - for (String checkProject : - library.staticAnalysis.androidLintCheckProjects) { - project - .getDependencies() - .add("lintChecks", project.project(checkProject)); - } - } - })); - - project.getTasks().register("firebaseLint", task -> task.dependsOn("lint")); - Coverage.apply(library); - } - - private static String kotlinModuleName(Project project) { - - String fullyQualifiedProjectPath = project.getPath().replaceAll(":", "-"); - - return project.getRootProject().getName() + fullyQualifiedProjectPath; - } - - private static void configurePublishing( - Project project, FirebaseLibraryExtension firebaseLibrary, LibraryExtension android) { - android.publishing( - p -> { - p.singleVariant( - "release", - v -> { - v.withSourcesJar(); - return Unit.INSTANCE; - }); - }); - project - .getTasks() - .withType( - GenerateModuleMetadata.class, - task -> { - task.setEnabled(false); - }); - project.afterEvaluate( - p -> { - project.apply(ImmutableMap.of("plugin", "maven-publish")); - PublishingExtension publishing = - project.getExtensions().getByType(PublishingExtension.class); - publishing.repositories( - repos -> - repos.maven( - repo -> { - String s = project.getRootProject().getBuildDir() + "/m2repository"; - File file = new File(s); - repo.setUrl(file.toURI()); - repo.setName("BuildDir"); - })); - publishing.publications( - publications -> - publications.create( - "mavenAar", - MavenPublication.class, - publication -> { - publication.from( - project - .getComponents() - .findByName(firebaseLibrary.type.getComponentName())); - publication.setArtifactId(firebaseLibrary.artifactId.get()); - publication.setGroupId(firebaseLibrary.groupId.get()); - firebaseLibrary.applyPomCustomization(publication.getPom()); - })); - }); - } -} diff --git a/buildSrc/src/main/java/com/google/firebase/gradle/plugins/FirebaseLibraryPlugin.kt b/buildSrc/src/main/java/com/google/firebase/gradle/plugins/FirebaseLibraryPlugin.kt new file mode 100644 index 00000000000..c99a536d472 --- /dev/null +++ b/buildSrc/src/main/java/com/google/firebase/gradle/plugins/FirebaseLibraryPlugin.kt @@ -0,0 +1,125 @@ +// Copyright 2023 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 + +import com.android.build.gradle.LibraryExtension +import com.android.build.gradle.LibraryPlugin +import com.github.sherter.googlejavaformatgradleplugin.GoogleJavaFormatExtension +import com.github.sherter.googlejavaformatgradleplugin.GoogleJavaFormatPlugin +import com.google.firebase.gradle.plugins.LibraryType.ANDROID +import com.google.firebase.gradle.plugins.ci.device.FirebaseTestServer +import com.google.firebase.gradle.plugins.license.LicenseResolverPlugin +import java.io.File +import org.gradle.api.JavaVersion +import org.gradle.api.Project +import org.gradle.api.attributes.Attribute +import org.gradle.api.publish.tasks.GenerateModuleMetadata +import org.gradle.kotlin.dsl.apply +import org.gradle.kotlin.dsl.create +import org.gradle.kotlin.dsl.getByType +import org.gradle.kotlin.dsl.withType +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +class FirebaseLibraryPlugin : BaseFirebaseLibraryPlugin() { + + override fun apply(project: Project) { + project.apply() + project.apply() + project.apply() + project.extensions.getByType().toolVersion = "1.10.0" + + setupAndroidLibraryExtension(project) + + // reduce the likelihood of kotlin module files colliding. + project.tasks.withType { + kotlinOptions.freeCompilerArgs = listOf("-module-name", kotlinModuleName(project)) + } + + project.apply() + project.apply() + project.tasks.getByName("preBuild").dependsOn("updateGitSubmodules") + } + + private fun setupAndroidLibraryExtension(project: Project) { + val firebaseLibrary = + project.extensions.create("firebaseLibrary", project, ANDROID) + val android = project.extensions.getByType() + android.compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + + // In the case of and android library signing config only affects instrumentation test APK. + // We need it signed with default debug credentials in order for FTL to accept the APK. + android.buildTypes { getByName("release").signingConfig = getByName("debug").signingConfig } + + android.defaultConfig { + buildConfigField("String", "VERSION_NAME", "\"" + project.version + "\"") + } + + // see https://github.com/robolectric/robolectric/issues/5456 + android.testOptions.unitTests.all { + it.systemProperty("robolectric.dependency.repo.id", "central") + it.systemProperty("robolectric.dependency.repo.url", "https://repo1.maven.org/maven2") + it.systemProperty("javax.net.ssl.trustStoreType", "JKS") + } + + setupApiInformationAnalysis(project, android) + android.testServer(FirebaseTestServer(project, firebaseLibrary.testLab, android)) + setupStaticAnalysis(project, firebaseLibrary) + configurePublishing(project, firebaseLibrary, android) + } + + private fun setupApiInformationAnalysis(project: Project, android: LibraryExtension) { + val srcDirs = android.sourceSets.getByName("main").java.srcDirs + + val mainSourceSets = android.sourceSets.getByName("main") + val getKotlinDirectories = mainSourceSets::class.java.getDeclaredMethod("getKotlinDirectories") + val kotlinSrcDirs = getKotlinDirectories.invoke(mainSourceSets) + + val apiInfo = getApiInfo(project, kotlinSrcDirs as Set) + val generateApiTxt = getGenerateApiTxt(project, kotlinSrcDirs) + val docStubs = getDocStubs(project, srcDirs) + + project.tasks.getByName("check").dependsOn(docStubs) + android.libraryVariants.all { + if (name == "release") { + val jars = + compileConfiguration.incoming + .artifactView { + attributes { + attribute(Attribute.of("artifactType", String::class.java), "android-classes") + } + } + .artifacts + .artifactFiles + apiInfo.configure { classPath = jars } + generateApiTxt.configure { classPath = jars } + docStubs.configure { classPath = jars } + } + } + } + + private fun configurePublishing( + project: Project, + firebaseLibrary: FirebaseLibraryExtension, + android: LibraryExtension + ) { + android.publishing.singleVariant("release") { withSourcesJar() } + project.tasks.withType { isEnabled = false } + + configurePublishing(project, firebaseLibrary) + } +} diff --git a/buildSrc/src/main/java/com/google/firebase/gradle/plugins/GradleUtils.kt b/buildSrc/src/main/java/com/google/firebase/gradle/plugins/GradleUtils.kt index 219ed8b07ba..47c55b479bc 100644 --- a/buildSrc/src/main/java/com/google/firebase/gradle/plugins/GradleUtils.kt +++ b/buildSrc/src/main/java/com/google/firebase/gradle/plugins/GradleUtils.kt @@ -18,6 +18,7 @@ import java.io.File import org.gradle.api.Project import org.gradle.api.provider.Provider import org.gradle.api.tasks.Copy +import org.gradle.kotlin.dsl.apply fun Copy.fromDirectory(directory: Provider) = from(directory) { into(directory.map { it.name }) } @@ -26,7 +27,6 @@ fun Copy.fromDirectory(directory: Provider) = * Creates a file at the buildDir for the given [Project]. * * Syntax sugar for: - * * ``` * project.file("${project.buildDir}/$path) * ``` @@ -37,7 +37,6 @@ fun Project.fileFromBuildDir(path: String) = file("$buildDir/$path") * Maps a file provider to another file provider as a sub directory. * * Syntax sugar for: - * * ``` * fileProvider.map { project.file("${it.path}/$path") } * ``` @@ -50,9 +49,17 @@ fun Project.childFile(provider: Provider, childPath: String) = * any children. * * Syntax sugar for: - * * ``` * listFiles().orEmpty() * ``` */ fun File.listFilesOrEmpty() = listFiles().orEmpty() + +/** + * Syntax sugar for: + * ```kotlin + * pluginManager.apply(T::class) + * ``` + */ +inline fun org.gradle.api.plugins.PluginManager.`apply`(): Unit = + `apply`(T::class)