-
Notifications
You must be signed in to change notification settings - Fork 20
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
Conversation
We never really supported this anyway
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
Would you mind if I provided an updated license header though?
return rootProject.tasks.register(NAME, MissingIdentifiersAggregatorTask::class.java) { | ||
inputFiles.from(resolver.artifactView()) |
There was a problem hiding this comment.
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
input = projectPath, | ||
group = "skippy" | ||
) | ||
.publishWith(skippyAndroidTestProjectPublisher) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice
@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() } } |
There was a problem hiding this comment.
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
// Depending on the root project task by name alone is ok for Project Isolation | ||
test.dependsOn(UpdateRobolectricJarsTask.NAME) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh gradle 👨🍳 💋
* @see <a | ||
* href="https://docs.gradle.org/current/userguide/cross_project_publications.html#sec:variant-aware-sharing">Variant-aware | ||
* sharing of artifacts between projects</a> | ||
* @see <a | ||
* href="https://dev.to/autonomousapps/configuration-roles-and-the-blogging-industrial-complex-21mn">Gradle | ||
* configuration roles</a> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh that's kind of nice. it always annoyed me that having these on a single line was so long, but this looks readable even in github
fun publish(output: Provider<RegularFile>) { | ||
external.configure { outgoing.artifact(output) } | ||
} | ||
|
||
/** | ||
* Teach Gradle which thing produces the artifact associated with the external/consumable | ||
* configuration. | ||
*/ | ||
fun publishDirs(output: Provider<Directory>) { | ||
external.configure { outgoing.artifact(output) } | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you could always pull a Gradle and do fun publish(output: Any)
fun artifactView(): Provider<Set<File>> = | ||
internal.flatMap { configuration -> | ||
configuration.incoming.artifacts.resolvedArtifacts.map { resolvedArtifactResults -> | ||
resolvedArtifactResults.mapTo(mutableSetOf()) { it.file } | ||
} | ||
} | ||
|
||
fun addSubprojectDependencies(slackProperties: SlackProperties) { | ||
project.dependencies.apply { | ||
for (subproject in project.subprojects) { | ||
if (subproject.path == slackProperties.platformProjectPath) continue | ||
add(declarable.name, project.project(subproject.path)) | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
takes notes
internal interface SgpArtifacts : Named { | ||
companion object { | ||
@JvmField | ||
val SGP_ARTIFACTS_ATTRIBUTE: Attribute<SgpArtifacts> = | ||
Attribute.of("sgp.internal.artifacts", SgpArtifacts::class.java) | ||
} | ||
|
||
enum class Kind( | ||
val declarableName: String, | ||
val artifactName: String, | ||
) { | ||
SKIPPY_UNIT_TESTS("skippyUnitTests", "skippy-unit-tests"), | ||
SKIPPY_LINT("skippyLint", "skippy-lint"), | ||
SKIPPY_AVOIDED_TASKS("skippyAvoidedTasks", "skippy-avoided-tasks"), | ||
SKIPPY_ANDROID_TEST_PROJECT("skippyAndroidTestProject", "skippy-android-test-project"), | ||
SKIPPY_DETEKT("skippyDetekt", "skippy-detekt"), | ||
ANDROID_TEST_APK_DIRS("androidTestApkDirs", "android-test-apk-dirs"), | ||
DAGP_MISSING_IDENTIFIERS("dagpMissingIdentifiers", "dagp-missing-identifiers"), | ||
MOD_STATS_STATS_FILES("modStatsFiles", "mod-stats-files"), | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if I were to try to turn this into a library, what are your thoughts on how I'd handle this sort of thing? My project and your project have different artifact kinds, but the SgpArtifacts
type is baked into the resolver/publisher APIs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated the PR with a sketch of a more agnostic API, but it forgoes use of Named
and instead expects the artifact you give it to implement equals(). This takes a page out of AGP's artifact handling (i.e. like SingleArtifact
's subtypes). I think this works pretty well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This whole pattern seems really nice and ergonomic.
Yep will add |
Attribute.of("sgp.internal.artifacts", SgpArtifact::class.java) | ||
} | ||
|
||
data object SKIPPY_UNIT_TESTS : SgpArtifact("skippyUnitTests") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL data object
Gradle's upcoming Project Isolation feature prohibits direct access of other projects' tasks (including the root project). This means a lot of our plumbing for things like skippy, mod stats, and androidTest APKs are incompatible, as they all use a pattern of reaching into the rootProject to get aggregating tasks.
This PR updates all those implementations to use Gradle's artifacts APIs to publish artifacts from these subproject tasks and consume them via dependency configurations in the root project.
Resolves #701, and multiple others like it that I found along the way.
More reading: https://docs.gradle.org/current/userguide/cross_project_publications.html#sec:variant-aware-sharing