Skip to content

xvik/gradle-pom-plugin

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

69 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Gradle POM plugin

License Build Status Appveyor build status codecov

About

Plugin enhance maven-publish plugin behaviour.

Features:

  • Support gradle java-library plugin
  • Adds optional and provided configurations when used with java or groovy plugins (affect only resulted pom)
  • Fix dependencies scopes in generated pom
  • Add pom configuration closure to avoid maven-publish's withXml.
  • Add withPomXml configuration closure to be able to modify xml manually (shortcut for maven-publish's withXml)
  • Compatible with spring's dependency management plugin

Note: Gradle 4.8 provides similar pom dsl: why pom plugin still matter

If you develop java or groovy library you may look to java-lib plugin which already includes pom plugin and configures maven publication for you (don't confuse with gradle's java-library plugin which only declares api and implementation configurations).

If your project is hosted on github you may look to github-info plugin which fills some pom sections for you automatically.

Also, you can use java-library generator to setup new project with all plugins configured.

Summary
  • Configuration closures: pom, withPomXml
  • Configurations: optional, provided (if java-library not enabled)
  • Enable plugins: maven-publish

Setup

IMPORTANT: version 1.3.0 and above

  • Requires gradle 4.6 or above. For lower gradle use version 1.2.0.
  • For gradle 4.8 and above plugin will enable STABLE_PUBLISHING preview feature - disable lazy evaluation of publishing configuration (unification). This is required to overcome hard to track Cannot configure the 'publishing' extension errors. If you need some properties to evaluate lazily wrap them in afterEvaluate inside publishing configuration.
  • In gradle 5 this preview option will be enabled by default.

Releases are published to bintray jcenter, maven central and gradle plugins portal.

JCenter Maven Central

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'ru.vyarus:gradle-pom-plugin:1.3.0'
    }
}
apply plugin: 'ru.vyarus.pom'

OR

plugins {
    id 'ru.vyarus.pom' version '1.3.0'
}

Plugin must be applied after java or groovy plugins. Otherwise it will do nothing.

Usage

Plugin requires java or groovy or java-library plugins to be enabled.

Plugin implicitly applies maven-publish plugin. Publication must be configured manually, for example:

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

Dependencies

dependencies {    
    compile 'com.foo:dep-compile:1.0'
    runtime 'com.foo:dep-runtime:1.0'
    provided 'com.foo:dep-provided:1.0'
    optional 'com.foo:dep-optional:1.0'        
}

Plugin correct dependencies scopes according to configuration, so the resulted pom will contain:

<dependencies>
     <dependency>
        <groupId>com.foo</groupId>
        <artifactId>dep-compile</artifactId>
        <version>1.0</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>com.foo</groupId>
        <artifactId>dep-runtime</artifactId>
        <version>1.0</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>com.foo</groupId>
        <artifactId>dep-provided</artifactId>
        <version>1.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>com.foo</groupId>
        <artifactId>dep-optional</artifactId>
        <version>1.0</version>
        <scope>compile</scope>
        <optional>true</optional>
    </dependency>
</dependencies>

Java and Groovy plugins

Currently (gradle 4), compile and runtime configurations are deprecated in favour of new java-library plugin's api and implementation. Old configurations could still be used (due to legacy reasons, for groovy projects or due to increased memory consumption).

Extra optional and provided configurations registered only if java-library plugin not applied (because otherwise obviously you want to use new configurations and will not use deprecated compile).

Available configurations and the resulted scope in pom:

Configuration Pom scope
compile compile
runtime runtime
optional compile (with optional marker)
provided provided
compileOnly Artifacts not present in pom
runtimeOnly runtime
Provided and optional configurations

Plugin registers provided and optional configurations and makes compile configuration extend them. So, for gradle, provided and optional dependencies will work the same as compile.

Only during pom generation plugin will detect dependencies from provided or optional and mark them accordingly in generated pom.

If you want to include some other configuration dependencies as provided in pom, you can do:

configurations.provided.extendsFrom configurations.myConf

But, don't forget that compile already extends provided, so your configuration will be transitively included into compile. Anyway, in resulted pom all dependencies from myConf will have provided scope.

Java-library plugin

When java-library plugin used, optional and provided configurations are not registered. Use compileOnly instead of provided.

Available configurations and the resulted scope in pom:

Configuration Migrate from (legacy conf. name) Pom scope
api compile compile
implementation compile compile
compileOnly provided Artifacts not present in pom
runtimeOnly runtime runtime
apiElements -- compile
runtimeElements -- runtime

Do not disable plugin's pom modifications, because without it dependencies in pom file will be without version. Plugin will generate dependencyManagement pom section, which will make pom dependencies without version valid.

Pom configuration

By default, maven-publish plugin fills pom only with dependencies and artifact id, group and version. Other information could be configured through pom closure:

