詹金斯正在开发一个由许多Maven项目组成的产品? (使用Jenkins Pipeline插件吗?) [英] Jenkins building a product consisting of many Maven projects? (with Jenkins Pipeline plugin?)

查看:144
本文介绍了詹金斯正在开发一个由许多Maven项目组成的产品? (使用Jenkins Pipeline插件吗?)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

We have a product that consists of many Maven projects that depend on each other. All of these Maven projects come together in a single project which delivers the end product.

Maven项目具有相同的生命周期.换句话说,它们不是由单独的团队进行管理的,这些团队具有显式的<dependency>更改以选择其他项目的较新版本.相反,当某人在其中一个项目中进行了某些更改时,结果应直接进入最终产品,而无需进行其他更改.

The Maven projects share the same life cycle. In other words, they are not managed by separate teams of people with explicit <dependency> changes to pick up newer versions of other projects. Rather, when someone changes something in one of the projects, then the result should go directly into the end product without additional changes.

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

We use Jenkins as our Continuous Integration tool.

我们的主要愿望如下:

  • 无需将所有项目间依赖项都复制到Jenkins配置中:这些应该放在一个位置,最好是pom.xml文件.
  • 避免不必要的构建:在更改SCM时,仅构建可能受影响的项目.
  • 如果存在钻石依赖项(C依赖于B1和B2,都依赖于A),如果最低(A)被更改,则最终产品(C)应始终使用也用于构建/测试B1和B2的A版本.
  • No need to copy all the inter-project dependencies to Jenkins configuration: these should be in a single place, ideally the pom.xml files.
  • Avoid unnecessary builds: on an SCM change, only build the projects that are potentially affected.
  • In case of diamond dependencies (C depends on both B1 and B2, which both depend on A), if the lowest (A) is changed, then the end product (C) should always use the version of A that was also used to build/test B1 and B2.

问题:使用Jenkins的最佳方法是什么?

Question: What is the best approach to do this with Jenkins?

我们目前正在考虑使用Jenkins Pipeline插件使用单个作业,该插件分析Maven依赖关系和SCM更改,确定需要构建的内容和顺序,然后实际构建项目.

We are currently thinking to use a single job using the Jenkins Pipeline plugin, which analyzes the Maven dependencies and the SCM changes, decides what needs to be built and in which order, and then actually build the projects.

推荐答案

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

In order to achieve your requirements you could rely on many of the default features of a maven multi-module build and an additional configuration explained below.

根据您的问题:

无需将所有项目间的依赖项都复制到Jenkins配置中:它们应该放在一个位置,最好是pom.xml文件.

使用聚合器/多模块pom ,您可以有一个入口(一个pom.xml文件)进行Maven构建,然后将构建所有已定义的模块:

Using an aggregator/multi-module pom you can have a single entry point (a pom.xml file) for a maven build which would then build all of the defined modules:

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

A project with modules is known as a multimodule, or aggregator project. Modules are projects that this POM lists, and are executed as a group. An pom packaged project may aggregate the build of a set of projects by listing them as modules, which are relative directories to those projects.

也就是说,是一个pom.xml文件,如下所示:

That is, a pom.xml file like the following:

<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>

是一个最小的示例:定义一个将从该maven项目(一个空项目,仅用于构建其他maven项目)开始构建的模块列表(其他maven项目).请注意具有模块所需的 pom包装,它告诉Maven该项目仅提供绒球(没有其他人工制品).

Is a minimal example: define a list of modules (other maven projects) which will be built starting from this maven project (an empty project which only purpose is to build other maven projects). Note the pom packaging required to have modules, it's telling maven that this project only provides a pom (no further artifacts).

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

You could hence have a root Maven aggregator project which would define the other maven projects as its modules and have a single Jenkins job building this entry point.

另外,根据您的问题:

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

Avoid unnecessary builds: on an SCM change, only build the projects that are potentially affected.

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

To meet this requirement, you could use the incremental-build-plugin:

