Jenkins构建了一个由许多Maven项目组成的产品?(使用Jenkins Pipeline插件?)

Mar*_*ica 21 maven jenkins maven-module jenkins-workflow maven-dependency

我们的产品由许多相互依赖的Maven项目组成.所有这些Maven项目都汇集在一个项目中,提供最终产品.

Maven项目共享相同的生命周期.换句话说,他们不是由单独的团队管理,他们有明确的<dependency>变化来获取其他项目的新版本.相反,当有人在某个项目中更改某些内容时,结果应该直接进入最终产品,而无需进行其他更改.

我们使用Jenkins作为持续集成工具.

我们的主要愿望如下:

  • 无需将所有项目间依赖项复制到Jenkins配置:这些应该在一个地方,理想情况下是pom.xml文件.
  • 避免不必要的构建:在SCM更改时,仅构建可能受影响的项目.
  • 钻石依赖性的情况下(C取决于B1和B2,它们都依赖于A),如果最低(A)被改变,那么最终产品(C)应该总是使用也用于构建的A的版本/测试B1和B2.

问题:使用Jenkins执行此操作的最佳方法是什么?

我们目前正在考虑使用Jenkins Pipeline插件来使用单个作业,该插件分析Maven依赖关系和SCM更改,决定需要构建什么以及以何种顺序构建,然后实际构建项目.

A_D*_*teo 24

为了满足您的要求,您可以依赖maven多模块构建的许多默认功能以及下面介绍的其他配置.

从你的问题:

无需将所有项目间依赖项复制到Jenkins配置:这些应该在一个地方,理想情况下是pom.xml文件.

使用聚合器/多模块pom,您可以为maven构建提供单个入口点(pom.xml文件),然后构建所有已定义的模块:

具有模块的项目称为多模块或聚合器项目.模块是此POM列出的项目,并作为一个组执行.pom打包项目可以通过将它们列为模块来聚合一组项目的构建,这些模块是这些项目的相对目录.

也就是说,pom.xml文件如下:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.sample</groupId>
    <artifactId>project</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>

    <modules>
        <module>module-1</module>
        <module>module-2</module>
        <module>module-n</module>
    </modules>
</project>
Run Code Online (Sandbox Code Playgroud)

这是一个最小的例子:定义一个模块列表(其他maven项目),这些模块将从这个maven项目开始构建(一个空项目,其唯一目的是构建其他maven项目).注意包含模块所需的pom包装,它告诉maven这个项目只提供一个pom(没有其他工件).

因此,您可以拥有一个根Maven聚合器项目,该项目将其他maven项目定义为其模块,并且具有构建此入口点的单个Jenkins作业.


另外,从您的问题:

避免不必要的构建:在SCM更改时,仅构建可能受影响的项目.

要满足此要求,您可以使用incremental-build-plugin:

因为它在一个独特项目的模块上寻找修改,所以Maven Incremental Plugin只对多模块项目有所了解.如果检测到模块上的修改,则删除输出目录.

此插件将验证任何pom文件,资源,源,测试源,测试资源是否会在模块中更改以及是否移除其输出目录.因此,为整个多模块项目(在本例中为我们自己的构建)保存相关模块和链中的构建时间.

要启用此机制,您可以在上面的聚合器pom中配置以下内容:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.sample</groupId>
    <artifactId>project</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>
    <modules>
        <module>module-1</module>
        <module>module-2</module>
        <module>module-n</module>
    </modules>

    <properties>
        <skip.incremental>true</skip.incremental>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>net.java.maven-incremental-build</groupId>
                <artifactId>incremental-build-plugin</artifactId>
                <version>1.6</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>incremental-build</goal>
                        </goals>
                        <configuration>
                            <noIncrementalBuild>${skip.incremental}</noIncrementalBuild>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
Run Code Online (Sandbox Code Playgroud)

上面,我们简单地添加了incremental-build-plugin聚合器构建和属性,skip.incremental它将跳过第一个构建的插件执行,空聚合器,同时将其启用到模块中,如下所示:

