【问题标题】:Find unresolved maven dependencies in multi-module maven project在多模块maven项目中查找未解决的maven依赖项
【发布时间】:2020-07-15 10:16:21
【问题描述】:

我希望 maven 报告具有以下结构的多模块 maven Java 项目中未解决的依赖关系:

multi-module-java-app/
├── app1
│   ├── pom.xml
│   └── src
├── app2
│   ├── pom.xml
│   └── src
└── pom.xml

pom 在底部。

背景:

Maven 被用作依赖管理和构建工具。 Artifactory 是存储库管理器。工件可以在开发人员的环境或 Jenkins 构建服务器上使用本地 maven 构建。 Artifactory 会定期将工件移动到特殊的 archive 存储库,该存储库是 all 虚拟存储库的一部分。

Maven 将本地构建的工件缓存在运行 Maven 的计算机上的 ~/.m2 目录中,无论是开发人员环境还是构建服务器。

问题

可能会出现几个问题:

在开发人员的虚拟机上进行本地构建可能会成功,但在 Jenkins 中会失败。

本地构建,Jenkins 构建可能会成功,但在其他开发人员的 VM 上会失败。

原因

开发人员 .m2 缓存中存在/缺少工件,构建服务器的 .m2 缓存和/或 archive Artifactory 存储库中缺少工件

建议的解决方案

运行[path_to_maven]mvn dependency:list[path_to_maven] 在项目的根文件夹中有自定义 maven 安装(带有空的 .m2 缓存)。 自定义 maven 还使用 settings.xml 配置为使用特殊的 non-archived 存储库(all 存储库没有 archive)。 输出如下:

它报告未解决的依赖关系以及遗漏它们的依赖工件。 然而,这种解决方案有两个主要缺点:

  1. .m2 缺失会显着减慢检测速度,因为必须下载所有依赖项
  2. 未解决的工件或缺少它们的模块始终是快照。

运行mvn -B -q versions:set -DnewVersion=[some_version] 解决了第二个问题。无论如何,此命令在发布管道期间运行。

但不清楚如何解决第一个问题。

如何在使用.m2时找到未解决的maven依赖,以便在每次推送到特性分支后在Jenkins构建过程中快速检测到未解决的依赖?

唯一的想法是构建服务器上的 .m2 将与 Artifactory 同步。

.m2 在开发人员的机器上也可以使用某种使用 rsync 的自定义插件进行同步。有没有已知的插件可以做到这一点?

最终目标是删除archive 存储库并让构建失败。但是,首先开发人员需要将依赖项与最新版本保持一致。

根 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
 
<project 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>
 
  <groupId>com.mycompany.app</groupId>
  <artifactId>multi-module-java-app</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>pom</packaging>
 
  <name>multi-module-java-app</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>
 
  <pluginRepositories>    
      <pluginRepository>
          <id>plugins</id>
          <name>plugins</name>
          <url>http://localhost:8081/artifactory/all</url>
      </pluginRepository>
  </pluginRepositories>
 
  <repositories>
      <repository>
          <id>all</id>
          <name>all</name>
          <url>http://localhost:8081/artifactory/all</url>
      </repository>
  </repositories>
 
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>com.example</groupId>
        <artifactId>spring-boot</artifactId>        
      </dependency>
    </dependencies>
  </dependencyManagement>
 
  <modules>
      <module>app1</module>
      <module>app2</module>
  </modules>
 
</project>

应用 1 pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
 
<project 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.mycompany.app</groupId>
        <artifactId>multi-module-java-app</artifactId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
  </parent>
  <groupId>com.mycompany.app.app1</groupId>
  <artifactId>app1</artifactId>
  <version>1.0-SNAPSHOT</version>
 
  <name>app1</name>
 
  <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <finalName>${artifactId}</finalName>
                </configuration>
            </plugin>
        </plugins>
  </build>
  <pluginRepositories>    
      <pluginRepository>
          <id>plugins</id>
          <name>plugins</name>
          <url>http://localhost:8081/artifactory/all</url>
      </pluginRepository>
  </pluginRepositories>
 
  <repositories>
      <repository>
          <id>all</id>
          <name>all</name>
          <url>http://localhost:8081/artifactory/all</url>
      </repository>
  </repositories>
 
  <dependencies>
    <dependency>
      <groupId>com.example</groupId>
      <artifactId>spring-boot</artifactId>
      <version>0.0.1-20200510.095344-1</version>
    </dependency>
  </dependencies>
 
</project>

app2 pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
 
<project 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.mycompany.app</groupId>
        <artifactId>multi-module-java-app</artifactId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
  </parent>
  <groupId>com.mycompany.app.app2</groupId>
  <artifactId>app2</artifactId>
  <version>1.0-SNAPSHOT</version>
 
  <name>app2</name>
  <build>
      <plugins>
          <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-jar-plugin</artifactId>
              <configuration>
                  <finalName>${artifactId}</finalName>
              </configuration>
          </plugin>
      </plugins>
  </build>
 
  <pluginRepositories>    
      <pluginRepository>
          <id>plugins</id>
          <name>plugins</name>
          <url>http://localhost:8081/artifactory/all</url>
      </pluginRepository>
  </pluginRepositories>
 
  <repositories>
      <repository>
          <id>all</id>
          <name>all</name>
          <url>http://localhost:8081/artifactory/all</url>
      </repository>
  </repositories>
 
  <dependencies>
    <dependency>
      <groupId>com.example</groupId>
      <artifactId>spring-boot</artifactId>
      <version>0.0.1-20200510.095344-1</version>
    </dependency>
  </dependencies>
 
</project>

【问题讨论】:

  • 哇,这是一个学术背景。问题 1 的一部分是,它根本不是问题。这就是 Maven 的工作原理;您从空的本地 pom 开始,它会解析您列为依赖项(以及传递依赖项)的内容。你想要的是dependency:analyze。这使您的 pom 与您的进口保持一致。干净的 pom 是要走的路。您还可以通过在根 pom 中指定 GAV 依赖项来保持模块版本对齐,但在子模块中仅指定 GA 依赖项。
  • 我不确定为什么开发人员存储库和工件之间存在这种差异。开发人员是否在本地构建和安装尚未发布的依赖项?
  • @tgdavies 是的,父模块和模块在 pom.xml 中有 SNAPSHOT 版本,开发人员需要在推送到功能分支之前验证本地构建是否通过,之后将在 Jenkins 中触发构建,如果未解决应该会失败找到依赖项
  • 我还不明白为什么你不能等到 Jenkins 构建完成。如果依赖项缺失,Jenkins 构建失败,开发者可以修复问题。
  • @JF Meier。这是因为 .m2 缓存存在于 Jenkins 构建服务器和开发人员的机器上。它可能有存档的工件,但 Jenkins .m2 可能没有,反之亦然。即使在不同的开发者机器之间也可能存在 .m2 缓存差异

标签: java maven jenkins artifactory maven-dependency-plugin


【解决方案1】:

我遇到了这个确切的问题,开发人员的本地构建环境与Jenkins Slave 环境不同。在理想情况下,开发人员需要将本地环境与从属环境作为基准,或者在初始开发阶段完成后完全依赖 Jenkins 作业构建。

我很欣赏您尝试提供 .m2 存储库的 automated sync 功能这一事实,这是可行的,但增加了错误和额外日常维护任务的范围,更不用说用户教育问题了。例如,您将如何确保.m2 是最新版本?对于maven dependencies,开发人员最了解,或者他们可能会引入slave 上尚不存在的新依赖项。因此,我建议解决开发人员没有调整他们的依赖关系的根本问题,这与设计相关而不是自动化。

不确定你是否想走这条路,但可以帮助别人:

  1. 消除开发人员在local machines 中对.m2 存储库的需求。如果开发人员的机器遭到破坏或损坏,m2 缓存就会产生问题,并且需要进行更新、审核和协调。
  2. 消除在Jenkins slaves 中对.m2 的需求。这里的问题是,多个从站往往具有不同的.m2 缓存内容,并且从 Artifactory 来回同步,然后开发人员还将其同步到他们的本地声音复杂。没有说所有这些.m2 将在任何时间点同步,并且仍然可以使用n-1 版本执行构建。
  3. 现在没有 .m2 ,我们仍然需要一个地方供开发人员从中提取依赖项。将所有依赖项推送到 Artifactory 中的 repo 并积极维护它。使用setting.xml 功能来提取标准依赖项。如果开发人员通过Eclipse 或其他方式在他的本地机器上构建,则可以使用相同的xml 引用从IDE 本身中提取依赖项,因此开发人员的机器上没有维护本地缓存。
  4. 当构建环境在localJenkins Slave 之间存在细微差别时,这会导致.jar 的大小相同或kilobytes 的大小略有不同。

要识别 jar 文件之间的这种差异,请使用本文中列出的任何工具,它还可以帮助开发人员自行识别哪些依赖项不同步: Comparing two .jar files

如果实现此设计,则包含依赖项的 Artifactory 存储库将成为依赖项的唯一真实来源,您需要与开发人员一起创建一个节奏,以了解如何在该单一来源中更新和使用依赖项的真理。我希望这很有用。

【讨论】:

  • 这个很有用,谢谢。实际上,首先将对齐依赖项,然后再查看。但我仍然,如果没有 .m2,无论本地还是远程构建都会非常缓慢......这就是为什么我要求使用 .m2 解决方案。
  • 谢谢!您是说构建持续时间会很慢还是网络延迟会导致构建很慢,即jenkinsartifactory 之间的防火墙?他们都在同一个网络上吗?
  • 本地构建持续时间会很慢,因为必须在每次构建时重新下载所有依赖项。关于 jenkins 构建,需要确保 jenkinsartifactory 在同一个网络上
  • 将它们放在同一个网络上,解决网络问题可能会更容易。另一件事是我几乎可以肯定Artifactory 不会每次都进行完整的结帐,只有delta 是根据checksum 值结帐的?这也是您可以向 JFrog 查询的内容。
猜你喜欢
  • 2017-05-27
  • 1970-01-01
  • 2013-06-15
  • 2019-11-17
  • 1970-01-01
  • 2020-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多