Gradle Artifactory Plugin - How to publish artifacts from multiple modules in a project?
Asked Answered
A

3

11

I have a project which has a SharedCode (Java) module and secondly an Android (Android library) module which depends on the SharedCode module. I want to publish a jar artifact from the SharedCode module and an aar artifact from the Android module. I can't figure out how to compose my build.gradle files so that both modules publish to Artifactory when the artifactoryPublish task is run. At the moment only the SharedCode module publishes its artifact to Artifactory.

My build.gradle files are as below. Note that the maven-publish aspect of my build.gradle files appears to be correct because when I run the publishToMavenLocal task I see the artifacts from both modules in my local Maven folder (i.e. '~/.m2/repository').

Firstly, the build.gradle file in my SharedCode module is as follows:

apply plugin: 'java'
apply plugin: 'maven-publish'
apply plugin: 'com.jfrog.artifactory'

group = "${projectGroupId}"
version = "${projectVersionName}"

dependencies {
    compile 'com.google.guava:guava:18.0'
}

publishing {
    publications {
        SharedCode(MavenPublication) {
            groupId "${projectGroupId}"
            artifactId 'SharedCode'
            version "${projectVersionName}"
            from components.java
        }
    }
}

artifactory {
    contextUrl = "${artifactory_url}"
    publish {
        repository {
            repoKey = 'libs-release-local'
            username = "${artifactory_username}"
            password = "${artifactory_password}"
        }
        defaults {
            publications('SharedCode')
            publishArtifacts = true
            properties = ['qa.level': 'basic', 'dev.team': 'core']
            publishPom = true
        }
    }
}

Secondly, the build.gradle file in my Android module is as follows:

apply plugin: 'com.android.library'
apply plugin: 'maven-publish'
apply plugin: 'com.jfrog.artifactory'

group = "${projectGroupId}"
version = "${projectVersionName}"

android {
    // android stuff here...
}

dependencies {
    compile project(':SharedCode')
}

publishing {
    publications {
        Android(MavenPublication) {
            groupId "${projectGroupId}"
            artifactId 'Android'
            version "${projectVersionName}"
            artifact "$buildDir/outputs/aar/Android-release.aar"
        }
    }
}

artifactory {
    contextUrl = "${artifactory_url}"
    publish {
        repository {
            repoKey = 'libs-release-local'
            username = "${artifactory_username}"
            password = "${artifactory_password}"
        }
        defaults {
            publications('Android')
            publishArtifacts = true
            properties = ['qa.level': 'basic', 'dev.team': 'core']
            publishPom = true
        }
    }
}

If I run the artifactoryPublish task at the root, project level or at the SharedCode module level then I see output as follows:

18:23:38: Executing external task 'artifactoryPublish'...
Publication named 'SharedCode' does not exist for project ':Android' in task ':Android:artifactoryPublish'.
:SharedCode:generatePomFileForSharedCodePublication
:SharedCode:artifactoryPublish
Deploying artifact: http://localhost:8081/artifactory/libs-release-local/com/mycompany/sdk/SharedCode/0.0.2/SharedCode-0.0.2.jar
Deploying artifact: http://localhost:8081/artifactory/libs-release-local/com/mycompany/sdk/SharedCode/0.0.2/SharedCode-0.0.2.pom
Deploying build descriptor to: http://localhost:8081/artifactory/api/build Build successfully deployed.
Browse it in Artifactory under http://localhost:8081/artifactory/webapp/builds/client-sdk/1457375019604

BUILD SUCCESSFUL

Note that only the SharedCode artifact is published in this case.

If I run the artifactoryPublish task at the Android module level, then I see output as follows:

18:25:25: Executing external task 'artifactoryPublish'...
Publication named 'SharedCode' does not exist for project ':Android' in task ':Android:artifactoryPublish'.
:Android:artifactoryPublish
Deploying build descriptor to: http://localhost:8081/artifactory/api/build
Build successfully deployed. Browse it in Artifactory under http://localhost:8081/artifactory/webapp/builds/client-sdk/1457375127269

BUILD SUCCESSFUL

Note that no artifacts are published in this case.

