Henning Habighorst
04/02/2025, 5:55 PMabstract class VersionExportTask : DefaultTask() {
@get:OutputFile
abstract val targetFile: RegularFileProperty
@TaskAction
fun export() {
if (project != project.rootProject) {
return
}
val file = targetFile.get().asFile
file.parentFile.mkdirs()
project.subprojects.forEach {
file.writeText("${it.name}=${it.version}")
}
}
}
Vampire
04/02/2025, 6:00 PMproject
at task execution time is deprecated.
And with CC you can of course not do this, as the configuration model is not available at task execution time.
So, no, this is not "so simple" as one might assume. 😄Vampire
04/02/2025, 6:02 PMVampire
04/02/2025, 6:03 PMephemient
04/02/2025, 6:07 PMVampire
04/02/2025, 6:08 PMThomas Broyer
04/02/2025, 6:14 PMHenning Habighorst
04/02/2025, 6:26 PMVampire
04/02/2025, 7:38 PMHenning Habighorst
04/02/2025, 9:08 PMfun createConfiguration(): Configuration {
if (project != project.rootProject) {
val exportProjectVersionConfiguration: Configuration by configurations.creating {
isCanBeResolved = false
}
return exportProjectVersionConfiguration
}
val exportProjectVersionConfiguration: Configuration by configurations.creating {
isCanBeConsumed = false
}
return exportProjectVersionConfiguration
}
fun createTask(configuration: Configuration): TaskProvider<Task> {
if (project != project.rootProject) {
return tasks.register("exportProjectVersion") {
val versionExportFile = layout.buildDirectory.file("exportProjectVersion.txt")
outputs.file(versionExportFile)
doLast {
versionExportFile.get().asFile.writeText("${project.name}=${project.version}")
}
}
}
return tasks.register("exportProjectVersion") {
val sharedFiles: FileCollection = configuration
inputs.files(sharedFiles)
doFirst {
val content = sharedFiles.joinToString(separator = "\n", transform = { file -> file.readText() })
logger.lifecycle("Shared file contains the text: '{}'", content)
}
}
}
val exportProjectVersionConfiguration = createConfiguration()
val exportProjectVersionTask = createTask(exportProjectVersionConfiguration)
if (project != project.rootProject) {
artifacts {
add(exportProjectVersionConfiguration.name, exportProjectVersionTask)
}
} else {
dependencies {
project.subprojects.forEach {
exportProjectVersionConfiguration(project(it.path, exportProjectVersionConfiguration.name))
}
}
}
I just stuffed this into a convention plugin script, as this is configured in all relevant projects and I could apply it at the root level.
It works and does the job...
https://docs.gradle.org/8.13/userguide/upgrading_version_7.html#task_project
leads to https://docs.gradle.org/8.13/userguide/configuration_cache.html#config_cache:requirements:use_project_during_execution
In createTask
I still call project.name
and project.version
which is a nono as Vampire already explained. That's the missing piece of the puzzle for me...
could you create a configuration that depends on all subprojects, try to resolve it, filter for local project component identifiers, and print their versions
If I'm not mistaken, the approach means that I can "fish" somehow out of the configuration the project component identifiers and the version... Which would imply that I don't access the projects anymore, as I just access the configuration.
Has someone maybe a code snippet, Gradle link or sth like that or an example?
Thanks in advance for your patience!Vampire
04/02/2025, 9:18 PMproject.
access at execution time.
Besides that you also missed to declare them as inputs so your up-to-date checks would be broken.
Use Property<String>
for name and version or one for the whole line, declare it as input property and query it at execution time, and the approach should work I think.Vampire
04/02/2025, 9:21 PMResolutionResult
API from https://docs.gradle.org/current/userguide/dependency_resolution_basics.html.Henning Habighorst
04/02/2025, 9:28 PMinputs.property("projectName", project.name)
inputs.property("projectVersion", project.version)
it appears to be too easy to be true. XDVampire
04/02/2025, 9:29 PMVampire
04/02/2025, 9:30 PMProperty<String>
IS a Provider<String>
, so where is the problem?
You create a property, use a provider { }
in which you get name / version so it is read as late as possible, give it to inputs.property
and get()
it at execution time.
Which part do you have problems with?Vampire
04/02/2025, 9:31 PMHenning Habighorst
04/02/2025, 9:37 PMHenning Habighorst
04/02/2025, 9:37 PM