繁体   English   中英

使用功能分支时避免 Maven 存储库版本冲突

[英]Avoiding maven repository version collision when using feature branches

问题:您如何处理 Maven 多项目构建的功能分支?

Jenkins 构建和部署这些分支以将开发人员的构建开销保持在最低限度,但开发和功能分支不能构建相同的 Maven 版本,否则我们可能会面临工件和源代码不匹配的风险。

我们有一个脚本来更改子 pom 中的父版本和根 pom 中的版本。 虽然这会隔离 Maven 空间中的分支,但合并时会导致额外的工作。

我认为 nexus pro 暂存功能可能会帮助我们避免这种要求,并使每个功能分支使用一个特定的存储库,我们可以在分支删除/合并后轻松删除该存储库。

再次:如何处理多个分支和maven的问题?

以下方法如何:

  • 使用buildnumber-maven-plugin从 git 中获取信息并填充特定的 Maven 属性(我们对scmBranch属性(即当前的 git 分支)特别感兴趣)
  • 使用build-helper-maven-plugin检查我们是否在功能分支中(通过正则表达式,不包括masterdevelop等知名分支)并填充(或不)新的 Maven 属性,例如branch.classifier
  • 使用maven-jar-plugin在生成的工件上设置分类器,基于上一步设置的内容,即使用新的branch.classifier属性:如果为空,则不应用分类器(默认行为,应用于develop分支,例如); 否则将动态应用以当前分支命名的分类器。

这是一个最小的例子:

<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>buildnumber-maven-plugin</artifactId>
            <version>1.4</version>
            <executions>
                <execution>
                    <phase>validate</phase>
                    <goals>
                        <goal>create</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>build-helper-maven-plugin</artifactId>
            <version>1.10</version>
            <executions>
                <execution>
                    <id>regex-property</id>
                    <goals>
                        <goal>regex-property</goal>
                    </goals>
                    <configuration>
                        <name>branch.classifier</name>
                        <value>${scmBranch}</value>
                        <regex>(^develop)|(^master)|(^release.*)</regex>
                        <replacement></replacement>
                        <failIfNoMatch>false</failIfNoMatch>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <artifactId>maven-jar-plugin</artifactId>
            <version>3.0.2</version>
            <configuration>
                <classifier>${branch.classifier}</classifier>
            </configuration>
        </plugin>
    </plugins>
</build>

下面的代码片段基本上是动态填充scmBranch属性,然后仅当与developmasterrelease*不同时才将branch.classifier设置为其值,然后将其设置为分类器。

这种方法的主要优点

  • 不会应用 pom 更改,因此根本没有合并问题
  • 在 Nexus 上工作在相同版本的项目但在不同的分支上没有冲突:分类的工件将具有不同的Maven 坐标,即 GAV (groupId, artifactId, version) 成为唯一的 GAVC (+classifier)
  • 这实际上是工件的classifier属性的一个有意义的用法:

    分类器允许区分由相同 POM 构建但内容不同的工件。

  • 生成的工件在 Nexus 中将根据其源分支动态不同,因此具有隐式可追溯性:没有开发人员的干预(没有容易出错的隐式约定),没有 CI 作业的干预(更容易维护),完全透明
  • 使用分类器,将更容易将分支生成的工件用作 maven 依赖项(例如,在库项目的情况下):我想使用当前在分支 xxx 上开发的依赖项

例子
因此,您将生成以下工件:

  • develop :例如project-1.0.0-SNAPSHOT.jar (空分类器,因此未应用,由正则表达式处理)
  • 在处理featureA :例如project-1.0.0-SNAPSHOT-featureA.jar
  • 处理hotfix-JIRA123 :例如project-1.0.0-hotfix-JIRA123.jar
  • 在处理release-sprint42 :这取决于你,我添加了这种情况来不应用分支名称,仅仅是因为在这些情况下我更喜欢为发布候选者明确设置一个特殊的分类器RC<number> ,但这是一个问题对于约定/品味/习惯,您也可以在此分支上应用相同的方法,只要不会在 Nexus 上产生冲突。 另请注意:当使用 JIRA/Stash/Git 集成时,发布分支名称通常类似于release/v0.1.0 ,其中/字符可能会导致某些操作系统出现问题(如果确实需要,仍然可以通过进一步的正则表达式替换来修复) .
  • master工作时:嘿,没有人应该在master工作 :) 这种情况只是作为一个双重检查,但这实际上不是必需的

这种方法的警告

  • 正如下面通过评论的讨论中所解释的,如果相关的 Maven 项目已经在使用分类器,甚至更多地通过模块间的依赖关系(例如对来自另一个模块的测试范围类的依赖),那么应该仔细测试这种方法,因为它可能有一些缺点
  • 包含分支分类器的<artifactId>.pom文件的发布可能会与主线构建发生冲突(即覆盖它)

当从顶级父级运行时,这不起作用在整个构建和 GC 错误中导致警告。

理想情况下,我们希望使用版本来区分特征分支和主线,因为这是正常的 Maven 方式,并且分类器操作会导致各种问题。

由于 maven 可以将环境变量用于属性,并且我们已经使用脚本初始化了构建环境(我们还有 git hook 脚本可以从分支名称设置环境变量)我们可以使用 env 来控制版本。

<groupID>my.project</groupId>
<artifactID>database</artifactId>
<version>1.2.0${env.BRANCHMODIFIER}-SNAPSHOT</version>

如果在开发我们的脚本时将BRANCHMODIFIER设置为“”
如果在 feature/JIRA-30495 上,我们的脚本将BRANCHMODIFIER设置为“.30495”

这在 eclipse 或 Intellij 中是如何工作的? 目前还没有任何线索。

我们使用与 Peter Kahn 类似的技术,在构建之前修改分支的版本。 我们的“准备步骤”分为三个步骤:

  1. 执行shell: echo VERSION=$(echo ${GIT_BRANCH} | sed 's_^.*\\/__') > env.properties
  2. 注入环境变量: env.properties
  3. 调用顶级 Maven 目标: versions:set -DgenerateBackupPoms=false -DnewVersion=${VERSION}-SNAPSHOT

我很确定这可以通过两个甚至一个步骤来完成,也可以只执行一步,其背后的原理是相同的。

我们之所以不直接在分支中更改pom.xml文件中的版本,确实是在合并。 使用 SVN,这是可能的(与--accept-mine-conflict合并。使用 GIT,这不再存在,因此我们停止更改版本并创建此预构建步骤。

对于 Maven ge 3.5.0,试试这个https://maven.apache.org/maven-ci-friendly.html这是推荐的 Maven 解决方案。 唯一的问题(但不寻常)可能是 maven 依赖项的数字版本解析。 但这只会出现,如果您使用模块的不同 SNAPSHOT 依赖项,无论如何这都是一个坏主意。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM