Maven Enforcer Plugin缓存未关联依赖树致构建误判如何解决?
问题场景
我们维护的大型多模块Maven项目通过Develocity Maven扩展启用本地及远程构建缓存加速,但遇到Enforcer插件执行结果误判的问题:
- 子模块A依赖子模块B,A配置了Enforcer规则禁止使用特定依赖
- 启用缓存时,A构建生成的缓存键会被复用;当给B添加被禁止的依赖后,A的构建依然命中旧缓存,未触发Enforcer检查(禁用缓存时A构建会正常失败)
- 核心原因是Develocity的缓存输入未将完整依赖树纳入计算,导致依赖变更后缓存键未更新
之前考虑过将依赖树哈希值作为配置输入传递给Enforcer,但实现复杂度太高,以下是更简洁的解决方案:
可行解决方案
1. 让Enforcer依赖dependency:tree目标的输出
Develocity的缓存键会自动包含前置构建目标的输出文件,我们可以让Enforcer的执行依赖dependency:tree生成的依赖树文件,从而让依赖树变化影响缓存键:
首先在A模块的pom.xml中添加dependency:tree的执行,绑定到validate阶段并输出到文件:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>3.6.1</version> <!-- 使用项目中对应版本 --> <executions> <execution> <id>generate-dependency-tree</id> <goals> <goal>tree</goal> </goals> <phase>validate</phase> <configuration> <outputFile>${project.build.directory}/dependency-tree.txt</outputFile> </configuration> </execution> </executions> </plugin>
然后修改Enforcer插件的配置,确保其在dependency:tree之后执行:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <executions> <execution> <id>enforce-banned-dependencies</id> <goals> <goal>enforce</goal> </goals> <phase>validate</phase> <configuration> <rules> <banDependencies> <excludes> <exclude>com.example:forbidden-dependency</exclude> <!-- 你的禁止依赖规则 --> </excludes> </banDependencies> </rules> </configuration> <inherited>false</inherited> </execution> </executions> </plugin>
当B的依赖变更时,dependency-tree.txt的内容会改变,Develocity会将该文件纳入缓存键计算,从而触发A模块的重新构建及Enforcer检查。
2. 配置Develocity显式纳入依赖树作为缓存输入
如果不想调整插件执行顺序,可以直接在Develocity配置中显式添加依赖树文件作为缓存输入:
在项目根目录的.mvn/develocity.xml中添加以下配置:
<develocity> <buildCache> <inputs> <input> <path>${project.build.directory}/dependency-tree.txt</path> </input> </inputs> </buildCache> </develocity>
结合上述dependency:tree生成文件的配置,即可让依赖树变化直接影响缓存键。
3. 启用Enforcer的requireDependencyTree规则
如果你的Enforcer规则本身依赖完整依赖树,可以添加requireDependencyTree规则,强制Maven先解析依赖树,Develocity会自动将依赖解析状态纳入缓存输入:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <executions> <execution> <id>enforce-banned-dependencies</id> <goals> <goal>enforce</goal> </goals> <phase>validate</phase> <configuration> <rules> <!-- 强制先解析完整依赖树 --> <requireDependencyTree/> <banDependencies> <excludes> <exclude>com.example:forbidden-dependency</exclude> </excludes> </banDependencies> </rules> </configuration> </execution> </executions> </plugin>
这个规则会确保依赖树已被解析,依赖变更时缓存键会自动更新,触发Enforcer重新检查。
内容的提问来源于stack exchange,提问作者Kevin Nammour

