• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

xvik/gradle-pom-plugin: Gradle POM plugin

原作者: [db:作者] 来自: 网络 收藏 邀请

开源软件名称(OpenSource Name):

xvik/gradle-pom-plugin

开源软件地址(OpenSource Url):

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

开源编程语言(OpenSource Language):

Groovy 100.0%

开源软件介绍(OpenSource Introduction):

Gradle POM plugin

License CI Appveyor build status codecov

About

Plugin simplifies maven-publish plugin usage and corrects generated pom.

Plugin should make gradle more familiar for maven users (at least simpler to use). With it, multi-module projects could be organized the same way as maven projects: all dependencies managed in the root project (and, optionally, published as bom).

Features:

  • Fix dependencies scopes in the generated pom
    • Fix war plugin's provided dependencies
  • Add provided and optional configuration (in maven meaning).
  • Add global pom configuration shortcuts (applied to all publications):
    • pom configuration closure (applied to all publications).
    • withPomXml configuration closure for manual xml modifications (same as maven-publish's withXml, but applied for all publications)
  • Moves declared BOMs on top in the generated dependencyManagement section (fixes java-platform behaviour)
  • Automatic pom enhancements could be disabled to see the native gradle behaviour)
  • Optionally, could remove used BOMs, applying resolved versions instead (useful with gradle platforms to simplify resulted poms)
  • Simplifies multi-module projects configuration
  • Compatible with:

If you develop java or groovy library you may look at java-lib plugin which already includes this 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 at 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, pomGeneration, withPomXml
  • Configurations: provided, optional
  • Enable plugins: maven-publish

Setup

Maven Central Gradle Plugin Portal

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

OR

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

Compatibility

Plugin compiled for java 8, compatible with java 11.

Gradle Version
5.0 2.2.1
4.6 1.3.0
older 1.2.0

Snapshots

Snapshots may be used through JitPack
  • Go to JitPack project page
  • Select Commits section and click Get it on commit you want to use (you may need to wait while version builds if no one requested it before) or use master-SNAPSHOT to use the most recent snapshot

For gradle before 6.0 use buildscript block with required commit hash as version:

buildscript {
    repositories {
        maven { url 'https://jitpack.io' }
    }
    dependencies {
        classpath 'ru.vyarus:gradle-pom-plugin:b5a8aee24f'
    }
}
apply plugin: 'ru.vyarus.pom'

For gradle 6.0 and above:

  • Add to settings.gradle (top most!) with required commit hash as version:

    pluginManagement {
        resolutionStrategy {
            eachPlugin {
                if (requested.id.namespace == 'ru.vyarus.pom') {
                    useModule('ru.vyarus:gradle-pom-plugin:b5a8aee24f')
                }
            }
        }
        repositories {
            maven { url 'https://jitpack.io' }
            gradlePluginPortal()          
        }
    }    
  • Use plugin without declaring version:

    plugins {
        id 'ru.vyarus.pom'
    }

Usage

If java, groovy, java-library or java-platform plugins enabled, maven-publish would be registered automatically. For example:

plugins {
    id 'java' // or groovy or java-library
    id 'ru.vyarus.pom'
}
plugins {
    id 'java-platform'
    id 'ru.vyarus.pom'
}

in both cases maven-publish plugin would be activated implicitly.

Configuration closures added when maven-publish plugin registered (and so will be available even if you don't use java plugins above and only register maven-publish manually).

For example the following is also a valid usage:

plugins {
    id 'maven-publish'
    id 'ru.vyarus.pom'
}

Publication must be configured manually, for example:

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

(see java-lib plugin for automatic publication registration)

Maven scopes reference:

Maven scope Gradle configuration
compile implementation, api
runtime runtimeOnly
provided provided (not compileOnly!)
optional optional, feature variants

Also, see good article describing maven/gradle scope analogies.

compileOnly should be used only for compile-time only dependencies like nullability annotations.

api configuration appear only when java-library plugin is enabled. Read this article to better understand api-implementation difference for gradle (or simply use implementaion by default).

Dependencies

Plugin fixes dependencies scopes in the generated pom:

Configuration Fixed scope Native behaviour Note
api compile compile ony with java-library plugin
implementation compile runtime
compileOnly - dependencies not added
runtimeOnly runtime runtime
compile compile compile removed in gradle 7
runtime runtime compile removed in gradle 7
providedCompile provided compile only with war plugin
providedRuntime provided compile only with war plugin

Note: in context of gradle java-library plugin, both api and implementation dependencies stored in pom as compile dependencies because there is only build time difference (it's a gradle optimization) between configurations and module still need implementation dependencies. For the end user they both are usual transitive dependencies and must have compile scope.

For example:

plugins {
    id: 'java'
    id 'ru.vyarus.pom'
}
dependencies {    
    implementation 'com.foo:dep-compile:1.0'
    runtimeOnly 'com.foo:dep-runtime:1.0'
    provided 'com.foo:dep-provided:1.0'
    optional 'com.foo:dep-optional:1.0' 
}

Will result in:

<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>
        <optinoal>true</optinoal>
    </dependency>
</dependencies>

And

plugins {
    id: 'java-library'
    id 'ru.vyarus.pom'
}
dependencies {    
    implementation 'com.foo:dep-compile:1.0'
    api 'com.foo:dep-api-compile:1.0'        
}

Will produce:

<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-api-compile</artifactId>
        <version>1.0</version>
        <scope>compile</scope>
    </dependency>
</dependencies>

NOTE: scope modifications could be disabled with pomGeneration section (see below)

Provided dependencies

Provided dependencies assumed to be present in target environment or already exists in projects consuming library. Provided dependencies will not be loaded as transitive dependencies, they will exist in pom just for consultation.

Additional provided configuration created for provided dependencies. Gradle implementation extends from it so for gradle provided dependencies would be the same as implementation and the difference will only appear in the resulted pom.

compileOnly

Gradle states that compileOnly is the official gradle analog for maven provided scope. But it's not: first of all, gradle does not add such dependencies to pom at all. More importantly, compileOnly dependencies are not visible in other scopes. So, for example, to use these dependencies in test, you'll have to add them again in test scope.

The only application for compileOnly scope is compile-time libraries, like nullability annotations.
This is not a provided scope.

Plugin does not do anything with compileOnly: these dependencies will not be present in the resulted pom.

Make other scopes as provided

If you already have some other scope and want to identify its dependencies in pom as provided then:

configurations.provided.extendsFrom configurations.apt

dependencies {
    implementation 'com.google.code.gson:gson:2.6.2'

    apt 'org.immutables:gson:2.1.19'
}

Suppose apt configuration was added by some plugin. Now, apt dependencies will be marked provided in the resulted pom:

 <dependencies> 
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.6.2</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>org.immutables</groupId>
        <artifactId>gson</artifactId>
        <version>2.1.19</version>
        <scope>provided</scope>
    </dependency>
</dependencies>
War plugin

Gradle war plugin declares it's own provided configurations providedCompile and providedRuntime and these dependencies are not going into resulted war, but contained in the generated pom as compile. Plugin fixes such dependencies scope to provided (how it could be declared in pure maven).

Optional dependencies

Optional dependencies supposed to be used for not required dependencies, for example, activating additional features.

Additional optional configuration created for optional dependencies. Gradle implementation extends from it so for gradle optional dependencies would be the same as implementation and the difference will only appear in the resulted pom.

Feature variants

Gradle states that native replacement for optional dependencies is gradle feature variants. For example:

java {
    registerFeature('someFeature') {
        usingSourceSet(sourceSets.main)
    }     
}

dependencies {                                                       
    someFeatureImplementation 'com.google.code.findbugs:annotations:3.0.0'                
}
<dependencies>
    <dependency>
      <groupId>com.google.code.findbugs</groupId>
      <artifactId>annotations</artifactId>
      <version>3.0.0</version>
      <scope>compile</scope>
      <optional>true</optional>
    </dependency>
</dependencies>

Looks good, but these dependencies will not work as you expect from optionals: these dependencies will not be visible in other scopes. So if you need to test this behavior then you'll have to add another dependency in test scope.

Probably, there is a way to workaround this, but, still, simple things must be done simple, so optional configuration would just do what the majority of library developers need.

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:[email protected]:me/my-repo.git'
        developerConnection 'scm:[email protected]:me/my-repo.git'
    }
    developers {
        developer {
            id "dev1"
            name "Dev1 Name"
            email "[email protected]"
        }
    }
}

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 a 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.

Multiple pom closures may be defined (useful for multi-module projects).

If multiple publications declared, then pom closure will affect all of them. If you need different data in poms then use pom closure only for general info and gradle native dsl for different parts.

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 any reason, you need to modify pom manually (like in withXml closure) you can use withPomXml configuration closure:

pom {
    scm {
        url 'https://github.com/me/my-repo.git'
        connection 'scm:[email protected]:me/my-repo.git'
        developerConnection 'scm:[email protected]: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.

Multiple withPomXml closures could be used (useful for multi-module projects).

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 the 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 generation options

Plugin behaviour could be controlled with pomGeneration closure.

For example, to disable scopes correction:

pomGeneration {
    disableScopesCorrection()
}

(you may use it to see the default gradle behaviour)

All options:

  • disableScopesCorrection() - disable dependencies scopes correction (to see native gradle behaviour)
  • disableBomsReorder() - disable moving declared BOMs on top of dependencyManagement section (to see native gradle behaviour)
  • forceVersions() - always put dependency version, even when platforms or BOM with spring plugin used (use recommended gradle way to force version)
  • removeDependencyManagement() - removes dependencyManagement section from the generated pom and implicitly activates forceVersions() (otherwise pom could become invalid). Useful with gradle platforms (see examples below)

(if you prefer property style declaration then you can use extension fields instead of methods (names differ from methods!): forcedVersions, removedDependencyManagement, disabledScopesCorrection (e.g. pomGeneration.forcedVersions = true))

Improving BOMs usage

If you use BOMs for dependency management:

dependencies {
    // declare BOM
    implementation platform('com.group:some-bom:1.0')
    // dependency version managed by BOM
    implementation 'com.other.group:some-dep'
}

(could be spring plugin instead of platform, behaviour is the same)

The resulted pom would look like (native behavior):

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.group</groupId>
            <artifactId>some-bom</artifactId>
            <version>1.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <dependency>
        <groupId>com.other.group</groupId>
        <artifactId>some-dep</artifactId>
        <scope>compile</scope>
    </dependency>
</dependencies>

Note that dependency version is not set (assuming resolution through bom).

In order to force dependency versions use:

pomGeneration {
    forceVersions()
}

To completely remove dependency management section from generated pom:

pomGeneration {
    removeDependencyManagement()
}

the resulted pom would become:

<dependencies>
    <dependency>
        <groupId>com.other.group</groupId>
        <artifactId>some-dep</artifactId>
        <version>1.0</version>
        <scope>compile</scope>
    </dependency>
</dependencies>

Gradle platforms are very handy for dependency management in the root project (maven style), but they should not "leak" into resulted poms. See the complete multi-module declaration example below.

Gradle pom dsl

Plugin was initially created when pom declaration in maven-publish plugin was clumsy, but 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/"
    }
}

A


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
houbie/lesscss-gradle-plugin发布时间:2022-06-18
下一篇:
Raul6469/android-gradle-action: Run Android Gradle tasks with GitHub actions发布时间:2022-06-18
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap