Publishing subprojects in sequence with maven-publish plugin

I have a setup where the maven-publish plugin is applied to the root project and publications are defined for sub-projects (say a, b, and c). I need to publish projects a, b, c (in that order), when project a is published.

I tried to establish a finalizedBy relationship between the publish tasks but the “downstream” tasks are always reported as being UP-TO-DATE and not executed. I also tried to force UP-TO-DATE to false in projects b and c, with no success.

In project a:

publish {
    finalizedBy(
            project(':b').tasks['publish'],
            project(':c').tasks['publish']
    )
}

In projects b and c (same result if I don’t customize the publish task):

publish {
    // Trying to force UP-TO-DATE to false
    outputs.upToDateWhen {false}
    onlyIf {true}
}

Execution looks like

> Task :a:publish
> Task :b:publish UP-TO-DATE
> Task :c:publish UP-TO-DATE

Only the artifacts of a are published, though, even when running it with --rerun-tasks. Is it a limitation of the maven-publish plugin or am I taking the wrong approach? I get similar results when trying to establish the dependency with dependsOn. I am using Gradle 5.5.1

Hello,

The publish task is not the task doing the actual publication. The task sending artifacts to the repository is named publish<PublicationName>To<RepositoryName>. The publish task has only a dependency on that task. It is the same as the assemble task: it is not the one that assembles (compile sources or archive binaries), it is simply a shortcut.

Note that coupling tasks between projects may have consequences on Configuration time and execution time. Note also the warning before the example #5 in Authoring Tasks.

If you decide to ignore these warnings and couple your tasks, then, maybe one of the most harmless way to do it would be:

rootProject/build.gradle:

/* In production code, I'd rather apply a convention plugin defined in buildSrc to subprojects
   to avoid coupling, but for the sake of brevity I'll use the subprojects idiom */
subprojects {
	apply plugin: 'java-library'
	apply plugin: 'maven-publish'

	publishing {
		repositories {
			maven {
				url = "file:///${project.rootProject.buildDir}/repo"
				name = "drive"
			}
		}
		publications {
			jar(MavenPublication) {
				from components.java
			}
		}
	}
}

Then to make sure that publications of foo happens before publications of bar, in bar/build.gradle:

tasks.withType(PublishToMavenRepository).configureEach { t ->
    t.mustRunAfter(provider { project(':foo').tasks.withType(PublishToMavenRepository) })
}

Term:

/tmp/dummy$ gradle :bar:publish :foo:publish -m
[...]
:foo:generateMetadataFileForJarPublication SKIPPED
:foo:generatePomFileForJarPublication SKIPPED
:foo:publishJarPublicationToDriveRepository SKIPPED
:bar:publishJarPublicationToDriveRepository SKIPPED
:bar:publish SKIPPED
:foo:publish SKIPPED

Should you value having uncoupled projects at configuration and runtime, then a third party tool ordering the task execution will be necessary like a shell script, or a Jenkins pipeline, for instance:

node {
    stage('publishing a') {
        sh 'gradle :a:publish'
    }
    stage('publishing b') {
        sh 'gradle :b:publish'
    }
    stage('publishing c') {
        sh 'gradle :c:publish'
    }
}