67

我们有一个工作流要求,本质上意味着我们需要从 git 中的当前分支外部定义模块的工件版本。

即,如果我们在 git 的 master 分支上,我需要<version>master-...</version>,如果我们在 bugfixX 分支上,我需要<version>bugfixX-....</version>为这个 pom.xml 生成的工件。

我之前发现https://github.com/koraktor/mavanagaiata可以提供 SHA-1 哈希作为属性,并且从文档中可以看出它也可以提供分支,所以如果它可以在足够早的时候运行我们可以设置属性并放入<version>${our.version}</version>pom 的过程。如果这是可能的,我非常希望看到一个可以工作的 pom.xml(并为此奖励 500 点赏金)。

如果没有,我想我们要么进入预处理,要么“git checkout”用一些钩子做额外的魔法(我还没有尝试过,工作代码也会很棒)。

我们有一个顶级 pom,可以运行它以在“..”中生成一个属性文件,然后再构建我要询问的这个功能需要去的模块。

关于如何解决这个问题的任何建议?

4

7 回答 7

51

事实上,Maven 不能在一次运行中更改它自己项目的版本与其他目标。最重要的是,据我所知,Maven 不支持<version>标签中的任意属性。因此,需要单独执行来运行将更改 POM 版本的目标。有各种插件可以做到这一点 - 对于这种情况,可能会使用插件中的versions:set目标versions- http://mojo.codehaus.org/versions-maven-plugin/set-mojo.html

因此,可以按如下方式执行它,例如:

mvn versions:set -DgenerateBackupPoms=false -DnewVersion=$branch-SNAPSHOT

其中$branch变量必须包含当前 Git 分支名称;它可以用 提取git rev-parse,如下所示:

branch=$(git rev-parse --abbrev-ref HEAD)

但是,仍然需要以某种方式执行它。你可以手动做,但是很麻烦。所以,我的猜测是,确实最强大的解决方案是从 Git 方面解决这个问题。那就是——一个 Git 钩子。这是完成这项工作的完整 Gitpost-checkout钩子(与上面的代码相同,只是在签出分支时运行钩子,而不是单个文件):

#!/bin/bash

echo 'Will change the version in pom.xml files...'

# check if the checkout was to checkout a branch
if [ $3 != '1' ]
    then echo 'git checkout did not checkout a branch - quitting';exit
fi

# get current branch name
branch=$(git rev-parse --abbrev-ref HEAD)
version=$branch-SNAPSHOT

# run maven versions plugin to set new version
mvn versions:set -DgenerateBackupPoms=false -DnewVersion=$version

echo 'Changed version in pom.xml files to $version'

将此内容放入文件PROJECTDIR\.git\hooks\post-checkout文件中。请注意,挂钩文件应该是可执行的以运行它(chmod +x post-checkout)。

关于versions插件的一些注意事项 - 它非常灵活并且支持许多选项并且几乎没有其他可能有帮助的目标,具体取决于您的项目结构(您是否使用父 pom,孩子是否有自己的版本或者它们是否来自父, ETC。)。因此,可以通过使用versions插件中的其他目标或指定其他参数来稍微修改上面的钩子以支持您的特定情况。

优点:

  • 强大的
  • 无需更改 pom.xml 文件本身中的任何内容即可完成此工作
  • 只需停用挂钩(删除或使其不可执行)即可关闭此“功能” - 同样,不需要在 pom.xml 中进行任何更改

缺点:

  • 不能强制其他人使用钩子——它应该在克隆 repo 后手动安装(或者,如果假设的 Git 用户害怕接触 .git 目录中的东西,你可以提供一个脚本来安装钩子)。

更新

之后是更复杂的钩子版本,它不仅会将版本设置为分支名称,还会保留旧版本的后缀。例如,提供旧版本master-1.0-SNAPSHOT,切换到feature1分支会将项目的版本更改为feature1-1.0-SNAPSHOT. 这个 bash 脚本存在一些问题(需要名称中没有短划线符号 ( -) 的分支名称,并且只采用根 pom 的版本),但可以了解如何扩展钩子:给定 mvn 和bash 命令可以提取和更新 POM 中的大量信息。

#!/bin/bash

echo 'Will change the version in pom.xml files...'

# check if the checkout was to checkout a branch
if [ $3 != '1' ]
    then echo 'git checkout did not checkout a branch - quitting';exit
fi

# get current branch name
branch=$(git rev-parse --abbrev-ref HEAD)

# get current version of the top level pom
current_version=$(mvn help:evaluate -Dexpression=project.version | grep -v '\[.*')

# extract version suffix
suffix=$(echo $current_version | cut -d \- -f 2)

# build new version
version=$branch-$suffix

# run maven versions plugin to set new version
mvn versions:set -DgenerateBackupPoms=false -DnewVersion=$version

echo 'Changed version in pom.xml files to $version'
于 2012-12-20T12:54:28.133 回答
18