Alpert answered 7/3, 2016 at 18:32 Comment(7)
What is the folder structure of your modules? Do you have both Shared and Android under a third Root folder? Can you show your settings.gradle as well please?Rimbaud
Yes, I have a root folder which has a project-level build.gradle file which has nothing substantial in it right now other than classpath declarations. And under that folder I have an Android and a SharedCode folder which represent an Android library and a Java module respectively. The build.gradle files for these two modules are as in my question above. (Thanks for your help btw @RaGe. Really appreciate it.)Alpert
My settings.gradle file has these three lines: (1) rootProject.name = 'client-sdk'; (2) include ':Android'; (3) include ':SharedCode'.Alpert
Adil, could you post a full working (after you took the advice from the accepted answer) to the end of your question? (for us future reader newbies?). Thanks.Levi
@granadaCoder, I posted a working solution in this answer but note that I later abandoned the com.jfrog.artifactory plugin in favour of the standard maven-publish plugin for Java library modules and the digital.wup.android-maven-publish plugin for Android library modules. See my comments in the answer that I've linked to. For an example of the digital.wup.android-maven-publish plugin, see the build.gradle files in this repository.Alpert
Thanks for the breadcrumb.Levi
I also had to apply the maven-publish plugin in the root build.gradle to get it work.Alternation
R
3

Going by artifactory multi-project examples on their github repo, it would seem that only the root project needs to have an artifactory{...} configuration section as opposed to in every sub-project as you have done.

Moreover when you declare publications('SharedCode') in the root project, artifactory plugin seems to be looking for a publication called sharedCode in every subproject.

I would try:

  • Remove the artifactory{...} section from the android build.gradle

  • Rename the android publication to sharedCode as well (or something more generic in both projects)

Rimbaud answered 9/3, 2016 at 22:39 Comment(13)
So I've moved the artifactory{...} section out from the Android and SharedCode modules and up into the project-level build.gradle file as follows: artifactory { publish { publications('SharedCode', 'Android') } }. This seems to be the right thing to do. But when I run the artifactoryPublish task now I get the following two error messages: (1) Publication named 'SharedCode' does not exist for project ':' in task ':artifactoryPublish'. (2) Publication named 'Android' does not exist for project ':' in task ':artifactoryPublish'. Oh and no artifacts are published to Artifactory.Alpert
Next step I guess is to figure out how to make the artifactoryPublish task aware of the SharedCode and Android modules.Alpert
You need to add something like artifactory.skip=true in the root project. One of the example projects had it.Rimbaud
No luck :-( Tried adding artifactory { defaults { skip = true } } as well as artifactoryPublish { skip = true } but still getting the same "Publication named ... does not exist for project ..." error messages as before.Alpert
Can you post your current root build.gradle to a github gist?Rimbaud
Small gain today: got Artifactory publishing working by removing the com.jfrog.artifactory plugin and instead using the publishing { repositories { maven { ... } } } construct from the maven-publish plugin in each of my Android/build.gradle and SharedCode/build.gradle files. And then to use the publish Gradle task.Alpert
so you're effectively treating artifactory as a maven repo? Good to know that this works. I don't have ready access to an artifactory instance right now, I didn't get a change to test this yet. Will look into it later tonight.Rimbaud
I'm having to resort to this until I can figure out how to get the Gradle Artifactory plugin to work :-( This does work though. I kicked off a local Artifactory instance on my machine and was able to upload the artifacts.Alpert
I'm unable to reproduce your issue. Once I add artifactoryPublish.skip=true to the root build.gradle, the sub-projects are able to publish their publications to Artifactory just fine. See git repo here. Running gradle artifactoryPublish from the root project results in: i.imgur.com/awdazUo.pngRimbaud
So strange... I don't know how this is working for you. I checked out the project that you created and when I run any Gradle task I see this output in the console: (1) Publication named 'JavaPublication' does not exist for project ':subB' in task ':subB:artifactoryPublish'. (2) Publication named 'someOtherName' does not exist for project ':subA' in task ':subA:artifactoryPublish'. Any ideas??Alpert
Interestingly... running the artifactoryPublish Gradle task does publish the foo and barartifacts to Artifactory despite the error messages in the console (see previous comment)!Alpert
are those warning or errors? Do they break the build? What it says is true, those publications do not exist on all sub projects, but that shouldn't be a problem. OR - you could name the publications in both projects the same and you wont get even that message.Rimbaud
Thanks for your help with this @RaGe. I've marked your answer as the accepted answer and awarded you the bounty. Although I still haven't managed to get the artifact from the Android library to publish to Artifactory I'll investigate this further and raise a separate, clearer question about this.Alpert
A
6

Update: As of version 4.6.0 of the com.jfrog.artifactory Gradle plugin, publishing artifacts in a multi-module project just does not work. From personal experience, you're best just abandoning this plugin and using the standard maven-publish plugin for both Java library modules and Android library modules.

--- What follows below is my original answer before I posted the above update ---

So I've finally got this all working! Special thanks to @RaGe for helping me along the way. The key points to note are that the artifactory block needs to be in the project's root-level build.gradle file and not in the build.gradle file of the individual modules. Also, you need to add artifactoryPublish.skip=true to the project's root-level build.gradle file. See this GitHub repo for a full-on yet minimal-as-possible example:

https://github.com/adil-hussain-84/SO-35851251-Multiproject-Artifactory-Publish

In case the link ever stops working I'll paste the contents of the build.gradle files here also. Firstly, the project's root-level build.gradle file:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.5.0'
        classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:4.0.1'
    }
}