pom {
    name 'Project Name'
    description 'My awesome project'
    licenses {
        license {
            name "The MIT License"
            url "http://www.opensource.org/licenses/MIT"
            distribution 'repo'
        }
    }
    scm {
        url 'https://github.com/me/my-repo.git'
        connection 'scm:git@github.com:me/my-repo.git'
        developerConnection 'scm:git@github.com:me/my-repo.git'
    }
    developers {
        developer {
            id "dev1"
            name "Dev1 Name"
            email "dev1@email.com"
        }
    }
}

Closure doesn't restrict structure: any tags may be used. If name and description not specified, they will be applied implicitly from project.name and project.description.

Here is complete example of all possible maven pom sections definition (you can use any tags if needed, not just these).

If pom already have some tags (e.g. set manually with withXml or by some plugin), plugin will override values and properly merge pom. No duplicate tags will be created.

Only one pom closure may be defined: next pom closure completely override previous one. If multiple publications declared, then pom closure will affect all of them. In this case, use it for general info and use gradle native dsl for details.

Clashed tag names

As pom closure is normal groovy closure, you may face situations when tag name clash with some method in your gradle project.

By default there is only one such case:

pom {
    parent {
        name 'name'
        relativePath 'path'
    }
}

relativePath tag will not be present in resulted pom, because it clashes with gradle Project.relativePath method and it will be called instead of "just holding" tag name.

Special prefix '_' may be used in such cases:

pom {
    parent {
        name 'name'
        _relativePath 'path'
    }
}

This prefix will solve clash with real method and will be dropped during xml generation. You can use this prefix with any tag.

Another (standard) solution for this problem is using delegate reference: delegate.relativePath. But, for me, solution with prefix is simpler and easier to read.

Testing

To test resulted pom you can use pom generation task:

$ gradlew generatePomFileForMavenJavaPublication

Note that 'MavenJava' in task name is publication name and in your case task name could be different.

Pom will be generated by default in build/publications/mavenJava/pom-default.xml

Manual pom modification

If for, some any reason, you need to modify pom manually (like in withXml closure) you can use define withPomXml configuration closure:

pom {
    scm {
        url 'https://github.com/me/my-repo.git'
        connection 'scm:git@github.com:me/my-repo.git'
        developerConnection 'scm:git@github.com:me/my-repo.git'
    }    
}

withPomXml {
    it.appendNode('description', 'A demonstration of maven POM customization')
}

Generated pom xml passed to closure as parameter (no need to call asNode() as in gradle withXml block), so block above could declare parameter explicitly

withPomXml { Node node ->
    node.appendNode('description', 'A demonstration of maven POM customization')
}

See Node api and groovy xml guide.

withPomXml called just after pom closure merging into main pom, but before applying default name and description (because you may define them manually). So xml Node passed into closure contains all modification applied by plugin (except default name and description).

NOTE pom plugin uses withXml to apply pom modifications. If other plugins use withXml too and these plugins registered after pom plugin, then their xml modification will be executed after pom plugin and after withPomXml block. Most likely, this will not be an issue, but just keep it in mind when using manual xml modifications.

Pom plugin vs gradle pom dsl

Since gradle 4.8 you can use dsl like in pom plugin in raw gradle:

publishing {
    publications {
        maven(MavenPublication) {
            from components.java
            // native gradle syntax!
            pom {
                name = 'first'
                scm {
                  url = "http://subversion.example.com/svn/project/trunk/"
                }
            }
        }
    }
}

So why use pom plugin now?

Because maven publication configuration could be moved to external plugin (like ru.vyarus.java-lib which configures maven-compatible publication artifacts) and, in this case, only pom should be customized:

plugins {
    id 'ru.vyarus.java-lib'
}

pom {
    name 'first'
    scm {
      url "http://subversion.example.com/svn/project/trunk/"
    }
}

Also, pom plugin applies pom declaration to all registered maven publications which is useful, for example, for gradle plugin where publication is prepared by closed source plugin.

If pom plugin used together with gradle dsl then pom plugin will merge it's configuration into dsl:

plugins {
    id 'ru.vyarus.pom'
}

publishing {
    publications {
        maven(MavenPublication) {
            from components.java
            // native gradle syntax!
            pom {
                name = 'first'
                description = 'desc'
                scm {
                  connection = "scm:svn:http://subversion.example.com/svn/project/trunk/"
                  url = "http://subversion.example.com/svn/project/trunk/"
                }
            }
        }
    }
}

pom {
    name 'custom name'
    scm {
      url "http://custom.url/"
    }
}

And the resulted pom will contain:

<pom>
    <name>custom name</name>
    <description>desc</description>
    <scm>
        <connection>scm:svn:http://subversion.example.com/svn/project/trunk/</connection>
        <url>http://custom.url/</url>            
    </scm>
</pom>

Plus, pom plugin automatically fixes dependencies scopes, which is also important.

Might also like


gradle plugin generator