Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I create a Maven POM-only (BOM) build using the Gradle maven plugin to be deployed to Nexus?

I have a Gradle project which uses Spring's dependency management plugin to define a list of dependency versions. I am also using the Maven plugin to deploy the project to a Maven repository.

I would like to be able to deploy this as a Maven bill of materials (BOM) so that I can use it in other Gradle projects to define my dependency versions. I have been able to get this to work so long as I also deploy a JAR file. However, the JAR is completely empty and superfluous. My goal is to generate and deploy just the POM file, like I would be able to do if this were a Maven project with a "pom" packaging.

If I manually exclude the JAR from the list of artifacts to be published, then nothing gets installed, not even the POM file.

This is a test build to demonstrate the issue:

group 'test'
version '1.0.0-SNAPSHOT'

buildscript {
  repositories {
    mavenCentral()

  }
  dependencies {
    classpath 'org.springframework.boot:spring-boot-gradle-plugin:1.5.1.RELEASE' //Matches the Spring IO version
  }
}

apply plugin: 'java'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'maven'

dependencyManagement {
  dependencies {
    dependency 'cglib:cglib-nodep:3.2.4'
    dependency 'junit:junit:4.12'
  }
}

////Uncommenting this causes nothing at all to be deployed:
//jar.enabled = false
//configurations.archives.artifacts.with { archives ->
//  archives.removeAll { it.type == 'jar' }
//}

The above correctly produces and installs the following POM file into my local Maven repo:

<?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>test</groupId>
  <artifactId>gradle-pom-packaging-test</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib-nodep</artifactId>
        <version>3.2.4</version>
      </dependency>
      <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
      </dependency>
    </dependencies>
  </dependencyManagement>
</project>

However, it also installs a JAR file that is empty save for the MANIFEST.MF file.

I was able to successfully get this working using the maven-publish plugin. However, I'm also making use of the Gradle Sonatype Nexus plugin to publish the artifact to a Nexus instance. As this builds upon the maven plugin, the maven-publish plugin will not work for my needs. The following is all I needed to add to get it working with the maven-publish plugin:

apply plugin: 'maven-publish'
publishing {
  publications {
    maven(MavenPublication) {
    }
  }
}

Is there a way to generate and deploy just the POM file using the maven Gradle plugin, like I would be able to do if this were a Maven project with a "pom" packaging?

like image 276
M. Justin Avatar asked Apr 12 '17 16:04

M. Justin


People also ask

Can I use a Gradle plugin in Maven?

Gradle ships with a Maven plugin, which adds support to convert a Gradle file to a Maven POM file. It can also deploy artifacts to Maven repositories. The plugin uses the group and the version present in the Gradle file and adds them to the POM file. Also, it automatically takes the artifactId from the directory name.

What is Maven BOM in Gradle?

Maven's dependency management includes the concept of a bill-of-materials (bom). A bom is a special kind of pom that is used to control the versions of a project's dependencies and provides a central place to define and update those versions.

How create POM XML from Gradle?

You can name the task createPom to anyTaskName as you like. Then just run gradle clean or grale build or simply gradle createPom . This will generate it as pom. xml in the root of the project.

Can I use Gradle instead of Maven?

In the end, what you choose will depend primarily on what you need. Gradle is more powerful. However, there are times that you really do not need most of the features and functionalities it offers. Maven might be best for small projects, while Gradle is best for bigger projects.


4 Answers

In Gradle 6+ versions, we can use Gradle Java Platform Plugin to publish a maven-bom without many configurations and scripting.

group 'test.platform.simple.bom'
version '1.0.0-SNAPSHOT'

repositories {
    maven {
        mavenCentral()
    }        
}

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

javaPlatform {
    allowDependencies()
}

dependencies {
    constraints {
        api 'junit:junit:4.12'
        api 'cglib:cglib-nodep:3.2.4'
        // runtime 'org.postgresql:postgresql:42.2.5' <-- runtime constraint
        // api project(":core") <-- constraint from local project
    }

    // api platform('com.fasterxml.jackson:jackson-bom:2.9.8') <-- constraint from another platform
}

publishing {
  publications {
    maven(MavenPublication) {
      from components.javaPlatform
    }
  }
}

Dependencies to be managed can be defined under dependencies as api or runtime constraints. Constraints can be utilized to manage dependencies from a local project as well as from another platform/bom. Please note that we need to configure a Maven publication that uses the javaPlatform component to get it published as a maven bom artifact.

like image 66
Kavindu R Avatar answered Oct 19 '22 09:10

Kavindu R


Tha acdcjunior's answer can be improved a little. Dependencies in the build.gradle can by declared in the standard dependencies section. Also, in pom.xml of a BOM versions should be declared in dependencyManagement section:

plugins {
    id 'java-library'
    id 'maven-publish'
}

group = 'com.example'
version = '1.0.0'

repositories {
    mavenCentral()
}

dependencies {
    api 'org.apache.commons:commons-lang3:3.9'
    api 'org.postgresql:postgresql:42.2.11'
}

publishing {
    repositories {
        maven {
            url = "$nexusUrl"
            credentials {
                username = "$nexusUsername"
                password = "$nexusPassword"
            }
        }
    }

    publications {
        maven(MavenPublication) {
            groupId = "${project.group}"
            artifactId = "${project.name}"
            version = "${project.version}"

            pom.withXml {
                asNode().children().last() + {
                    resolveStrategy = Closure.DELEGATE_FIRST

                    name 'My BOM'
                    description 'My Bill of Materials (BOM)'

                    dependencyManagement {
                        dependencies {
                            project.configurations.each { conf ->
                                conf.dependencies.each { dep ->
                                    dependency {
                                        groupId "${dep.group}"
                                        artifactId "${dep.name}"
                                        version "${dep.version}"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

The resulting pom.xml can be published to Nexus with the command

./gradlew clean build publish -i

or to a local Maven repo (~/.m2/repository)

./gradlew clean build pTML -i

This notation is not only shorter but also allows processing dependencies. For example, perform vulnerabilities scanning using OWASP Dependency-Check plugin:

plugins {
    //...
    id 'org.owasp.dependencycheck' version '5.3.0'
}

dependencyCheck {
    failBuildOnCVSS = 9 //Critical Severity
}

check.dependsOn dependencyCheckAnalyze
like image 31
Evgeniy Khyst Avatar answered Oct 19 '22 08:10

Evgeniy Khyst


You could have a build.gradle such as:

apply plugin: 'maven-publish'
apply plugin: 'signing'

publishing {
    repositories {
        maven {
            def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
            def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/"
            url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
            credentials {
                username ossrhUsername
                password ossrhPassword
            }
        }
    }

    publications {
        maven(MavenPublication) {
            groupId = 'com.example.id'
            artifactId = 'my-artifact-id'
            version = '1.0.0'

            pom.withXml {
                asNode().children().last() + {
                    resolveStrategy = Closure.DELEGATE_FIRST

                    name 'My Lib Name'
                    description 'My Lib Description'
                    url 'https://example.com/id/lib'

                    licenses {
                        license {
                            name 'The Apache License, Version 2.0'
                            url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                        }
                    }
                    scm {
                        connection 'scm:git:[email protected]:acdcjunior/lib/id.git'
                        developerConnection 'scm:git:[email protected]:acdcjunior/lib/id.git'
                        url '[email protected]/id.git'
                    }
                    developers {
                        developer {
                            id 'someone'
                            name 'Someone Name'
                            email '[email protected]'
                        }
                    }
                    dependencies {
                        dependency {
                            groupId 'com.example.other'
                            artifactId 'some-dependency'
                            version '1.0.0'
                        }
                        dependency {
                            groupId 'org.apache.commons'
                            artifactId 'commons-lang3'
                            version '3.9'
                        }
                    }
                }
            }
        }
    }
}

signing {
    sign publishing.publications.maven
}

Example of a project using this: https://github.com/acdcjunior/domain-id/blob/master/domain-id-all/build.gradle

like image 2
acdcjunior Avatar answered Oct 19 '22 08:10

acdcjunior


You should consider that plugin which has a DSL to create BOMs the gradle way :

https://github.com/xvik/gradle-pom-plugin

Julien

like image 1
Julien Lafourcade Avatar answered Oct 19 '22 09:10

Julien Lafourcade