allprojects {
    apply plugin: 'com.jfrog.artifactory'

    repositories {
        jcenter()
    }

    group = "${projectGroupName}"
    version = "${projectVersionName}"
}

artifactoryPublish.skip=true

artifactory {
    contextUrl = "${artifactory_url}"
    publish {
        repository {
            repoKey = 'libs-release-local'
            username = "${artifactory_username}"
            password = "${artifactory_password}"
        }
        defaults {
        publications('SomePublication')
            publishArtifacts = true
            properties = ['qa.level': 'basic', 'dev.team': 'core']
            publishPom = true
        }
    }
}

task wrapper(type: Wrapper) {
    gradleVersion = '2.8'
}

Secondly, the build.gradle file of the Android module:

apply plugin: 'com.android.library'
apply plugin: 'maven-publish'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        minSdkVersion 19
        targetSdkVersion 23
        versionCode Integer.parseInt("${projectVersionCode}")
        versionName "${projectVersionName}"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile project(':SharedCode')
    compile 'com.android.support:appcompat-v7:23.2.1'

    testCompile 'junit:junit:4.12'
}

publishing {
    publications {
        SomePublication(MavenPublication) {
            artifact "$buildDir/outputs/aar/Android-release.aar"

            //The publication doesn't know about our dependencies, so we have to manually add them to the pom
            pom.withXml {
                def dependenciesNode = asNode().appendNode('dependencies')

                //Iterate over the compile dependencies (we don't want the test ones), adding a <dependency> node for each
                configurations.compile.allDependencies.each {
                    def dependencyNode = dependenciesNode.appendNode('dependency')
                    dependencyNode.appendNode('groupId', it.group)
                    dependencyNode.appendNode('artifactId', it.name)
                    dependencyNode.appendNode('version', it.version)
                }
            }
        }
    }
}

Thirdly and finally, the build.gradle file of the SharedCode (Java) module:

apply plugin: 'java'
apply plugin: 'maven-publish'

dependencies {
    compile 'com.google.guava:guava:18.0'
}

publishing {
    publications {
        SomePublication(MavenPublication) {
            from components.java
        }
    }
}

That's it!

Alpert answered 16/3, 2016 at 19:34 Comment(8)
I'm using version 4.4.14 of the plugin and I can confirm that I no longer need the hack of adding the artifactory {...} block in the project's root level build.gradle file. The publishing {...} and artifactory {...} blocks can be added separately in each of the modules of the project that are to publish artifacts.Alpert
Is it possible to publish an apk to the artifactory? I have a project with 2 modules. One is a library and other one is an application.Adaptive
DineshKumar, I'm guessing by application you mean Android application, i.e. an apk file. I haven't tried it but it certainly should be possible to PUT your apk file to Artifactory with Gradle. Bear in mind that you won't want to publish your apk as a Maven artifact (i.e. with a pom file etc) since that only makes sense for libraries.Alpert
Update: As of version 4.6.0 of the com.jfrog.artifactory Gradle plugin publishing artifacts in a multi-module project just does not work. From personal experience you're best just abandoning this plugin and using the standard maven-publish plugin for Java library modules and the digital.wup.android-maven-publish plugin for Android library modules.Alpert
You are right. I am trying to upload an apk along with an aar. I have partially succeeded. What am facing is, if the apk gets uploaded, aar doesnt and vice-versa.After adding the artifactory closure in the root gradle file, the log shows deploying artifacts for both. However, in case of library it just has an empty folder and a pom file and the apk gets uploaded successfully. Any idea about this?Adaptive
I somehow found a solution to upload both aar and a apk file.Its working for me and am using version 4.2.0. Earlier I was using 3.1.2 and it didnt work.Adaptive
Okay. Good stuff. I had success with version 4.5.4 of the com.jfrog.artifactory plugin but no luck with later versions. I've now abandoned using this plugin in favour of using the digital.wup.android-maven-publish and maven-publish plugins with a publishing { publications { ... } repositories { ... } } block in each of my build.gradle files.Alpert
Update: The digital.wup.android-maven-publish Gradle plugin has been deprecated since the maven-publish Gradle plugin is now supported by the Android Gradle plugin. See here for a short guide on how to use the maven-publish to publish an Android application or Android library.Alpert
R
3

Going by artifactory multi-project examples on their github repo, it would seem that only the root project needs to have an artifactory{...} configuration section as opposed to in every sub-project as you have done.

Moreover when you declare publications('SharedCode') in the root project, artifactory plugin seems to be looking for a publication called sharedCode in every subproject.

I would try:

  • Remove the artifactory{...} section from the android build.gradle

  • Rename the android publication to sharedCode as well (or something more generic in both projects)

Rimbaud answered 9/3, 2016 at 22:39 Comment(13)
So I've moved the artifactory{...} section out from the Android and SharedCode modules and up into the project-level build.gradle file as follows: artifactory { publish { publications('SharedCode', 'Android') } }. This seems to be the right thing to do. But when I run the artifactoryPublish task now I get the following two error messages: (1) Publication named 'SharedCode' does not exist for project ':' in task ':artifactoryPublish'. (2) Publication named 'Android' does not exist for project ':' in task ':artifactoryPublish'. Oh and no artifacts are published to Artifactory.Alpert
Next step I guess is to figure out how to make the artifactoryPublish task aware of the SharedCode and Android modules.Alpert
You need to add something like artifactory.skip=true in the root project. One of the example projects had it.Rimbaud
No luck :-( Tried adding artifactory { defaults { skip = true } } as well as artifactoryPublish { skip = true } but still getting the same "Publication named ... does not exist for project ..." error messages as before.Alpert
Can you post your current root build.gradle to a github gist?Rimbaud
Small gain today: got Artifactory publishing working by removing the com.jfrog.artifactory plugin and instead using the publishing { repositories { maven { ... } } } construct from the maven-publish plugin in each of my Android/build.gradle and SharedCode/build.gradle files. And then to use the publish Gradle task.Alpert
so you're effectively treating artifactory as a maven repo? Good to know that this works. I don't have ready access to an artifactory instance right now, I didn't get a change to test this yet. Will look into it later tonight.Rimbaud
I'm having to resort to this until I can figure out how to get the Gradle Artifactory plugin to work :-( This does work though. I kicked off a local Artifactory instance on my machine and was able to upload the artifacts.Alpert
I'm unable to reproduce your issue. Once I add artifactoryPublish.skip=true to the root build.gradle, the sub-projects are able to publish their publications to Artifactory just fine. See git repo here. Running gradle artifactoryPublish from the root project results in: i.imgur.com/awdazUo.pngRimbaud
So strange... I don't know how this is working for you. I checked out the project that you created and when I run any Gradle task I see this output in the console: (1) Publication named 'JavaPublication' does not exist for project ':subB' in task ':subB:artifactoryPublish'. (2) Publication named 'someOtherName' does not exist for project ':subA' in task ':subA:artifactoryPublish'. Any ideas??Alpert
Interestingly... running the artifactoryPublish Gradle task does publish the foo and barartifacts to Artifactory despite the error messages in the console (see previous comment)!Alpert
are those warning or errors? Do they break the build? What it says is true, those publications do not exist on all sub projects, but that shouldn't be a problem. OR - you could name the publications in both projects the same and you wont get even that message.Rimbaud
Thanks for your help with this @RaGe. I've marked your answer as the accepted answer and awarded you the bounty. Although I still haven't managed to get the artifact from the Android library to publish to Artifactory I'll investigate this further and raise a separate, clearer question about this.Alpert
I
3

Version 4.2.0 of the Gradle Artifactory Plugin was released last week and added multiple Artifactory repositories deployment. Now you can simply define an artifactory closure with a different repository for different modules of the project.

Infrasonic answered 9/4, 2016 at 4:22 Comment(4)
We confirm that this is an issue started from 4.4.9 of the Gradle Artifactory Plugin, Jira ticket: jfrog.com/jira/browse/GAP-272.Stagy
Fixed plugin version has been released and an example project - gradle-example-multi-repos has been added.Infrasonic
I'm using version 4.4.14 of the plugin and I can confirm that I no longer need the hack of adding the artifactory {...} block in the project's root level build.gradle file. The publishing {...} and artifactory {...} blocks can be added separately in each of the modules of the project that are to publish artifacts.Alpert
Which gradle command are you using? gradle clean build artifactoryPublish is not publishing the android modules (only the java modules).Polly

© 2022 - 2024 — McMap. All rights reserved.