Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to using gradle artifact APIs for root project tasks #704

Merged
merged 27 commits into from
Jan 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,12 @@ tasks.withType<Detekt>().configureEach {

val ktfmtVersion = libs.versions.ktfmt.get()

val externalFiles = listOf("SkateErrorHandler", "MemoizedSequence").map { "src/**/$it.kt" }
val externalFiles = listOf(
"SkateErrorHandler",
"MemoizedSequence",
"Publisher",
"Resolver",
).map { "src/**/$it.kt" }

allprojects {
apply(plugin = "com.diffplug.spotless")
Expand Down
1 change: 1 addition & 0 deletions slack-plugin/best-practices-baseline.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"issues":[{"type":"get_subprojects","name":"getSubprojects","trace":{"trace":[{"owner":"slack/gradle/artifacts/Resolver$Companion","name":"interProjectResolver$default","descriptor":"(Lslack/gradle/artifacts/Resolver$Companion;Lorg/gradle/api/Project;Lorg/gradle/api/attributes/Attribute;Ljava/io/Serializable;Ljava/lang/String;ZILjava/lang/Object;)Lslack/gradle/artifacts/Resolver;","metadata":{"isTaskAction":false,"isVirtual":false}},{"owner":"slack/gradle/artifacts/Resolver$Companion","name":"interProjectResolver","descriptor":"(Lorg/gradle/api/Project;Lorg/gradle/api/attributes/Attribute;Ljava/io/Serializable;Ljava/lang/String;Z)Lslack/gradle/artifacts/Resolver;","metadata":{"isTaskAction":false,"isVirtual":false}},{"owner":"slack/gradle/artifacts/Resolver","name":"addSubprojectDependencies","descriptor":"(Lorg/gradle/api/Project;)V","metadata":{"isTaskAction":false,"isVirtual":false}},{"owner":"org/gradle/api/Project","name":"getSubprojects","descriptor":"()Ljava/util/Set;","metadata":{"isTaskAction":false,"isVirtual":false}}]}},{"type":"get_subprojects","name":"getSubprojects","trace":{"trace":[{"owner":"slack/stats/ModuleStatsTasks$configureRoot$1$1","name":"call","descriptor":"()Ljava/lang/Object;","metadata":{"isTaskAction":false,"isVirtual":false}},{"owner":"slack/stats/ModuleStatsTasks$configureRoot$1$1","name":"call","descriptor":"()Ljava/util/Map;","metadata":{"isTaskAction":false,"isVirtual":false}},{"owner":"org/gradle/api/Project","name":"getSubprojects","descriptor":"()Ljava/util/Set;","metadata":{"isTaskAction":false,"isVirtual":false}}]}},{"type":"get_subprojects","name":"getSubprojects","trace":{"trace":[{"owner":"slack/gradle/SlackRootPlugin","name":"apply","descriptor":"(Ljava/lang/Object;)V","metadata":{"isTaskAction":false,"isVirtual":false}},{"owner":"slack/gradle/SlackRootPlugin","name":"apply","descriptor":"(Lorg/gradle/api/Project;)V","metadata":{"isTaskAction":false,"isVirtual":false}},{"owner":"slack/gradle/SlackRootPlugin","name":"configureRootProject","descriptor":"(Lorg/gradle/api/Project;Lslack/gradle/SlackProperties;Lorg/gradle/api/provider/Provider;)V","metadata":{"isTaskAction":false,"isVirtual":false}},{"owner":"slack/gradle/tasks/AndroidTestApksTask$Companion","name":"register$slack_plugin","descriptor":"(Lorg/gradle/api/Project;)Lorg/gradle/api/tasks/TaskProvider;","metadata":{"isTaskAction":false,"isVirtual":false}},{"owner":"slack/gradle/artifacts/Resolver$Companion","name":"interProjectResolver$default","descriptor":"(Lslack/gradle/artifacts/Resolver$Companion;Lorg/gradle/api/Project;Lslack/gradle/artifacts/SgpArtifact;ZILjava/lang/Object;)Lslack/gradle/artifacts/Resolver;","metadata":{"isTaskAction":false,"isVirtual":false}},{"owner":"slack/gradle/artifacts/Resolver$Companion","name":"interProjectResolver","descriptor":"(Lorg/gradle/api/Project;Lslack/gradle/artifacts/SgpArtifact;Z)Lslack/gradle/artifacts/Resolver;","metadata":{"isTaskAction":false,"isVirtual":false}},{"owner":"slack/gradle/artifacts/Resolver$Companion","name":"interProjectResolver","descriptor":"(Lorg/gradle/api/Project;Lorg/gradle/api/attributes/Attribute;Ljava/io/Serializable;Ljava/lang/String;Z)Lslack/gradle/artifacts/Resolver;","metadata":{"isTaskAction":false,"isVirtual":false}},{"owner":"slack/gradle/artifacts/Resolver","name":"addSubprojectDependencies","descriptor":"(Lorg/gradle/api/Project;)V","metadata":{"isTaskAction":false,"isVirtual":false}},{"owner":"org/gradle/api/Project","name":"getSubprojects","descriptor":"()Ljava/util/Set;","metadata":{"isTaskAction":false,"isVirtual":false}}]}},{"type":"get_subprojects","name":"getSubprojects","trace":{"trace":[{"owner":"slack/gradle/SlackRootPlugin$configureRootProject$10","name":"execute","descriptor":"(Ljava/lang/Object;)V","metadata":{"isTaskAction":false,"isVirtual":false}},{"owner":"slack/gradle/SlackRootPlugin$configureRootProject$10","name":"execute","descriptor":"(Lorg/gradle/api/plugins/AppliedPlugin;)V","metadata":{"isTaskAction":false,"isVirtual":false}},{"owner":"slack/dependencyrake/MissingIdentifiersAggregatorTask$Companion","name":"register","descriptor":"(Lorg/gradle/api/Project;)Lorg/gradle/api/tasks/TaskProvider;","metadata":{"isTaskAction":false,"isVirtual":false}},{"owner":"slack/gradle/artifacts/Resolver$Companion","name":"interProjectResolver$default","descriptor":"(Lslack/gradle/artifacts/Resolver$Companion;Lorg/gradle/api/Project;Lslack/gradle/artifacts/SgpArtifact;ZILjava/lang/Object;)Lslack/gradle/artifacts/Resolver;","metadata":{"isTaskAction":false,"isVirtual":false}},{"owner":"slack/gradle/artifacts/Resolver$Companion","name":"interProjectResolver","descriptor":"(Lorg/gradle/api/Project;Lslack/gradle/artifacts/SgpArtifact;Z)Lslack/gradle/artifacts/Resolver;","metadata":{"isTaskAction":false,"isVirtual":false}},{"owner":"slack/gradle/artifacts/Resolver$Companion","name":"interProjectResolver","descriptor":"(Lorg/gradle/api/Project;Lorg/gradle/api/attributes/Attribute;Ljava/io/Serializable;Ljava/lang/String;Z)Lslack/gradle/artifacts/Resolver;","metadata":{"isTaskAction":false,"isVirtual":false}},{"owner":"slack/gradle/artifacts/Resolver","name":"addSubprojectDependencies","descriptor":"(Lorg/gradle/api/Project;)V","metadata":{"isTaskAction":false,"isVirtual":false}},{"owner":"org/gradle/api/Project","name":"getSubprojects","descriptor":"()Ljava/util/Set;","metadata":{"isTaskAction":false,"isVirtual":false}}]}}]}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ import org.gradle.api.tasks.PathSensitivity
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.UntrackedTask
import slack.gradle.artifacts.Resolver
import slack.gradle.artifacts.SgpArtifact
import slack.gradle.convertProjectPathToAccessor
import slack.gradle.property
import slack.gradle.util.mapToBoolean
Expand Down Expand Up @@ -459,7 +461,10 @@ internal abstract class MissingIdentifiersAggregatorTask : DefaultTask() {
const val NAME = "aggregateMissingIdentifiers"

fun register(rootProject: Project): TaskProvider<MissingIdentifiersAggregatorTask> {
val resolver =
Resolver.interProjectResolver(rootProject, SgpArtifact.DAGP_MISSING_IDENTIFIERS)
return rootProject.tasks.register(NAME, MissingIdentifiersAggregatorTask::class.java) {
inputFiles.from(resolver.artifactView())

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh I like this, I will probably steal it

outputFile.set(
rootProject.layout.buildDirectory.file("rake/aggregated_missing_identifiers.txt")
)
Expand Down
21 changes: 0 additions & 21 deletions slack-plugin/src/main/kotlin/slack/gradle/GlobalConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,11 @@
package slack.gradle

import org.gradle.api.Project
import org.gradle.api.tasks.TaskProvider
import org.gradle.jvm.toolchain.JvmVendorSpec
import slack.gradle.tasks.robolectric.UpdateRobolectricJarsTask

/** Registry of global configuration info. */
public class GlobalConfig
private constructor(
internal val updateRobolectricJarsTask: TaskProvider<UpdateRobolectricJarsTask>?,
internal val kotlinDaemonArgs: List<String>,
internal val errorProneCheckNamesAsErrors: List<String>,
internal val affectedProjects: Set<String>?,
Expand All @@ -34,10 +31,7 @@ private constructor(
operator fun invoke(project: Project): GlobalConfig {
check(project == project.rootProject) { "Project is not root project!" }
val globalSlackProperties = SlackProperties(project)
val robolectricJarsDownloadTask =
project.createRobolectricJarsDownloadTask(globalSlackProperties)
return GlobalConfig(
updateRobolectricJarsTask = robolectricJarsDownloadTask,
kotlinDaemonArgs = globalSlackProperties.kotlinDaemonArgs.split(" "),
errorProneCheckNamesAsErrors =
globalSlackProperties.errorProneCheckNamesAsErrors?.split(":").orEmpty(),
Expand All @@ -63,18 +57,3 @@ private constructor(
}
}
}

private fun Project.createRobolectricJarsDownloadTask(
slackProperties: SlackProperties
): TaskProvider<UpdateRobolectricJarsTask>? {
if (slackProperties.versions.robolectric == null) {
// Not enabled
return null
}

check(isRootProject) {
"Robolectric jars task should only be created once on the root project. Tried to apply on $name"
}

return UpdateRobolectricJarsTask.register(this, slackProperties)
}
10 changes: 10 additions & 0 deletions slack-plugin/src/main/kotlin/slack/gradle/GradleExt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -321,3 +321,13 @@ internal inline fun <reified T : Any> Project.serviceOf(): T =
(this as ProjectInternal).services.get()

internal inline fun <reified T : Any> ServiceRegistry.get(): T = this[T::class.java]!!

@Suppress("UNCHECKED_CAST")
internal inline fun <reified T : Task> TaskContainer.registerOrConfigure(
taskName: String,
crossinline configureAction: T.() -> Unit
): TaskProvider<T> =
when (taskName) {
in names -> named(taskName) as TaskProvider<T>
else -> register(taskName, T::class.java)
}.apply { configure { configureAction() } }
Comment on lines +325 to +333

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a neat pattern

2 changes: 0 additions & 2 deletions slack-plugin/src/main/kotlin/slack/gradle/SlackBasePlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.MinimalExternalModuleDependency
import org.gradle.api.provider.Provider
import slack.gradle.tasks.CoreBootstrapTask
import slack.stats.ModuleStatsTasks

/**
Expand All @@ -43,7 +42,6 @@ internal class SlackBasePlugin : Plugin<Project> {
target.getVersionsCatalogOrNull() ?: error("SGP requires use of version catalogs!")
val slackTools = target.slackTools()
StandardProjectConfigurations(slackProperties, versionCatalog, slackTools).applyTo(target)
CoreBootstrapTask.configureSubprojectBootstrapTasks(target)

// Configure Gradle's test-retry plugin for insights on build scans on CI only
// Thinking here is that we don't want them to retry when iterating since failure
Expand Down
7 changes: 7 additions & 0 deletions slack-plugin/src/main/kotlin/slack/gradle/SlackRootPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import slack.gradle.tasks.InstallCommitHooksTask
import slack.gradle.tasks.KtLintDownloadTask
import slack.gradle.tasks.KtfmtDownloadTask
import slack.gradle.tasks.SortDependenciesDownloadTask
import slack.gradle.tasks.robolectric.UpdateRobolectricJarsTask
import slack.gradle.util.JsonTools
import slack.gradle.util.Thermals
import slack.gradle.util.ThermalsData
Expand Down Expand Up @@ -92,6 +93,7 @@ internal class SlackRootPlugin @Inject constructor(private val buildFeatures: Bu
} else {
project.logger.debug("Skippy is disabled")
}

SlackTools.register(
project = project,
logThermals = logThermals,
Expand Down Expand Up @@ -145,6 +147,11 @@ internal class SlackRootPlugin @Inject constructor(private val buildFeatures: Bu
UnitTests.configureRootProject(project)
ModuleStatsTasks.configureRoot(project, slackProperties)
ComputeAffectedProjectsTask.register(project, slackProperties)
// Register robolectric jar downloads if requested
slackProperties.versions.robolectric?.let {
UpdateRobolectricJarsTask.register(project, slackProperties)
}

val scanApi = ScanApi(project)
if (slackProperties.applyCommonBuildTags) {
project.configureBuildScanMetadata(scanApi)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,19 +57,21 @@ import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.internal.KaptGenerateStubsTask
import org.jetbrains.kotlin.gradle.plugin.KaptExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinBasePlugin
import org.jetbrains.kotlin.gradle.utils.named
import slack.dependencyrake.MissingIdentifiersAggregatorTask
import slack.dependencyrake.RakeDependencies
import slack.gradle.AptOptionsConfig.AptOptionsConfigurer
import slack.gradle.AptOptionsConfigs.invoke
import slack.gradle.avoidance.ComputeAffectedProjectsTask
import slack.gradle.artifacts.Publisher
import slack.gradle.artifacts.SgpArtifact
import slack.gradle.dependencies.BuildConfig
import slack.gradle.dependencies.SlackDependencies
import slack.gradle.lint.DetektTasks
import slack.gradle.lint.LintTasks
import slack.gradle.permissionchecks.PermissionChecks
import slack.gradle.tasks.AndroidTestApksTask
import slack.gradle.tasks.CheckManifestPermissionsTask
import slack.gradle.tasks.SimpleFileProducerTask
import slack.gradle.tasks.publishWith
import slack.gradle.tasks.robolectric.UpdateRobolectricJarsTask
import slack.gradle.util.booleanProperty
import slack.gradle.util.configureKotlinCompilationTask
import slack.gradle.util.setDisallowChanges
Expand Down Expand Up @@ -231,13 +233,9 @@ internal class StandardProjectConfigurations(
configure<DependencyAnalysisSubExtension> {
registerPostProcessingTask(rakeDependencies)
}
val aggregator =
project.rootProject.tasks.named<MissingIdentifiersAggregatorTask>(
MissingIdentifiersAggregatorTask.NAME
)
aggregator.configure {
inputFiles.from(rakeDependencies.flatMap { it.missingIdentifiersFile })
}
val publisher =
Publisher.interProjectPublisher(project, SgpArtifact.DAGP_MISSING_IDENTIFIERS)
publisher.publish(rakeDependencies.flatMap { it.missingIdentifiersFile })
}
}
}
Expand Down Expand Up @@ -449,16 +447,13 @@ internal class StandardProjectConfigurations(
slackProperties: SlackProperties,
) {
val javaVersion = JavaVersion.toVersion(jvmTargetVersion)
val computeAffectedProjectsTask =
project.rootProject.tasks.named(
ComputeAffectedProjectsTask.NAME,
ComputeAffectedProjectsTask::class.java
)
// Contribute these libraries to Fladle if they opt into it
val androidTestApksAggregator =
project.rootProject.tasks.named(AndroidTestApksTask.NAME, AndroidTestApksTask::class.java)
val androidTestApksPublisher =
Publisher.interProjectPublisher(project, SgpArtifact.ANDROID_TEST_APK_DIRS)
val projectPath = project.path
val isAffectedProject = slackTools.globalConfig.affectedProjects?.contains(projectPath) ?: true
val skippyAndroidTestProjectPublisher =
Publisher.interProjectPublisher(project, SgpArtifact.SKIPPY_ANDROID_TEST_PROJECT)

val commonComponentsExtension =
Action<AndroidComponentsExtension<*, *, *>> {
Expand Down Expand Up @@ -505,12 +500,22 @@ internal class StandardProjectConfigurations(
val isAndroidTestEnabled = variant is HasAndroidTest && variant.androidTest != null
if (isAndroidTestEnabled) {
if (!excluded && isAffectedProject) {
computeAffectedProjectsTask.configure { androidTestProjects.add(projectPath) }
// Note this intentionally just uses the same task each time as they always produce
// the same output
SimpleFileProducerTask.registerOrConfigure(
project,
name = "androidTestProjectMetadata",
description =
"Produces a metadata artifact indicating this project path produces an androidTest APK.",
input = projectPath,
group = "skippy"
)
.publishWith(skippyAndroidTestProjectPublisher)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice

if (isLibraryVariant) {
(variant as LibraryVariant).androidTest?.artifacts?.get(SingleArtifact.APK)?.let {
apkArtifactsDir ->
// Wire this up to the aggregator
androidTestApksAggregator.configure { androidTestApkDirs.from(apkArtifactsDir) }
// Wire this up to the aggregator. No need for an intermediate task here.
androidTestApksPublisher.publishDirs(apkArtifactsDir)
}
}
} else {
Expand Down Expand Up @@ -588,12 +593,12 @@ internal class StandardProjectConfigurations(
//
// Note that we can't configure this to _just_ be enabled for robolectric projects
// based on dependencies unfortunately, as the task graph is already wired by the
// time
// dependencies start getting resolved.
// time dependencies start getting resolved.
//
slackTools.globalConfig.updateRobolectricJarsTask?.let {
slackProperties.versions.robolectric?.let {
logger.debug("Configuring $name test task to depend on Robolectric jar downloads")
test.dependsOn(it)
// Depending on the root project task by name alone is ok for Project Isolation
test.dependsOn(UpdateRobolectricJarsTask.NAME)
Comment on lines +600 to +601

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh gradle 👨‍🍳 💋

}

// Necessary for some OkHttp-using tests to work on JDK 11 in Robolectric
Expand Down
Loading