<project>
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.sample</groupId>
        <artifactId>project</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>simple-module</artifactId>

    <properties>
        <skip.incremental>false</skip.incremental>
    </properties>
</project>
Run Code Online (Sandbox Code Playgroud)

注意:在示例模块的上面的pom中,我们将聚合器pom文件指向父级,因此将maven继承与聚合(经典用法)结合使用,因此具有多模块构建和提供的公共构建治理由所有已声明模块的公共父级(在这种情况下,公共构建治理提供了其他incremental-build-plugin配置).此外,每个模块重新配置skip.incremental属性以不跳过上述插件.这是一个技巧:现在插件只会在模块中执行,而不是在它的根目录中执行(这没有意义,在这种情况下实际上会抛出错误).

显然,在相关的Jenkins工作中,在其源代码管理部分,我们不必在每个构建中配置一个全新的签出,否则不会检测到任何更改(并且每次从零开始,这是实际上是发布版本的良好实践).

此外,您的maven命令不应该调用clean生命周期,这也会删除target每个版本,因此也不会检测到任何更改.


此外,从您的问题:

在'钻石依赖性'的情况下(C取决于B1和B2,它们都依赖于A),如果最低(A)被改变,那么最终产品(C)应该总是使用也被使用的A的版本构建/测试B1和B2.

作为多模块构建及其反应堆机制的一部分,Maven将负责此要求:

Maven中处理多模块项目的机制称为反应堆.Maven核心的这一部分执行以下操作:

  • 收集要构建的所有可用模块
  • 将项目排序为正确的构建顺序
  • 按顺序构建选定的项目

默认情况下,反应器也将创建构建顺序,并始终其依赖/使用者模块之前构建模块.这也意味着最后构建的模块实际上将是负责构建最终工件的模块,可交付产品取决于部分或全部其他模块(例如,负责传递war文件的模块可能是最后一个模块构建一个多模块的webapp项目).


关于Maven的进一步相关阅读和当事情不变时的跳过动作:

  • maven-jar-plugin提供forceCreation的默认情况下已启用

    即使没有任何内容似乎已更改,也需要jar插件来构建新的JAR.默认情况下,此插件会查看输出jar是否存在且输入是否未更改.如果这些条件为真,则插件会跳过jar的创建.

  • maven-compiler-plugin提供了useIncrementalCompilation,虽然工作不正常的时刻.
  • maven-war-plugin提供了recompressZippedFiles可能也可以用来加快构建和避免重复做一些事情(切换到选项false在这种情况下):

    指示是否应再次压缩添加到战争中的zip存档(jar,zip等).再次压缩可能会导致较小的存档大小,但会显着延长执行时间.
    默认值:true


更新

Maven项目共享相同的生命周期.

此要求还将强制使用聚合器/多模块项目,但也可能适用于通过依赖关系链接的不同项目.

它们不是由具有明确更改的单独团队管理,以获取其他项目的较新版本.

这一点还强制使用多模块项目.在多模块项目中,模块之间可能有不同的版本,但通常的做法和准则是共享相同的版本,由父项目(聚合器)定义并在其模块中级联.因此,它的集中化和治理将避免错位和错误.

当有人在其中一个项目中更改某些内容时,结果应直接进入最终产品,而无需进行其他更改.

同样,这将由多模块项目自动处理.每个使用SNAPSHOT版本的不同项目都会发生同样的情况,因此无需在其消费者项目(负责构建最终产品的项目)中更改依赖项版本.但是,虽然SNAPSHOT版本在开发过程中非常有用(并且推荐),但在交付最终产品时绝对不能使用它们,因为构建可重复性会有危险(也就是说,您可能无法在以后重新构建相同版本因为它依赖于SNAPSHOT版本,因此不是冻结版本).因此,SNAPSHOT不是银弹解决方案,只能在产品的SDLC的某些阶段使用,而不能作为最终的冷冻解决方案.


更新2
值得看看Maven 3.3.1+和Java 7的新Maven增量模块构建器.

更多细节: