Gradle java multimodule project - extract sources jar

Hello.

I have 2 gradle projects:

  1. common
  2. app

Nowdays these projects are build indipedently, so commons is deployed to nexus and app uses it from nexus.

I try to create gradle multimodule project, where these 2 projects will build together. Nothing special, settings.gradle with 2 includes.

Everything works fine except sources extraction in ‘app’ project:

This is how it works when using nexus -sources artifact:

extractSourcesArtifacts "foo:commons:${version}:sources"
...
task extractCommonsSources(type: Copy, dependsOn: compileJava) {
    from zipTree( configurations.extractSourcesArtifacts.singleFile)
    into "$buildDir/dependency-sources"
}

But I would like to change dependency on commons to project() dependency:

extractSourcesArtifacts project(":commons") // how to specify :sources?

… it extracts main jar not -sources jar.

I can’t find the way/syntax/whatever how to specify ‘:sources’ using project() dependency.

Anyone?
Thank you
d

Assuming you are using common not only in that project but continue to use it in other projects too, you should probably not try to use it as subproject of a multi-project build like that, but instead use it as composite build. Usually you can get the sources artifact for a dependency using an artifact resolution query, but it is to be tried whether this works when having the dependency as included build, never tried that.

Hmm, I didn’t described my usecase properly.

Yes, ‘common’ project is used across multiple other projects, that are build indepedently on jenkins. But during local development cycle it is uncomfortable to develop across services and common project, because every change in common must be released (as a snapshot), or deployed to maven local.

So I would like to change build process so when developing locally, with all projects cloned in a single folder, I would like to use project() dependencies and edit sources over all projects at once. Jenkins build should not be affected at all. So I created parent ‘project’ (which is not in git nor jenkins build), used only to “couple” my repos together. In gradle.properties in root project I define variable “local_build=true”, and then in every ‘subproject’ I have following:

if( project?.properties?.parent?.properties?.local_dependencies) {
  // project() dependencies
} else {
  // jenkins-released dependencies
}

To get back to the root of my question (extract ‘common’ sources into ‘app’ folder, I found following solution:

In ‘common’:

configurations.create('sourcesJar')
artifacts.add('sourcesJar', sourcesJar)

In ‘app’:
extractSourcesArtifacts project (path: ':common', configuration: 'sourcesJar')

And that’s it. Thank you

Again, you should not do that.
Do not use a project sometimes as part of one build and sometimes as part of another build.

As I said, your use-case is exactly what composite builds are invented for.
You don’t even need to replace binary dependencies (group:module:version) by project dependencies.
You just use a composite build, by including the common build in your project,
either via commandline parameter, or via settings script code includeBuild and the latter could even be inside an if like if property is set or if project exists there, and your binary dependencies are automatically substituted by a subbuild.

https://docs.gradle.org/current/userguide/composite_builds.html

Hmm, that looks promising, but no luck with that because original question is still in a place.

‘root’ project:

includeBuild 'commons'
includeBuild 'app'

app reverted to original dependencies (no project()):

implementation("foo:commons:${commonsVersion}")
extractSourcesArtifacts("foo:commons:${commonsVersion}:sources")  // this doesn't work in composite build

Maybe it is one of documented limitations of composite build [’ Cases where composite build substitutions won’t work - When a configuration other than default is published’]?

thank you

As the other build is also a Gradle build, just use variant-aware resolution.

configurations {
    extractSourcesArtifacts
        canBeConsumed = false
        attributes {
            attribute(DocsType.DOCS_TYPE_ATTRIBUTE, objects.named(DocsType.SOURCES))
        }
    }
}
dependencies {
    extractSourcesArtifacts("foo:commons:${commonsVersion}")
}

Or if you want all dependencies that are in the runtime classpath:

configurations {
    extractSourcesArtifacts
        canBeConsumed = false
        extends(runtimeClasspath)
        attributes {
            attribute(DocsType.DOCS_TYPE_ATTRIBUTE, objects.named(DocsType.SOURCES))
        }
    }
}