【问题标题】:Gradle maven-publish: How to add testCompile dependencies to generated pom?Gradle maven-publish:如何将 testCompile 依赖项添加到生成的 pom?
【发布时间】:2015-05-03 00:09:44
【问题描述】:

当使用maven-publish(我知道是孵化)发布时,compile 依赖项被添加到生成 POM(在runtime 范围内),但 testCompile 依赖项被忽略。

如何将testCompile 依赖项作为test 作用域放入生成的POM 中?

【问题讨论】:

  • 请解释您为什么要将测试代码发布为工件。这当然不是标准程序。
  • spring-testspring-batch-testjsonpath等测试库,用于基础模块和依赖模块的模块化设置。所以最好在 test 范围内的基本模块中声明它们,就像例如spring-contextruntime 范围内声明。

标签: gradle pom.xml maven-publish


【解决方案1】:

我花了几个小时才找到一种好方法来选择工件或出版物应使用的构建配置,但没有运气。我的发现是,实现它的唯一方法是修改生成的 POM XML,如下所示:

// build.gradle

publishing {
    repositories { /* skipped for brevity */ }

    publications {
        core(MavenPublication) {
            from components.java
            artifactId project.name

            artifact sourcesJar {
                classifier 'sources'
            }
        }

        generators(MavenPublication) {
            from components.java
            artifactId "${project.name}-generators"

            artifacts = [ generatorsJar ]
            artifact generatorsSourcesJar {
                classifier 'sources'
            }

            pom.withXml { pomXml -> replaceDependenciesWith('generatorsBase', pomXml) }
        }
    }
}

void replaceDependenciesWith(String configurationName, XmlProvider pomXml) {
    Node configurationDependencies = new Node(null, 'dependencies')
    project.configurations.getByName(configurationName).allDependencies.each { dep ->
        Node dependency = new Node(null, 'dependency')
        dependency.appendNode('groupId', dep.group)
        dependency.appendNode('artifactId', dep.name)
        dependency.appendNode('version', dep.version)
        dependency.appendNode('scope', 'compile')
        configurationDependencies.append(dependency)
    }
    pomXml.asNode().dependencies*.replaceNode(configurationDependencies)
}

以上在 Gradle 3.3 上工作


评论 Groovy 的类似 XML 构建器的语法

我也尝试使用 Groovy 的类似 XML 构建器的语法,但不幸的是错误的上下文附加到传递给 replaceNode 方法的闭包,因此它不起作用。内联时,它获得与 publications {} 闭包相同的上下文,而当提取到方法时,version dep.version 没有按预期工作)。

// Does not work!
void replaceDependenciesWith(String configurationName, Node pomXmlNode) {
    pomXmlNode.dependencies*.replaceNode {
        dependencies {
            project.configurations.getByName(configurationName).allDependencies.each { dep ->
                dependency {
                    groupId dep.group
                    artifactId dep.name
                    version dep.version
                    scope 'compile'
                }
            }
        }
    }
}

【讨论】:

    【解决方案2】:

    POM 仅在发布工件时使用;它与工件一起上传到 Maven 存储库。因此,POM 只需要运行时依赖。

    Gradle 执行独立于您的部署插件的测试,因此它不使用 POM 文件。

    假设您使用的是 Java 插件,它会添加 test 源集。这又会创建 testCompile 任务。

    现在,Gradle 假设您的运行时依赖项将与您的编译时依赖项相同,如果您不进行其他配置。但是,它只考虑main 源集。这就是为什么您的 POM 不包含 test 依赖项的原因。

    因此,总而言之,配置您的测试依赖项类似于以下内容。然后,快乐地生活,知道发布的工件不会包含您的测试代码或其依赖项。

    dependencies {
        testCompile 'org.springframework:spring-test:4.+'
    }
    

    如果您遇到特殊情况,即在无法访问测试源代码的机器上执行测试,请更详细地描述您的要求。应该可以为测试代码设置单独的输出工件,以便可以发布它,但我仍然认为您不应该将它发布在与main 源集相同的包(或 POM)中。

    【讨论】:

    • 好的,我已经发布了一个单独的artifact testJar,在模块之间共享测试代码。也可以为测试 jar 创建一个额外的 POM,声明外部库,如 spring-test。这可能吗?
    • 您发布测试代码的用例是什么?很抱歉这么坚持,但我认为如果不需要的话,不要在某事上花费精力是很重要的。 =) 是的,您可以声明要发布的更多工件。请参阅 gradle.org/docs/current/userguide/… 了解如何声明您的 publications
    • 没问题,这里有一些关于动机的细节。让我们以初始化内存数据库或测试常量 Java 类的数据库初始化脚本为例。这些由主/基本模块中的单元测试以及依赖模块使用。另一种方法是复制粘贴此类测试资源。
    • 这里为 Maven 说明了多模块设置中的传递测试依赖关系问题:stackoverflow.com/q/15816805/606662
    • 结论似乎是传递性测试依赖关系不被视为正确的做法。因此,我会在每个项目中声明测试依赖项,即使这是重复代码并违反 DRY 原则。
    【解决方案3】:

    当我需要修改 POM xml 时,我无法使用 groovy 语言的任何功能。我不得不像krzychu's answer一样直接依赖API。

    否则 xml 闭包没有像我预期的那样应用,构建失败并出现一些警告,或者没有正确应用闭包导致无效的 pom。

    但最近,在仔细阅读 groovy's closure 文档后,我注意到可以将 resolutionStrategy 应用于闭包,以帮助运行时找到正确的上下文(隐式 this)。

    默认的解析策略是Closure.OWNER_FIRST,这解释了为什么在我的一些试验中我收到关于将闭包应用于publications 的错误。从他们的文档中,我尝试将策略设置为Closure.DELEGATE_FIRST,事实证明这可以正常工作。

    请注意,闭包必须应用于Node,因此.children() 返回一个列表,.last() 返回一个Node,您可以通过.plus(...) 方法或其别名在其上添加另一个节点+.

    publishing {
        publications {
            core(MavenPublication) {
                pom.withXml {
                    def dependenciesNode = 
                        asNode().dependencyManagement
                                .first()
                                .dependencies
                                .first()
    
                    dependenciesNode.children().last().plus( {
                        resolveStrategy = Closure.DELEGATE_FIRST
                        dependency {
                            'groupId'('org.springframework.boot')
                            'artifactId'('spring-boot-dependencies')
                            'version'(rootProject.'spring-boot.version')
                            'type'('pom')
                            'scope'('import')
                        }
                    })
                }
            }
        }
    }
    

    找到正确的语法就像大海捞针,这里有一些链接(1)(2)(3) 帮助我找到了resolutionStrategy

    【讨论】:

      猜你喜欢
      • 2016-06-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-27
      • 1970-01-01
      • 2014-01-09
      • 2016-06-03
      • 2016-07-03
      相关资源
      最近更新 更多