Gradle Release System Task - Calling uploadArchives on subprojects - continuous-integration

In order to release my system, I am creating a releaser project that calls uploadArchives for a number of other projects.
In my project I have the following files:
settings.gradle
include '../proj-a', '../proj-b'
build.gradle
task releaseSystem() {
// what goes here?
}
What should the contents of the releaseSystem task be such that I can call gradle releaseSystem and have it run uploadArchives for each of my sub projects?
I've tried a number of options, but none have been successful thus far.
Thank you for any insights you can provide.
ANSWER
I'm continually impressed with the graceful solutions gradle provides to my problems. Here's my final solution (as Peter pointed out below):
settings.gradle
include 'proj-a', 'proj-b'
project (':proj-a').projectDir = new File(settingsDir, '../proj-a')
project (':proj-b').projectDir = new File(settingsDir, '../proj-b')
build.gradle
task releaseSystem() {
dependsOn {
[
subprojects.build,
subprojects.uploadArchives
]
}
}
Note, that since my repository is a maven repository, when I originally included '../proj-a' in my settings.gradle, it produced poms with artifactId ../proj-a which was invalid. I had to change my settings.gradle to the format above for the system to put the poms together correctly and for the uploadArchives task to complete successfully.

Assuming all subprojects have an uploadArchives task:
task releaseSystem {
dependsOn { subprojects.uploadArchives }
}
Note that this won't run the subprojects' tests.

Related

Gradle - custom task to execute all GenerateMavenPom tasks

I want to write a Gradle task to share among all my subprojects. This task finds all other tasks inside the subproject where it is called that have type "GenerateMavenPom" and executes those tasks.
By doing this, my subprojects can define any Maven publications that they wish, and I can execute gradle with a single task like "gradle generateMavenPomFiles" to create the pom.xml without knowing the individual publication types in each subproject. Why? Because the Maven plugin creates publication tasks whose names depend on the publication type.
Inside my subprojects block in the root build.gradle file I have, passing subproject as the closure delegate:
task generateMavenPomFiles << {
model {
TaskCollection<GenerateMavenPom> pomTasks = subproject.tasks.matching { t -> t.TASK_TYPE.equals("GenerateMavenPom") }
if (pomTasks != null) {
pomTasks.each { pomTask -> pomTask.execute }
}
}
}
I have accessed the Maven publishing tasks inside the model block as according to the plugin doc:
The “maven-publish” plugin leverages some experimental support for
late plugin configuration, and any GenerateMavenPom tasks will not be
constructed until the publishing extension is configured. The simplest
way to ensure that the publishing plugin is configured when you
attempt to access the GenerateMavenPom task is to place the access
inside a model block...
Inside my subprojects I have Maven publications defined like this:
publishing {
publications {
mavenCustom(MavenPublication) {
artifacts = someArtifactTask.archivePath
groupId = someGroupId
artifactId = someArtifactId
version = someVersion
}
}
}
Of course, "gradle generateMavenPomFiles" doesn't work. The task executes on each subproject but I don't see the actual Maven POM tasks created by the plugin being invoked.
I'm fairly new to Gradle + Groovy, so perhaps I have misunderstood something, or my logic is just wrong.
Any help is greatly appreciated!
you can do this with the following snippet:
task runAllGenerateMavenPomTasks {
dependsOn tasks.withType(GenerateMavenPom)
}

Gradle's publishToMavenLocal task is not executed correctly

I'm trying to create a gradle based multi-module project. There is also an project that contains different gradle scripts that enables pluggable build configurations. One of those scripts is for publishing artifacts to maven repository. This is the content of that script:
apply plugin: 'maven-publish'
configure(subprojects.findAll()) {
if (it.name.endsWith('web')) {
publishing {
publications {
mavenWeb(MavenPublication) {
from components.web
}
}
}
} else {
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
}
}
}
}
}
build.dependsOn publishToMavenLocal
This script is included in the build gradle file of other project.
apply from: '../../food-orders-online-main/artifact-publish.gradle'
When I run build task it always shows that publishToMavenLocal task is up to date and I cannot find the artifacts in the local repository. Am I doing something wrong?
By adapting answer from here, it works for me.
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
}
}
repositories {
mavenLocal()
}
}
I think this could be a manifestation of a bug with gradle, that modules can lose the publishMavenJavaPublicationToMavenLocal task when they are depended upon in a certain way.
If gradle determines that there is no publishMavenJavaPublicationToMavenLocal task for a module then the publishToMavenLocal task will always report that it is up to date.
The specific case I have found occurs in a multimodule setup, with multiple levels of nested modules. It can be summarised as follows, where shared:domain loses its publishMavenJavaPublicationToMavenLocal when depended upon by A
root
root gradle build file
->A
own gradle build file with dependency on shared:domain
-> shared
gradle build file for shared modules
-> shared:domain
-> shared:B
I have created a small example project demonstrating this behaviour available here - https://github.com/piersy/Gradle2MavenPublishBug
I have also logged a bug with gradle here - http://forums.gradle.org/gradle/topics/the-publishmavenjavapublicationtomavenlocal-task-disappears-from-a-project-when-that-project-is-depended-upon-in-a-specific-way
For now the workarounds I have found are to
Remove A's dependency on shared:domain
Make A a submodule with its configuration specified in its parent module build file
Give shared:domain its own gradle build file

