Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invalid pom is produced when using both the dependency management plugin and Gradle's bom support #257

Closed
acidbee opened this issue Jun 26, 2019 · 12 comments
Milestone

Comments

@acidbee
Copy link

acidbee commented Jun 26, 2019

When including other BOMs in a build file, generating POMs for publishing artifacts include two dependency management nodes resulting in an invalid POM.

build.gradle.kts

plugins {
    java
    application
    maven
    `maven-publish`
    id("org.springframework.boot") version "2.1.5.RELEASE"
    id("com.gorylenko.gradle-git-properties") version "2.0.0"
}

apply(plugin = "io.spring.dependency-management")

group = "com.isonas"

repositories {
    mavenCentral()
}

// Configure Java
java {
    sourceCompatibility = JavaVersion.VERSION_11
    targetCompatibility = JavaVersion.VERSION_11
}

// Enable creating jar as part of build artifacts
tasks.getByName<Jar>("jar") {
    enabled = true
}

// Define main class name for distributions
springBoot {
    mainClassName = "com.isonas.microservice.App"
    buildInfo()
}

application {
    mainClassName = "com.isonas.microservice.App"
}

// Make sure distributions have launch scripts
tasks.bootJar {
    launchScript()
}

publishing {
    publications {
        create<MavenPublication>("jar") {
            from(components["java"])
            artifact(tasks.getByName("jar"))
        }

        create<MavenPublication>("bootJar") {
            artifact(tasks.getByName("bootJar"))
        }
    }
}

// Explicitly enable the JUnit 5 Jupiter engine
tasks.test {
    useJUnitPlatform()
}

// Project Dependencies
dependencies {
    // Bill of Materials
    implementation(platform("software.amazon.awssdk:bom:2.5.29"))

    // Annotation Processors
    annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")

    // Spring Boot Framework
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("org.springframework.boot:spring-boot-starter-actuator")

    // AWS
    implementation("software.amazon.awssdk:ssm")

    // Test Dependencies
    testImplementation("org.junit.jupiter:junit-jupiter-api")
    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
}

Running a publish task results in an error

$gradle clean build publishToMavenLocal --stacktrace

> Task :publishJarPublicationToMavenLocal FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':publishJarPublicationToMavenLocal'.
> Failed to publish publication 'jar' to repository 'mavenLocal'
   > Invalid publication 'jar': POM file is invalid. Check any modifications you have made to the POM file.

...

Caused by: org.codehaus.plexus.util.xml.pull.XmlPullParserException: Duplicated tag: 'dependencyManagement' (position: START_TAG seen ...</dependencies>\n  <dependencyManagement>... @36:25)

build/publications/jar/pom-default.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.isonas</groupId>
  <artifactId>micro-service-template</artifactId>
  <version>unspecified</version>
  <packaging>pom</packaging>
  <!-- AWS SDK BOM -->
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>bom</artifactId>
        <version>2.5.29</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>ssm</artifactId>
      <scope>runtime</scope>
    </dependency>
  </dependencies>
  <!-- Spring Boot BOM -->
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>2.1.5.RELEASE</version>
        <scope>import</scope>
        <type>pom</type>
      </dependency>
    </dependencies>
  </dependencyManagement>
</project>
@wilkinsona
Copy link
Contributor

wilkinsona commented Jun 26, 2019

This looks like a Gradle bug to me. This plugin only adds <dependencyManagement> to the project's pom if it does not already exist:

private void doConfigurePom(Node pom) {
Node dependencyManagementNode = findChild(pom, NODE_NAME_DEPENDENCY_MANAGEMENT);
if (dependencyManagementNode == null) {
dependencyManagementNode = pom.appendNode(NODE_NAME_DEPENDENCY_MANAGEMENT);
}
Node managedDependenciesNode = findChild(dependencyManagementNode, NODE_NAME_DEPENDENCIES);
if (managedDependenciesNode == null) {
managedDependenciesNode = dependencyManagementNode.appendNode(NODE_NAME_DEPENDENCIES);
}
configureBomImports(managedDependenciesNode);
configureManagedDependencies(managedDependenciesNode, findChild(pom, NODE_NAME_DEPENDENCIES));
}

There's also a test that verifies this behaviour:

def "Dependency management can be added to a pom with existing dependency management"() {
given: 'Dependency management that imports a bom'
this.dependencyManagement.importBom(null, new Coordinates('io.spring.platform', 'platform-bom',
'1.0.3.RELEASE'), new MapPropertySource([:]));
when: 'The pom with existing dependency management is configured'
Node pom = new XmlParser().parseText("<project><dependencyManagement><dependencies></dependencies></dependencyManagement></project>")
new StandardPomDependencyManagementConfigurer(this.dependencyManagement.globalDependencyManagement,
new PomCustomizationSettings(), pomResolver, project).configurePom(pom)
then: 'The imported bom has been added'
pom.dependencyManagement.dependencies.dependency.size() == 1
def dependency = pom.dependencyManagement.dependencies.dependency[0]
dependency.groupId[0].value() == 'io.spring.platform'
dependency.artifactId[0].value() == 'platform-bom'
dependency.version[0].value() == '1.0.3.RELEASE'
dependency.scope[0].value() == 'import'
dependency.type[0].value() == 'pom'
}

If you have evidence to the contrary, please comment with it here and we can re-open the issue to investigate. Otherwise, I think this needs to be reported to the Gradle team. You could also avoid the problem by using either the dependency management plugin or Gradle's platform support, rather than mixing the two.

@primehot
Copy link

primehot commented Jan 2, 2020

Hello,
If some one still have this problem.
Solution works for me, add to build.gradle:
dependencyManagement { imports { mavenBom 'groupId:artifactID:version' } }

@nstdio
Copy link

nstdio commented May 7, 2020

Using

implementation platform("my.company:dependencies:$version")
implementation platform("org.springframework.boot:spring-boot-dependencies:$springBootVersion")

Correctly publishes to Artifactory.

@piyush8098
Copy link

When including other BOMs in a build file, generating POMs for publishing artifacts include two dependency management nodes resulting in an invalid POM.

build.gradle.kts

plugins {
    java
    application
    maven
    `maven-publish`
    id("org.springframework.boot") version "2.1.5.RELEASE"
    id("com.gorylenko.gradle-git-properties") version "2.0.0"
}

apply(plugin = "io.spring.dependency-management")

group = "com.isonas"

repositories {
    mavenCentral()
}

// Configure Java
java {
    sourceCompatibility = JavaVersion.VERSION_11
    targetCompatibility = JavaVersion.VERSION_11
}

// Enable creating jar as part of build artifacts
tasks.getByName<Jar>("jar") {
    enabled = true
}

// Define main class name for distributions
springBoot {
    mainClassName = "com.isonas.microservice.App"
    buildInfo()
}

application {
    mainClassName = "com.isonas.microservice.App"
}

// Make sure distributions have launch scripts
tasks.bootJar {
    launchScript()
}

publishing {
    publications {
        create<MavenPublication>("jar") {
            from(components["java"])
            artifact(tasks.getByName("jar"))
        }

        create<MavenPublication>("bootJar") {
            artifact(tasks.getByName("bootJar"))
        }
    }
}

// Explicitly enable the JUnit 5 Jupiter engine
tasks.test {
    useJUnitPlatform()
}

// Project Dependencies
dependencies {
    // Bill of Materials
    implementation(platform("software.amazon.awssdk:bom:2.5.29"))

    // Annotation Processors
    annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")

    // Spring Boot Framework
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("org.springframework.boot:spring-boot-starter-actuator")

    // AWS
    implementation("software.amazon.awssdk:ssm")

    // Test Dependencies
    testImplementation("org.junit.jupiter:junit-jupiter-api")
    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
}

Running a publish task results in an error

$gradle clean build publishToMavenLocal --stacktrace

> Task :publishJarPublicationToMavenLocal FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':publishJarPublicationToMavenLocal'.
> Failed to publish publication 'jar' to repository 'mavenLocal'
   > Invalid publication 'jar': POM file is invalid. Check any modifications you have made to the POM file.

...

Caused by: org.codehaus.plexus.util.xml.pull.XmlPullParserException: Duplicated tag: 'dependencyManagement' (position: START_TAG seen ...</dependencies>\n  <dependencyManagement>... @36:25)

build/publications/jar/pom-default.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.isonas</groupId>
  <artifactId>micro-service-template</artifactId>
  <version>unspecified</version>
  <packaging>pom</packaging>
  <!-- AWS SDK BOM -->
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>bom</artifactId>
        <version>2.5.29</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>ssm</artifactId>
      <scope>runtime</scope>
    </dependency>
  </dependencies>
  <!-- Spring Boot BOM -->
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>2.1.5.RELEASE</version>
        <scope>import</scope>
        <type>pom</type>
      </dependency>
    </dependencies>
  </dependencyManagement>
</project>

Hi @acidbee , I am facing the same issue. Were you able to fix it?

@wilkinsona
Copy link
Contributor

wilkinsona commented Mar 9, 2021

@piyush8098 Did you try the suggestion above?

You could also avoid the problem by using either the dependency management plugin or Gradle's platform support, rather than mixing the two.

@Warfront1
Copy link

I had the same problem when using implementation platform("software.amazon.awssdk:bom:2.17.8") and plugin id 'io.spring.dependency-management' version '1.0.11.RELEASE'

In order to fix this I removed the awssdk:bom implementation and directly just referenced the AWS components I needed:
implementation "software.amazon.awssdk:s3:2.17.8" etc...

Obviously less than ideal, but I wasn't able to get anything working that was already posted.

@FrogDevelopper
Copy link

FrogDevelopper commented Aug 10, 2021

I get the same issue while using dependencyManagement only.
Based on the hack found in Gradle plugin: Duplicated tag: 'dependencyManagement', I've added this script that will merge the 2 blocks <dependencyManagement> into 1 and so resolve the issue.

Groovy
tasks.withType(GenerateMavenPom).all {
    doLast {
        File file = new File("$buildDir/publications/maven/pom-default.xml")
        def text = file.text
        def pattern = "(?s)(<dependencyManagement>.+?<dependencies>)(.+?)(</dependencies>.+?</dependencyManagement>)"
        Matcher matcher = text =~ pattern
        if (matcher.find()) {
            text = text.replaceFirst(pattern, "")
            def firstDeps = matcher.group(2)
            text = text.replaceFirst(pattern, '$1$2' + firstDeps + '$3')
        }
        file.write(text)
    }
}
Kotlin
tasks.withType<GenerateMavenPom>().all {
    doLast {
        val file = File("$buildDir/publications/maven/pom-default.xml")
        var text = file.readText()
        val regex = "(?s)(<dependencyManagement>.+?<dependencies>)(.+?)(</dependencies>.+?</dependencyManagement>)".toRegex()
        val matcher = regex.find(text)
        if (matcher != null) {
            text = regex.replaceFirst(text, "")
            val firstDeps = matcher.groups[2]!!.value
            text = regex.replaceFirst(text, "$1$2$firstDeps$3")
        }
        file.writeText(text)
    }
}

@lucianspec
Copy link

thanks @FrogDevelopper 's solutions , it save my day.

@wwShuang
Copy link

wwShuang commented Aug 9, 2022

@FrogDevelopper excellent solution! thanks!

@nddipiazza
Copy link

omg thank you. you saved my friday.

@morohon
Copy link

morohon commented Aug 31, 2023

@wilkinsona Hello!
I made issues in the gradle repo: gradle/gradle#21277 (comment) , but they seem to have found a problem on the plugin side. Maybe you can study and comment on this point?

@wilkinsona wilkinsona changed the title maven/maven-publish plugins produce invalid POMs when including additional BOMs Invalid pom is produced when using both the dependency management plugin and Gradle's bom support Sep 1, 2023
@wilkinsona wilkinsona added this to the 1.1.x milestone Sep 1, 2023
@wilkinsona wilkinsona reopened this Sep 1, 2023
@wilkinsona wilkinsona modified the milestones: 1.1.x, 1.1.4 Sep 1, 2023
@wilkinsona
Copy link
Contributor

@jvandort is correct (thank you, Justin). The tests didn't catch the problem as the name (returned as Object by Groovy's API) was always a String and never a QName.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests