以编程方式替换 pom.xml 中的依赖版本?

Replace a dependency version in pom.xml programmatically?

假设我有一个 pom.xml 包含这样的父依赖项:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.example</groupId>
        <artifactId>some-parent</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
</project>

有没有一种方法可以通过脚本以编程方式替换 1.0.0-SNAPSHOT 版本?

我的用例:

例如,我可以执行以下操作,但这将更新 pom.xml 中出现的所有 1.0.0-SNAPSHOT,我想将其限制为仅 some-parent 工件有一个版本 1.0.0-SNAPSHOT:

git-xargs \
  --branch-name test-branch \
  --github-org <your-github-org> \
  --commit-message "Update pom.xml" \
  sed -i 's/1.0.0-SNAPSHOT/2.0.1/g' pom.xml

根据 git-xargs 文档,我可以使用任何类型的脚本来处理 pom.xml、bash、python、ruby等:https://github.com/gruntwork-io/git-xargs#how-to-supply-commands-or-scripts-to-run

更新:

以下 xmlstarlet 方法在一定程度上起作用:

if [[ $(xmlstarlet sel -N my=http://maven.apache.org/POM/4.0.0 -t -v '//my:project/my:parent/my:artifactId' pom.xml) == "some-parent" && $(xmlstarlet sel -N my=http://maven.apache.org/POM/4.0.0 -t -v '//my:project/my:parent/my:version' pom.xml) == "1.0.0-SNAPSHOT" ]]; then xmlstarlet edit -L -N my=http://maven.apache.org/POM/4.0.0 --update '//my:project/my:parent/my:version' --value '2.0.6' pom.xml; fi

xmlstarlet 正确更新了我想要的 xml 元素,但它也重新排序了顶部的 xsi:schemaLocationxmlnsxmlns:xsi我的档案。

它更新自:

<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

至:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

这对我不利。

:

虽然您可以将 --if--else 用于 xmlstarlet sel(例如参见 [​​=22=]),但我认为您不能将它们用于 xmlstarlet ed.我几乎从不使用 xmlstarlet,所以我不太确定。
这意味着您必须在 Bash...

内完成
$ if [[ $(xmlstarlet sel -t -v 'parent/version' pom.xml) == "1.0.0-SNAPSHOT" ]]
  then xmlstarlet ed -O -u 'parent/version' -v 2.0.1 pom.xml
  fi
<parent>
  <groupId>com.example</groupId>
  <artifactId>some-parent</artifactId>
  <version>2.0.1</version>
</parent>

:

$ xidel -s pom.xml -e '
  if (parent/version = "1.0.0-SNAPSHOT")
  then x:replace-nodes(parent/version/text(),"2.0.1")
  else .
' --output-node-format=xml
<parent>
    <groupId>com.example</groupId>
    <artifactId>some-parent</artifactId>
    <version>2.0.1</version>
</parent>

如果您希望输出包含 XML 声明,对于 xmlstarlet 删除 -O 选项,对于 xidel 使用 --output-format=xml 代替。

这有效,结合使用了 xmlstarlet 和 mvn:

#! /usr/bin/env bash
if [[ $(xmlstarlet sel -N my=http://maven.apache.org/POM/4.0.0 -t -v '//my:project/my:parent/my:artifactId' pom.xml) == "some-parent" && \
      $(xmlstarlet sel -N my=http://maven.apache.org/POM/4.0.0 -t -v '//my:project/my:parent/my:version' pom.xml) == "4.0.0-SNAPSHOT" ]]; then 
    mvn versions:update-parent -DparentVersion=[4.0.0-661]
    mvn versions:commit
fi

您应该避免使用 xml 作为纯文本文件,但如果您没有其他选择,您可以尝试一下。 sed 范围 (/starting-regex/,/ending-regex/{commands}) 允许在特定上下文中限制您的替换。 IE。这条线:

sed -e '/<parent/,/\/parent/{/artifactId>some-parent/,/parent/{s/1.0.0-SNAPSHOT/2.0.0-SNAPSHOT/g}}'

将仅替换

你可以使用 xq.

只需将某个元素设置为新值就和

一样简单
xq -x '.project.parent.version = "2.0.1"' pom.xml

按条件设置为

xq -x '(.project.parent | select(
  .artifactId == "some-parent" and .version == "1.0.0-SNAPSHOT"
)).version = "2.0.1"' pom.xml

输入样本数据,两者都会产生

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.example</groupId>
    <artifactId>some-parent</artifactId>
    <version>2.0.1</version>
  </parent>
</project>

如您所见,属性的 order 保持不变,但是 indentation 不同,尤其是您的 in-tag 换行符被吞掉了。此外,缺少 XML 声明(第一行),评论,如果存在于输入中。也许这对你也不可行,但请考虑

  • 编辑逻辑结构(而不​​是其文本表示)较少error-prone,
  • 所有这些问题(当然,缺少的注释除外)都可以使用 command-line 可用的众多 XML pretty-printers 之一轻松解决。 This 是一个 (non-exhaustive) 列表,列出了从这里到哪里去。

例如,让我们选择 tidy

有了这个配置

xq -x '…' pom.xml |
tidy -xml -iq -utf8 --indent-with-tabs yes --indent-spaces 4 --tab-size 4 \
  --indent-attributes yes --add-xml-decl yes

你会达到

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.example</groupId>
        <artifactId>some-parent</artifactId>
        <version>2.0.1</version>
    </parent>
</project>

就我所见,这仍然缺少 top-line 声明中的 encoding="UTF-8" (整洁拒绝打印 obvious 声明),以及属性的缩进仍然减少了 1 个字符。如果这仍然是一个问题,请尝试与其他 pretty-printers 一起玩。很有可能您会找到适合完美收尾的那个。