How to let gradle build dependent sub-project first when using non-compile dependencies

How can I tell gradle to build a certain sub-projects first, even though I don't have a compile dependency to them? How are project dependencies handled internally?
Example:
settings.gradle:
include "app", "schema"
build.gradle:
allprojects {
apply plugin: 'java'
}
schema/build.gradle:
// empty
app/build.gradle:
configurations {
schemas
}
dependencies {
schemas project(":schema")
schemas "org.example:example-schema:1.0"
}
task extractSchema(type: Copy) {
from {
configurations.schemas.collect { zipTree(it) }
}
into "build/schemas"
}
//compileJava.dependsOn extractSchema
And when running:
$ cd app
$ gradle extractSchema
I get:
Cannot expand ZIP 'schema/build/libs/schema.jar' as it does not exist.
What I want is that gradle automatically builds all sub-projectes defined in the configurations.schemas dependency list first (if they are projects).
Note: I want to be able to share the extractSchema task across multiple gradle projects, so it is important that gradle takes the list of sub-project to be built first from the configurations.schemas list.
Thanks
Gradle build order is never on the project level, but always on the task level. from(configuration.schemas) would infer task dependencies automatically, but in case of from(configuration.schemas.collect { ... }), this doesn't work because the resulting value is no longer Buildable. Adding dependsOn configurations.schemas should solve the problem.

Gradle dependency to project in buildscript

Trying to get my head around if it is possible to use Tasks from other projects in Gradle. Let's say ProjectB is a project with src/main/groovy containing com.MyTask, having parent ProjectA
In build.gradle in ProjectC, also having parent ProjectA:
buildscript {
dependencies{
project(':ProjectB')
}
}
That seems to be legit, because introdusing a typo in "project(:'ProjectB')" fails hard. What also fails is introducing this line:
import com.MyTask
Is project-references not valid in buildscript closure? Also tried moving com.MyTask to buildSrc/src/main/groovy with the same amount of success.
The solution which worked for me was to make "com.MyTask" available both at configurationtime and in sources.
ProjectA(the parent) got this added to buildSrc/build.gradle's sourceSets:
sourceSets{
main{
groovy{
srcDir 'ProjectB/src/main/groovy'
}
}
}
Now ProjectC and all other projects can use MyTask. At the same time it is bundled with the final jar of ProjectB.
The issue has also been discussed thoroughly between between Adam Murdoch, Luke Daley and Steve Ebersole: http://gradle.1045684.n5.nabble.com/buildSrc-as-a-regular-project-td5677255.html
Edit: It was smarter manipulating parent buildSrc than the standalone project. That way IntelliJ is happy-go-lucky.
From Gradle documentation 15.4. Adding dependencies to a task:
Example 15.13. Adding dependency on task from another project
build.gradle
project('projectA') {
task taskX(dependsOn: ':projectB:taskY') << {
println 'taskX'
}
}
project('projectB') {
task taskY << {
println 'taskY'
}
}

Gradle batch task that invokes subproject and other tasks in order

I am writing gradle 1.4 build file for multimodule project. So there is root build.gradle that defines something like:
subprojects {
apply plugin: 'java'
...
which defines build task for all submodules. Submodules are included in settings.gradle and each module has its build file with defined dependencies.
Everything by-the-book, so far:) Now, in the main build file I've added some additional project-scope tasks, like: aggregateJavadoc (collects all javadocs into one) or bundleJar (creates bundle jar from all classes), etc. Each on works when invoked manually.
Now I need a task release that will
build all submodules (as invoked from command line - meaning, i dont want to manually write execute() for each submodule)
invoke additional tasks (using execute() I presume).
I tried dependsOn but the order of listed tasks is not followed. Also, dependent modules seems to be executed after release task execution. I tried several other ideas and failed.
Question: what would be the best way to create such batch task, that has to invoke something on all submodules and additionally to perform some more tasks? What would be the best gradle-friendly solution? Thanx!
It happened that this can be solved with simple dependency management.
So, we have many modules. Now, lets create additional tasks that depends on modules being build:
task aggregateJavadoc(type: Javadoc) {
dependsOn subprojects.build
task bundleJar(type: Jar) {
dependsOn subprojects.build
Finally, our release task would simply look like this:
task release() {
dependsOn subprojects.build
dependsOn aggregateJavadoc
dependsOn bundleJar
...
}
This will build subprojects first; not because it is listed first, but because additional tasks depends on building. Order of additional task is not important. This make sense the most to me.
EDIT
if one of your subprojects (i.e. modules) is non-java module, then you will have a problem building this project. What I do is to group submodules, like this:
def javaModules() {
subprojects.findAll {it.name.contains('jodd-')}
}
and then instead to refer to subprojects, use javaModules everywhere! For example:
configure(javaModules()) {
apply plugin: 'java'
...
and
task prj {
dependsOn javaModules().build
}
btw, I am using this 'dummy' task prj for dependsOn on all those additional projects that depends on building, to prevent repeating.

Resources