由于它希望在一个独特项目的模块上进行修改,因此Maven增量插件仅对多模块项目适用.如果检测到模块上的修改,则会删除输出目录.

Because it looks for modification on modules of an unique project, the Maven Incremental Plugin takes it sens only on multi modules projects. If modification on a module is detected, the output directory is removed.

此插件将验证模块中的pom文件,资源,源,测试源,测试资源是否会发生更改,以及是否删除了其输出目录.这样,可以节省相关模块的构建时间,并节省整个多模块项目(在这种情况下,是我们自己的构建)的链式构建.

This plugin will verify whether any of the pom file, resources, sources, test sources, test resources would change in a module and if the case remove its output directory. As such, saving build time for a concerned module and in chain for the whole multi-module project (our own build, in this case).

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

To enable this mechanism, you can configure in the aggregator pom above, the following:

<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>

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

Above, we have simply added the incremental-build-plugin to the aggregator build and a property, skip.incremental, which will skip the plugin execution for the first build, the empty aggregator one, while enabling it into the modules as following:

<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>

注意:在示例模块上方的pom中,我们将聚集器pom文件作为父文件指向,因此使用 maven继承与聚合(经典用法)结合使用,因此具有多模块构建以及由公共父代为所有已声明模块提供的公共构建治理(在这种情况下,构建管理提供了附加的incremental-build-plugin配置).此外,每个模块都重新配置skip.incremental属性,以不跳过上述插件.这是一个把戏:现在,该插件将仅在模块中执行,而不是在其根目录中执行(这没有意义,在这种情况下,实际上会引发错误).

Note: in the pom above of a sample module we are pointing at the aggregator pom file as a parent, hence using maven inheritance in combination with aggregation (a classic usage) and as such having a multi-module build plus a common build governance provided by the common parent for all the declared modules (in this case, the common build governance provides the additional incremental-build-plugin configuration). Moreover, each module re-configures the skip.incremental property to not skip the aforementioned plugin. That's a trick: now the plugin will only be executed in modules, not in its root (which would not make sense and in this case would actually throw an error otherwise).

很显然,在相关的詹金斯(Jenkins)工作中,在其 Source Code Management 部分中,我们不必在每个构建中配置新的新签出,否则,将无法检测到任何更改(并且每次都会从零开始,这实际上是发行版本的好习惯.)

Obviously, in the related Jenkins job, in its Source Code Management section we don't have to configure a fresh new check-out as part of each build, otherwise no changes would be detectable (and everytime it would start from zero, which is a good practice for release builds actually).

此外,您的maven命令不应调用clean生命周期,这也会在每次构建时都删除target,因此也无法检测到更改.

Moreover, your maven command should not invoke the clean lifecycle, which would also remove the target at each build and as such make no change detectable either.

此外,根据您的问题:

如果存在钻石依赖项"(C依赖于B1和B2,都依赖于A),如果最低(A)被更改,则最终产品(C)应始终使用A的版本,即还用于构建/测试B1和B2.

In case of 'diamond dependencies' (C depends on both B1 and B2, which both depend on A), if the lowest (A) is changed, then the end product (C) should always use the version of A that was also used to build/test B1 and B2.

Maven将在多模块构建及其

Maven will take care of this requirement as part of a multi-module build and its reactor mechanism:

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

The mechanism in Maven that handles multi-module projects is referred to as the reactor. This part of the Maven core does the following:

  • 收集所有要构建的模块
  • 将项目按正确的构建顺序排序
  • 按顺序构建所选项目
  • Collects all the available modules to build
  • Sorts the projects into the correct build order
  • Builds the selected projects in order

默认情况下,反应堆还将因此创建一个构建订单,并始终在其依存/消费者模块之前构建一个模块.这也意味着最后构建的模块实际上将是负责构建最终工件的模块,可交付产品取决于其他模块的一部分或全部(例如,负责交付war文件的模块可能是最后一个用于构建多模块的webapp项目.

By default, the reactor will also hence create a build order and always build a module before its dependent/consumer module. That also means that the last built module will actually be the module responsible of building the final artifact, the deliverable product depending on part or all of the other modules (for instance, a module responsible of delivering a war file will probably be the last one to build in a multi-module webapp project).

有关Maven的其他相关阅读内容,当某些内容未更改时跳过动作:

Further related reading concerning Maven and skip actions when something is unchanged:

  • The maven-jar-plugin provides the forceCreation which by default is already enabled

即使所有内容似乎都没有更改,也需要jar插件来构建新的JAR.默认情况下,此插件将查看输出jar是否存在并且输入没有更改.如果满足这些条件,则该插件将跳过创建jar的操作.

Require the jar plugin to build a new JAR even if none of the contents appear to have changed. By default, this plugin looks to see if the output jar exists and inputs have not changed. If these conditions are true, the plugin skips creation of the jar.

  • maven-compiler-plugin 提供了 maven-war-plugin 提供了

  • The maven-compiler-plugin provides the useIncrementalCompilation, although not properly working at the moment.
  • The maven-war-plugin provides the recompressZippedFiles option which could also be used to speed up builds and avoid re-doing something (to switch to false in this case):

    指示是否应再次压缩添加到战争中的zip档案(jar,zip等).再次压缩可以减少存档大小,但执行时间明显更长.
    默认:true

    Indicates if zip archives (jar,zip etc) being added to the war should be compressed again. Compressing again can result in smaller archive size, but gives noticeably longer execution time.
    Default: true

  • 更新

    Maven项目具有相同的生命周期.

    The Maven projects share the same life cycle.

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

    This requirement would also enforce the usage of an aggregator/multi-module project, however may also apply to different projects linked through dependencies indeed.

    他们不是由单独的团队管理的,他们进行了明显的更改以选择其他项目的较新版本.

    they are not managed by separate teams of people with explicit changes to pick up newer versions of other projects.

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

    This point also enforces the usage of a multi-module project. In a multi-module project you may have different versions among modules, however the common practice and guideline is to share the same version, defined by the parent project (the aggregator) and cascaded across its modules. As such, its centralization and governance will avoid misalignments and mistakes.

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

    when someone changes something in one of the projects, then the result should go directly into the end product without additional changes.

    同样,这将由多模块项目自动处理.对于每个使用 SNAPSHOT版本,则无需在其使用者项目(负责构建最终产品的项目)中更改依赖项版本.但是,虽然SNAPSHOT版本在开发过程中确实很有帮助(并建议使用),但在交付最终产品时绝对不应使用它们,因为构建的可复制性将处于危险之中(也就是说,您以后可能无法重新构建相同的版本)因为它依赖于SNAPSHOT版本,因此不是冻结版本).因此,SNAPSHOT并不是灵丹妙药,只能在产品SDLC的某些阶段使用,而不是最终定型和冷冻的溶液.

    Again, this would be handled automatically by a multi-module project. The same would happen with different projects each using SNAPSHOT versions, then no need to change the dependency version in its consumer project (the one responsible of building the final product). However, while SNAPSHOT versions are really helpful (and recommended) during development, they should definitely not be used when delivering the final product since build reproducibility would be in danger (that is, you may not be able to re-build the same version later on since it was relying on SNAPSHOT versions, hence not frozen versions). Hence, SNAPSHOT is not a silver bullet solution and should be used only during certain phases of the SDLC of the product, not as a finalized and frozen solution.

    更新2
    值得一看的还有新的 Maven增量模块生成器 Maven 3.3.1 + 和Java 7 .

    Update 2
    Worth to also look at the new Maven Incremental Module Builder for Maven 3.3.1+ and Java 7.

    更多详细信息:

    • Its Github project
    • Its author blog post (one the main Apache Maven contributors)

    这篇关于詹金斯正在开发一个由许多Maven项目组成的产品? (使用Jenkins Pipeline插件吗?)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