Maven publication 'maven' cannot include multiple components - maven

When I am building multi-project with multibranch using this command with Gradle 6.0:
./gradlew :soa-report-consumer-multi_master:soa-report-consumer-api:build publishMavenPublicationToMavenRepository -x test -PpubRepoUrl=https://nexus.balabala.com/repository/maven-releases/ -PmultibranchProjDir=soa-report-consumer-multi_master
shows this eror:
FAILURE: Build failed with an exception.
* Where:
Build file '/Users/dabaidabai/.jenkins/workspace/t-consumer-multi_feature_happygo/build.gradle' line: 35
* What went wrong:
A problem occurred evaluating project ':t-consumer-multi_feature_happygo'.
> Maven publication 'maven' cannot include multiple components
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
this is my build.gradle config in sub project:
project(":$consumerMultibranchProjDir:soa-report-consumer-api") {
jar {
enabled = true
}
bootJar {
enabled = false
}
archivesBaseName = "soa-report-consumer-api"
version = "1.0.0-RELEASE"
jar {
enabled = true
}
dependencies {
api("com.sportswin.soa:soa-misc-biz:1.0.0-RELEASE")
api project(":soa-wallet:soa-wallet-api")
}
publishing {
publications {
maven(MavenPublication) {
groupId 'com.sportswin.soa'
artifactId 'soa-report-consumer-api'
version '1.0.0-RELEASE'
from components.java
artifact sourceJar {
classifier "sources"
}
}
}
}
}
where is the problem? and what should I do to fix it?

from the part config you shared - I think that you have 2 sources jars
remove explicit sources jar in publishing
project(":$consumerMultibranchProjDir:soa-report-consumer-api") {
jar {
enabled = true
}
bootJar {
enabled = false
}
archivesBaseName = "soa-report-consumer-api"
version = "1.0.0-RELEASE"
dependencies {
api("com.sportswin.soa:soa-misc-biz:1.0.0-RELEASE")
api project(":soa-wallet:soa-wallet-api")
}
publishing {
publications {
maven(MavenPublication) {
groupId 'com.sportswin.soa'
artifactId 'soa-report-consumer-api'
version '1.0.0-RELEASE'
from components.java
}
}
}
}

Related

Unable to publish a gradle Jar artifact to a sonatype repository