很抱歉重新提出这个问题并最近发布了另一个解决方案,但确实可以动态更改 maven 版本并使用一些 git 功能,有点像git describe这样做。

执行此操作的项目是jgitver-maven-plugin (免责声明;我是作者),它使用jgitver一个基于 jgit 的库,以便从 git 信息派生 maven 项目版本。

在此处输入图像描述

它很容易用作 maven 扩展

...
  <build>
      <extensions>
          <extension>
              <groupId>fr.brouillard.oss</groupId>
              <artifactId>jgitver-maven-plugin</artifactId>
              <version>0.1.0</version>
          </extension>
      </extensions>
     ...
  </build>
...

该扩展也可以用作插件扩展,然后允许更多配置,例如在您不想使用 SNAPSHOTS 的情况下。有关完整使用场景的描述,请参阅项目页面。

还有一个可用的gradle 插件或多或少是相同的。


[编辑 1]:回答 Thorbjørn Ravn Andersen 评论

该插件不会修改原始 pom 文件或 build.gradle 文件。
对于 maven 插件,修改在 maven 对象模型的内存中完成,并写入临时目录中的临时文件。计算仅基于 git 元数据(标签、提交等)。
这种非修改允许不污染 git 历史记录。当您对 git 提交感到满意时,标记它git tag -a x.y.zmvn deploy: 仅此而已。
项目文件中的版本现在无用,例如可以设置为 0。

截至今天,由于IDEA-155733 ,只有 IntelliJ 的最新 EAP 版本才能与 maven 插件一起使用。Eclipse & Netbeans 没有问题。


于 2016-06-24T07:41:14.507 回答
15

免责声明:我是作者

我的 maven 核心扩展将根据当前分支或标签虚拟设置版本。您可以根据需要配置自定义版本格式模式。

https://github.com/qoomon/maven-branch-versioning-extension

版本格式示例 在此处输入图像描述

于 2017-10-16T04:59:14.467 回答
4

如果在工件文件名中设置 git 标记和版本信息就足够了,可以使用maven-jgit-buildnumber-plugin

<build>
  <finalName>${artifactId}-${git.buildnumber}</finalName>
  <plugins>
    <plugin>
      <groupId>ru.concerteza.buildnumber</groupId>
      <artifactId>maven-jgit-buildnumber-plugin</artifactId>
      <version>1.2.7</version>
      <executions>
        <execution>
          <id>git-buildnumber</id>
          <goals>
            <goal>extract-buildnumber</goal>
          </goals>
          <phase>prepare-package</phase>
        </execution>
      </executions>
    </plugin>
    <!-- more plugins -->
  </plugins>
</build>
于 2014-08-22T16:51:04.220 回答
4

maven-3.5.0开始,版本标签内支持 ${revision}、${sha1} 和 ${changelist} 属性。如果您想将 Git 分支名称合并到 CI 构建作业的版本中,则此功能可能足以满足您的目的。请参阅Maven CI 友好版本

基本上,在您的 pom.xml 中,将固定版本替换为:

<version>${revision}${changelist}</version>

通过创建包含以下内容的文件,在项目根目录中设置修订变更列表.mvn/maven.config的默认值:

-Drevision=1.2.3
-Dchangelist=-SNAPSHOT

将此文件检查到版本控制中,当您遇到项目修订时更新它。

然后,在您的 CI 系统中,您可以使用 Git 分支名称的清理表示覆盖changelist变量,例如。

# sed regex replaces non-(alphanumeric, dot or dash) char sequences with a dash
BRANCHNAME=$(git rev-parse --abbrev-ref HEAD | sed -E -e 's@[^0-9A-Za-z.-]+@-@g')
mvn clean install -Dchangelist="-${BRANCHNAME}"

(您可能更喜欢git symbolic-ref --short HEAD获取分支名称,YMMV)

CI 系统为分支构建的工件feature/branchname将具有版本化分支后缀,例如:

yourproject-1.2.3-feature-branchname.jar

而不使用任何覆盖的开发人员仍将其构建为:

yourproject-1.2.3-SNAPSHOT.jar
于 2018-09-22T15:51:00.700 回答
2

您是否检查过buildnumber-maven-plugin,它使您有机会使用 git 的修订号。但是你需要一些不同的东西。此外,我建议做这样的事情:

   1.0.0-SNAPSHOT 
   1.0.0-SNAPSHOT 

蜂拥而至

在分支上,您可以简单地将版本更改为

  1.0.0-BF-SNAPSHOT 
于 2012-11-27T15:02:13.353 回答
2

你试过使用这个插件吗?:https ://github.com/ktoso/maven-git-commit-id-plugin 。您可以将其配置为生成一个包含有关您的 repo 状态的所有相关信息的属性文件:

  • 分支
  • 描述
  • 提交 ID
  • 构建用户名
  • 建立用户邮箱
  • 构建时间
  • 提交用户名
  • 提交用户电子邮件
  • commitMessageShort
  • commitMessageFull
  • 提交时间
于 2012-12-20T15:37:19.557 回答