如何停止 Maven 的验证阶段重建工件?
-
30-09-2019 - |
题
想象一下使用 Maven 构建的 Java 项目,我有:
- 一些快速运行的单元测试:
- 开发人员应该在提交之前运行
- 我的 CI 服务器(Hudson、FWIW)应该在检测到新提交时运行,在出现故障时几乎立即给出反馈
- 一些运行缓慢的自动化验收测试:
- 开发人员可以选择运行,例如重现并修复故障
- 我的 CI 服务器应该在成功运行单元测试后运行
这似乎是一个典型的场景。目前,我正在运行:
- “测试”阶段的单元测试
- “验证”阶段的验收测试
配置了两个 CI 作业,都指向项目的 VCS 分支:
- “Commit Stage”,运行“mvn package”(编译和单元测试代码,构建工件),如果成功,则会触发:
- “自动验收测试”,运行“mvn verify”(设置、运行和拆除验收测试)
问题是作业 2 再次进行单元测试并构建被测工件(因为验证阶段自动调用打包阶段)。由于以下几个原因(重要性逐渐降低),这是不可取的:
- 作业 2 创建的工件可能与作业 1 创建的工件不同(例如如果同时有新的提交)
- 延长了提交给开发人员的反馈循环(即他们需要更长的时间才能发现他们破坏了构建)
- 浪费 CI 服务器资源
所以我的问题是,如何配置作业 2 以使用作业 1 创建的工件?
我意识到我可以只拥有一个运行“mvn verify”的 CI 作业,这只会创建一次工件,但我希望拥有上述单独的 CI 作业,以便实现 Farley 风格的部署管道。
如果它对任何人有帮助,这里是接受的答案中“项目 2”的完整 Maven 2 POM:
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.cake</groupId>
<artifactId>cake-acceptance</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<name>Cake Shop Acceptance Tests</name>
<description>
Runs the automated acceptance tests for the Cake Shop web application.
</description>
<build>
<plugins>
<!-- Compiler -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<!-- Suppress the normal "test" phase; there's no unit tests -->
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.5</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
<!-- Cargo (starts and stops the web container) -->
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.0.5</version>
<executions>
<execution>
<id>start-container</id>
<phase>pre-integration-test</phase>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>stop-container</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- Don't wait for CTRL-C after starting the container -->
<wait>false</wait>
<container>
<containerId>jetty7x</containerId>
<type>embedded</type>
<timeout>20000</timeout>
</container>
<configuration>
<properties>
<cargo.servlet.port>${http.port}</cargo.servlet.port>
</properties>
<deployables>
<deployable>
<groupId>${project.groupId}</groupId>
<artifactId>${target.artifactId}</artifactId>
<type>war</type>
<properties>
<context>${context.path}</context>
</properties>
</deployable>
</deployables>
</configuration>
</configuration>
</plugin>
<!-- Failsafe (runs the acceptance tests) -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>integration-test</id>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
<execution>
<id>verify</id>
<goals>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<includes>
<include>**/*Test.java</include>
</includes>
<skipTests>false</skipTests>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- Add your tests' dependencies here, e.g. Selenium or Sahi,
with "test" scope -->
<dependency>
<!-- The artifact under test -->
<groupId>${project.groupId}</groupId>
<artifactId>${target.artifactId}</artifactId>
<version>${target.version}</version>
<type>war</type>
</dependency>
</dependencies>
<properties>
<!-- The artifact under test -->
<target.artifactId>cake</target.artifactId>
<target.version>0.1.0-SNAPSHOT</target.version>
<context.path>${target.artifactId}</context.path>
<http.port>8081</http.port>
<java.version>1.6</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
请注意,即使这个“测试”项目没有创建工件,它也必须使用某种打包(我在这里使用“jar”),否则在验证阶段不会运行任何测试。
解决方案
尝试两个Maven项目。第一个包含构建和单元测试。您将工件安装在本地存储库中。第二个作业运行第二个Maven项目,该项目将第一个项目的工件称为依赖项,并运行功能测试。
不确定我刚刚描述的场景是否可能是可能的,但我认为是。
为了快速改进,您可以绕过单位测试 -Dmaven.test.skip=true
. 。如果将SCM中代码的修订号传递到第二个作业,则应该能够检查相同的源代码。
您还可以检查Clone Workspace SCM插件。这可能会为您提供一些其他选择。
其他提示
我知道这已经很长时间了,但这是很好的索引,没有任何答案能做什么,但是我发现了一些有效的东西:
mvn failsafe:integration-test
这直接进行了测试,而无需浏览所有构建项目的中间步骤。您可能想添加 failsafe:verify
之后。
因此,我的问题是,如何配置作业2来使用作业1创建的工件?
你不能。
您不需要。这 Maven构建生命周期 是以一种听起来可以满足您需求的方式进行设置。测试生命周期只能运行快速丛林。包装构建您的最终状态而无需进行验证。
您只需要一个CI工作。当CI运行您的Maven部署/安装生命周期时,如果Junits失败,则构建失败,验证脚本将不会执行。
您可以定义仅用于执行集成测试的 Maven 配置文件。我经常这样做。
像这样的东西:
<profiles>
<profile>
<id>integration</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId><version>2.17</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId><version>2.4</version>
<configuration>
<outputDirectory>/tmp</outputDirectory>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
您可以通过以下方式调用它:
mvn verify -Pintegration
不幸的是,WAR 插件不能被跳过,但您可以将其输出发送到某个地方(我使用了 /tmp)。如果你真的想节省毫秒,你也可以让它忽略网络资源(除了 web.xml,没有它它就无法工作)。
您还可以使用配置文件跳过您可能正在运行的任何其他插件,例如程序集插件、Cobertura、PMD 等。
仅执行集成测试的Maven配置文件(如这里所建议的)不够。您还需要确保配置 小杂志 - 补给剂 拥有 useIncrementAlCompilation = false. 。以这种方式运行配置文件,不会自动重新编译,例如:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<useIncrementalCompilation>false</useIncrementalCompilation>
</configuration>
</plugin>