I am following instructions in the Sonatype documentation for publishing a gradle project.
I have the following gradle version.
$ ./gradlew --version
------------------------------------------------------------
Gradle 7.6
------------------------------------------------------------
Build time: 2022-11-25 13:35:10 UTC
Revision: daece9dbc5b79370cc8e4fd6fe4b2cd400e150a8
Kotlin: 1.7.10
Groovy: 3.0.13
Ant: Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM: 1.8.0_181 (Oracle Corporation 25.181-b13)
OS: Mac OS X 10.16 x86_64
When I try to use the uploadArchives task as given in their example, I get the following error:
$ ./gradlew uploadArchives
FAILURE: Build failed with an exception.
* Where:
Build file '/Users/ferozed/stash/libs/mask-json-field-transform/build.gradle' line: 167
* What went wrong:
A problem occurred evaluating root project 'mask-json-field-transform'.
> Could not find method uploadArchives() for arguments [build_6yphclnk6m8p3rtmq5h7m56li$_run_closure12#19fbeecd] on root project 'mask-json-field-transform' of type org.gradle.api.Project.
This is my build.gradle file
buildscript {
repositories {
gradlePluginPortal()
}
dependencies {
classpath 'gradle.plugin.com.github.johnrengelman:shadow:7.1.2'
}
}
plugins {
id 'java' // so that we can use 'implementation', 'testImplementation' for dependencies
id 'maven-publish'
id 'signing'
}
apply plugin: 'maven-publish'
apply plugin: 'signing'
apply plugin: 'com.github.johnrengelman.shadow'
repositories {
jcenter()
mavenCentral()
maven {
url = "https://packages.confluent.io/maven"
}
maven {
url = "https://jitpack.io"
}
}
group = 'io.github.ferozed.kafka.connect'
version = '0.1'
dependencies {
// Kafka
implementation group: 'org.apache.kafka', name: 'connect-api', version: '3.3.1'
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.14.1'
implementation 'com.github.jcustenborder.kafka.connect:connect-utils:0.7.173'
implementation 'com.github.jcustenborder.kafka.connect:kafka-connect-transform-common:0.1.0.14'
//test
testImplementation(platform('org.junit:junit-bom:5.9.0'))
testImplementation('org.junit.jupiter:junit-jupiter')
testImplementation("io.mockk:mockk:1.9.2")
}
sourceSets {
main {
java {
srcDirs = ["src/main/java"]
}
resources {
srcDirs = ["src/main/avro", "src/main/resources"]
}
}
test {
java {
srcDirs = ["src/test/java"]
}
}
}
test {
useJUnitPlatform()
testLogging {
events "passed", "skipped", "failed"
}
}
task javadocJar(type: Jar) {
classifier = 'javadoc'
from javadoc
}
task sourcesJar(type: Jar) {
classifier = 'sources'
from sourceSets.main.allSource
}
tasks.withType(AbstractArchiveTask).configureEach {
preserveFileTimestamps = false
reproducibleFileOrder = true
}
plugins.withId("com.github.johnrengelman.shadow"){
//this block requires the java plugin to be applied first.
plugins.withId("java"){
shadowJar {
//We are overriding the default jar to be the shadow jar
classifier = null
exclude 'META-INF'
exclude 'META-INF/*.INF'
exclude 'META-INF/license/*'
}
jar {
manifest {
attributes(
'Built-By' : System.properties['user.name'],
'Build-Timestamp': new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(new Date()),
'Created-By' : "Gradle ${gradle.gradleVersion}",
'Build-Jdk' : "${System.properties['java.version']} (${System.properties['java.vendor']} ${System.properties['java.vm.version']})",
'Build-OS' : "${System.properties['os.name']} ${System.properties['os.arch']} ${System.properties['os.version']}"
)
}
}
tasks.build.dependsOn tasks.shadowJar
tasks.shadowJar.mustRunAfter tasks.jar
tasks.shadowJar.mustRunAfter tasks.javadocJar
tasks.shadowJar.mustRunAfter tasks.sourcesJar
}
}
publishing {
publications {
mavenJava(MavenPublication) {
pom {
name = 'Mask Json Field Transform'
description = 'A kafka connect transform to remove the value of a sensitive field in a json document.'
url = 'https://github.com/ferozed/mask-json-field-transform'
properties = [
myProp: "value",
"prop.with.dots": "anotherValue"
]
licenses {
license {
name = 'The Apache License, Version 2.0'
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
developers {
developer {
id = 'ferozes'
name = 'Feroze Daud'
email = 'ferozed.oss#gmail.com'
}
}
scm {
connection = 'scm:git:git#github.com:ferozed/mask-json-field-transform.git'
developerConnection = 'scm:git:git#github.com:ferozed/mask-json-field-transform.git'
url = 'https://github.com/ferozed/mask-json-field-transform'
}
}
}
}
}
signing {
sign configurations.archives
sign publishing.publications.mavenJava
}
tasks.signArchives.dependsOn tasks.shadowJar
artifacts {
archives javadocJar, sourcesJar
}
uploadArchives {
repositories {
mavenDeployer {
beforeDeployment { deployment -> signing.signPom(deployment) }
repository(url: "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/") {
authentication(userName: ossrhUsername, password: ossrhPassword)
}
snapshotRepository(url: "https://s01.oss.sonatype.org/content/repositories/snapshots/") {
authentication(userName: ossrhUsername, password: ossrhPassword)
}
pom.project {
name 'Example Application'
packaging 'jar'
// optionally artifactId can be defined here
description 'A kafka connect transform to remove the value of a sensitive field in a json document.'
url 'https://github.com/ferozed/mask-json-field-transform'
scm {
connection 'scm:svn:http://foo.googlecode.com/svn/trunk/'
developerConnection 'scm:svn:https://foo.googlecode.com/svn/trunk/'
url 'https://github.com/ferozed/mask-json-field-transform'
}
licenses {
license {
name 'The Apache License, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
developers {
developer {
id 'ferozed'
name 'Feroze Daud'
email 'feroz#gmail.com'
}
}
}
}
}
}
What am I doing wrong?
First and foremost, you may not need to 'fix the error' so to speak, in that it appears the problematic code MAY be able to be outright deleted. However...
To fix the error...
Could not find method uploadArchives() for arguments [build_6yphclnk6m8p3rtmq5h7m56li$_run_closure12#19fbeecd] on root project 'mask-json-field-transform' of type org.gradle.api.Project.
This is telling us that uploadArchives is not valid. See immediately below.
I believe you may need to use the maven plugin to access this functionality.
https://github.com/siddeshbg/gradle-uploadArchives/blob/master/README.md
to do this, add:
id 'maven'
to your plugins{}
block.
The above example explains that the maven plugin is responsible for doing this
The Maven plugin adds support for deploying artifacts to Maven repositories
It is worth considering also that the author of the above repository claims:
This is the legacy publishing mechanism, should not be used in newer
builds
Now... on to the better solution, forgetting the maven plugin, in favor of the maven-publish plugin you're already using...
I do not personally work with Maven often enough to know what other mechanisms one should use, but Google suggests that perhaps the maven-publish plugin you're using might do this WITHOUT the 'uploadArchives{}' portion of your code that is causing the error.
See:
https://docs.gradle.org/current/userguide/publishing_maven.html
Per this page, it would seem the entire uploadArchives block is unnecessary

How do I suppress POM and IVY related warnings in Gradle 7?

After upgrading to Gradle 7 I have many warnings like:
Cannot publish Ivy descriptor if ivyDescriptor not set in task ':myProject:artifactoryPublish' and task 'uploadArchives' does not exist.
Cannot publish pom for project ':myProject' since it does not contain the Maven plugin install task and task ':myProject:artifactoryPublish' does not specify a custom pom path.
The artifactoryPublish task works fine.
My Gradle script:
buildscript {
repositories{
maven {
url = '...'
credentials {
username '...'
password '...'
}
metadataSources {
mavenPom()
artifact()
}
}
}
dependencies {
classpath "org.jfrog.buildinfo:build-info-extractor-gradle:4.24.12"
}
}
apply plugin: 'java'
apply plugin: 'maven-publish'
apply plugin: org.jfrog.gradle.plugin.artifactory.ArtifactoryPlugin
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
suppressAllPomMetadataWarnings()
}
}
}
group = '...'
artifactory {
contextUrl = '...'
publish {
repository {
repoKey = '...'
username = '...'
password = '...'
}
defaults {
publishConfigs('archives')
publishIvy = false
publications("mavenJava")
}
}
}
How do I disable those warnings?
It looks like you mixed between the old Gradle publish-configuration method and the new Gradle publication method.
You applied the maven-publish plugin which allows creating publications. In artifactory.default, you added the "mavenJava" publication as expected.
However, the archives publish-configuration doesn't exist in your build.gradle file. Basically, publish-configurations are created by the legacy maven plugin. The configured mavenJava publication does the same as the archives publish-configuration and therefore all of the JARs are published as expected.
To remove the warning messages you see, remove the publishConfigs('archives') from artifactory.default clause:
artifactory {
publish {
defaults {
publishConfigs('archives') // <-- Remove this line
publishIvy = false
publications("mavenJava")
}
}
}
Read more:
Gradle Artifactory plugin documentation
Example

What exactly is "The plugins {} block must not be used here. If you need to apply a plugin imperatively"?

I have a gradle project that uses kotlin dsl:
plugins {
base
kotlin("jvm") version "1.3.70" apply false
}
//val scalaV: String by project
//val ext = SpikeExt(this)
allprojects {
apply(plugin = "java")
apply(plugin = "scala")
group = "com.tribbloids.scalaspike"
version = "1.0.0-SNAPSHOT"
repositories {
mavenCentral()
jcenter()
maven("https://dl.bintray.com/kotlin/kotlin-dev")
}
dependencies {
}
}
when I run gradlew build I encounter the following error:
FAILURE: Build failed with an exception.
* Where:
Script '/home/peng/git/scalaspike/build.gradle.kts' line: 1
* What went wrong:
The plugins {} block must not be used here. If you need to apply a plugin imperatively, please use apply<PluginType>() or apply(plugin = "id") instead.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 870ms
In the mean time, the exact identical line 1 works normal in the other project:
https://github.com/gradle/kotlin-dsl-samples/tree/master/samples/multi-kotlin-project
plugins {
base
kotlin("jvm") version "1.3.70" apply false
}
allprojects {
group = "org.gradle.kotlin.dsl.samples.multiproject"
version = "1.0"
repositories {
jcenter()
}
}
dependencies {
// Make the root project archives configuration depend on every sub-project
subprojects.forEach {
archives(it)
}
}
So I have 2 questions:
what does this mean?
why the same thing works in the second project but fails on the first project? What is the difference?

gradle artifactory plugin fails to publish with groupID

In my build.gradle script, publishing works when the groupId is left undefined. I would like to use "org.company.foobar.common" for the groupId.
When I uncomment the groupId lines in the following build.gradle script, I receive an error. Below the script is the execution results when this groupId is defined.
buildscript {
repositories {
maven { url "http://tribe.ust.doj.gov:8085/artifactory/jcenter/"}
maven { url "http://tribe.ust.doj.gov:8085/artifactory/MavenCentral/"}
maven { url "http://tribe.ust.doj.gov:8085/artifactory/gradlePlugins/"}
}
dependencies {
classpath "org.jfrog.buildinfo:build-info-extractor-gradle:latest.release"
}
}
repositories {
maven { url "http://tribe.ust.doj.gov:8085/artifactory/jcenter/"}
maven { url "http://tribe.ust.doj.gov:8085/artifactory/MavenCentral/"}
maven { url "http://tribe.ust.doj.gov:8085/artifactory/gradlePlugins/"}
}
apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'maven-publish'
apply plugin: "com.jfrog.artifactory"
def getArtifactoryUrl() {
return "http://tribe.ust.doj.gov:8085/artifactory/"
}
allprojects {
repositories {
def artifactoryMcentralUrl = getArtifactoryUrl() + "MavenCentral/"
maven {url artifactoryMcentralUrl }
}
}
dependencies {
}
sourceSets {
main {
java {
srcDir "/src"
}
}
}
//project.group = 'org.company.foobar.common'
task printProps {
doLast {
println artifactory_user
println artifactory_contextUrl
//println project.group
}
}
publishing {
publications {
mavenJava(MavenPublication) {
//groupId project.group
artifactId project.getName()
version '1.0.0'
from components.java
}
}
}
artifactory {
def artifactoryUrl = getArtifactoryUrl()
contextUrl = artifactoryUrl
publish {
repository {
repoKey = 'libs-snapshot-local'
username = "${artifactory_user}"
password = "${artifactory_password}"
}
defaults {
publications('mavenJava')
publishArtifacts = true
publishPom = true
}
}
}
The output from "gradle artifactoryPublish" when using the groupId (uncommented) is:
$ gradle artifactoryPublish
:generatePomFileForMavenJavaPublication
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar UP-TO-DATE
:artifactoryPublish
Deploying artifact: http://tribe.ust.doj.gov:8085/artifactory/libs-snapshot-local/org/company/foobar/common/kambucha/1.0.0/kambucha-1.0.0.jar
:artifactoryPublish FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':artifactoryPublish'.
> java.io.IOException: Failed to deploy file. Status code: 409 Response message: Artifactory returned the following errors:
The repository 'libs-snapshot-local' rejected the resolution of an artifact 'libs-snapshot-local:org/company/foobar/common/kambucha/1.0.0/kambucha-1.0.0.jar' due to conflict in the snapshot release handling policy. Status code: 409
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
BUILD FAILED
Total time: 1.84 secs
As it seems, you are trying to publish a RELEASE artifact to a SNAPSHOT repository. When using maven repositories in Artifactory, you will need to make sure that you are following both the Maven layout, and the release / snapshot policy.
In this specific example it seems that your issue is as following:
Artifactory, following maven policy, is recognizing the following path:
'libs-snapshot-local:org/company/foobar/common/kambucha/1.0.0/kambucha-1.0.0.jar' as a release, while the repository is set to handle only snapshots. For this specific path to work, and in case this is really a snapshot artifact, you will need to change the path to be:
libs-snapshot-local:org/company/foobar/common/kambucha/1.0.0-SNAPSHOT/kambucha-1.0.0-SNAPSHOT.jar
If this is a release, change your deployment path to use 'libs-release-local' repository
You can read more on the repository configuration here

Excluding files and folders during plugin publishing

I want to exclude .svn folders when I publish my plugin to our custom Artifactory repository. I'm assuming the inclusion of .svn folders is the issue based on the error strack trace provided below.
I'm publishing using the following command:
gradlew artifactoryPublish --stacktrace
This is the publishing block in build.gradle:
artifactory {
contextUrl = artifactory_context
publish {
repository {
repoKey = 'plugins-release-local'
username = artifactory_user
password = artifactory_password
maven = true
}
defaults {
publications ('mavenJava')
}
}
}
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
}
}
}
This is the stack trace I get when I attempt to publish, notice the attempt copy of .svn/entries to assets/entries.
...
:copyAssets FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':copyAssets'.
> Could not copy file '/u01/var/build/pluginXYZ/grails-app/assets/.svn/entries' to '/u01/var/build/pluginXYZ/build/resources/main/META-INF/assets/entries'.
* Try:
Run with --info or --debug option to get more log output.
* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':copyAssets'.
...
Caused by: org.gradle.api.GradleException: Could not copy file '/u01/var/build/pluginXYZ/grails-app/assets/.svn/entries' to '/u01/var/build/pluginXYZ/build/resources/main/META-INF/assets/entries'.
...
Caused by: java.io.FileNotFoundException: /u01/var/build/pluginXYZ/build/resources/main/META-INF/assets/entries (Permission denied)
... 80 more
The permission on entries (both trees) are -r--r--r--.
If I exclude those folders, I should get rid of said permission issue. The first checkout will always publish, but subsequent publishes (say after an update), fail with this error.
Update #2
Here are the three combination I tried without success:
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
//first attempt
//exclude("**/.svn/**")
//second attempt
//exclude{ details -> details.file.name.contains(".svn") }
//third attempt
//exclude "**/.svn/**"
}
}
}
The error output when publishing, using all three attempts, is the following:
Caused by: org.gradle.api.internal.MissingMethodException: Could not find method exclude() for arguments [build_3nsvrqvwahy23ir3fxdj970id$_run_closure7_closure13_closure14_closure15#10e9a5fe] on org.gradlpublish.maven.internal.publication.DefaultMavenPublication_Decorated#ca7e37f.
Update #3
I found the following link taking about excluding files.
I then adjusted my gradle.build to this:
publishing {
publications {
mavenJava(MavenPublication) {
from components.java {
exclude "**/.svn/**"
}
}
}
}
Same error.
Update #4
More attempts... same results
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
artifact sourceJar{
exclude '**/.svn/**'
}
}
}
}
or
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
artifact exclude '**/.svn/**'
}
}
}
Say, you have a file which you want to avoid ONLY while publishing to the repository. If you go with as suggested by #TekiusFanatikus
sourceSets {
main {
java {
exclude '**/.svn/**'
}
}
}
you will be able to achieve it but this will also exclude the file/folder etc. from the artifact that you generate using gradle build.
Instead, I would recommend to use the approach as mentioned here gradle documnetation
You can create a task which have your desired exclusion applied
task apiJar(type: Jar) {
baseName "publishing-api"
from sourceSets.main.output
exclude '**/.svn/**'
}
and then refer the task while publishing.
publishing {
publications {
api(MavenPublication) {
groupId 'org.gradle.sample'
artifactId 'project2-api'
version '2'
artifact apiJar
}
}
}
This way, the jar that gets published will not have .svn folder. The point that I wanted to make here is that it will not touch your artifact that gets created using gradle build. It will still have your .svn folder.
But if you want it to be removed from both the places, then the best option is as suggested above.
I would like to extend on #Neeraj answer. The problem with the custom JAR approach is that it doesn't produce a valid POM -- especially not in the case of multi-module projects -- unlike the from components.java approach which generates a POM correctly.
In order to overcome this, we could declare two publications - one internal used only to generate a POM, and the second is the actual publication we wish to publish (without the excluded files):
task apiJar(type: Jar) {
baseName "publishing-api"
from sourceSets.main.output
exclude '**/.svn/**'
}
publishing {
publications {
def pomString = null
internal(MavenPublication) {
from components.java
pom.withXml {
pomString = asString().toString()
}
}
api(MavenPublication) {
artifact apiJar
pom.withXml {
def builder = asString()
builder.delete(0, builder.length())
builder.append(pomString)
}
}
}
}
generatePomFileForApiPublication.dependsOn(generatePomFileForInternalPublication)
artifactoryPublish {
publications('api')
}
Note that the names of the generatePomFileForXPublication tasks are determined according to the names of the publications.
Old Answer
This is my previous attempt at generating a POM manually, but it is not nearly as complete as the newer answer above.
task apiJar(type: Jar) {
baseName "publishing-api"
from sourceSets.main.output
exclude '**/.svn/**'
}
publishing {
publications {
api(MavenPublication) {
artifact apiJar
pom.withXml {
def dependenciesNode = asNode().appendNode("dependencies")
project.configurations.runtimeClasspath.resolvedConfiguration.firstLevelModuleDependencies.forEach { d ->
def dependencyNode = dependenciesNode.appendNode("dependency")
dependencyNode.appendNode("groupId", d.moduleGroup)
dependencyNode.appendNode("artifactId", d.moduleName)
dependencyNode.appendNode("version", d.moduleVersion)
}
}
}
}
}
artifactoryPublish {
publications('api')
}
I think you can use 'exclude' method with filefilter. Just add it under 'from' in publications block.
I appended the following at the root level in my build.gradle and it seems to work:
sourceSets {
main {
java {
exclude '**/.svn/**'
}
}
}

Resources