5.2 build 工具的使用方法
本节将对实现 CI 所需的 build 工具的使用方法进行简单的讲解。
虽说 build 自动化是实现 CI 所必不可少的,但是没有实现 build 自动化的开发现场并不在少数。像 Java 这样比较多地使用 IDE(Integrated Development Environment,集成开发环境)进行开发的现场,特别普遍。
IDE 将编译(compile)、build、程序的启动,到测试的执行等所有流程进行了半自动化封装,用起来的确非常方便。但几乎所有的操作都要通过 GUI 来设置,在实施 build 自动化时反而会成为阻碍。与之相对,使用脚本语言的开发现场由于缺乏 IDE 的支持,比较多见的是从一开始就使用 build 工具来实施自动化。
还有一些开发现场是开发人员用 IDE 进行 build,负责 build 的人员用 Ant 这样的工具重新 build 后再实施 QA 和部署。这样的做法会造成开发时和 QA 时的 build 方法产生差异,所以应该避免这样的做法。
确保开发人员、测试人员、负责 build 的人员、负责发布的人员都能使用相同的方法进行 build,这对于 CI 的实现是非常重要的。因此开发人员也应该从一开始就使用 build 工具来构建开发环境。
build 工具种类繁多,请根据使用的语言以及开发环境来选择合适的 build 工具。
5.2.1 新建工程的情况
这里以 Java 为例进行讲解。
开始新的工程,使用 Maven 等工具从零创建工程的雏形。
Maven 是根据 CoC(Convention over Configration,惯例优先原则)的思想而设计的 build 工具。其目录的构成等都有明确的规定,能够高效地进行 build。Maven 的安装方法请参考相关网站 20 或书籍 21 。撰写本书时(2014 年 3 月)Maven 的最新版本是 322 。
21
22 国内的相关书籍以及网站上的内容几乎都是关于 Maven3 的,这点请注意。Maven3 最大限度地考虑了和 Maven2 之间的兼容性,因此在 Maven2 上能够运行的在 Maven3 上基本都能运行,但也有例外。还需要注意 Maven1,Maven1 和 Maven2、Maven3 并不兼容。参考网络上的资料时,请一定要注意 Maven 的版本。——译者注
Maven 工程雏形的创建方式有两种:从命令行创建和通过 IDE 的 GUI 创建。
Maven 还是一款能够和 Eclipse 以及 IntelliJ IDEA23 等 IDE 紧密结合的工具,能够通过 IDE 的 GUI 进行设置。但 Maven 原本是作为命令行工具设计的,因此应该尽可能地通过命令行来调用,这样会省去很多麻烦。
23 http://www.jetbrains.com/idea/
这里将简单介绍从命令行创建工程雏形到导入 Eclipse 的过程。
●…… 创建工程雏形
Maven 安装完成后,执行以下命令来创建工程雏形 24 。
24 Maven 会首先从互联网上下载必要的模块,并 build 执行命令的环境。因此第一次启动 Maven 时会执行下载和 build,需要等待一段时间。
$ mvn archetype:generate稍许等待后会出现如下使用何种工程雏形的询问。本书执笔时共有 914 种雏形可供选择。这里使用 Maven 建议的最基本的 344 号工程雏形。确定后按下掉头键。
略 913: remote → tk.skuro:clojure-maven-archetype (A simple Maven archetype for Clojure) 914: remote → uk.ac.rdg.resc:edal-ncwms-based-webapp (-) Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 344:接着会询问雏形的版本、groupId、artifactId 等必要的信息。
Choose org.apache.maven.archetypes:maven-archetype-quickstart version: 1: 1.0-alpha-1 2: 1.0-alpha-2 3: 1.0-alpha-3 4: 1.0-alpha-4 5: 1.0 6: 1.1 Choose a number: 6: Define value for property 'groupId': : com.gmail.ikeike443 Define value for property 'artifactId': : sample Define value for property 'version': 1.0-SNAPSHOT: : Define value for property 'package': com.gmail.ikeike443: :首先要选择 maven-archetype-quickstart 的版本,使用最新的版本(这里是 6:1.1),然后按下掉头。
groupId 会指定区分团队或项目等多个产品的 Id。通常将所属团队的域名等用点分割并倒序显示。这里使用笔者自己的邮件地址。
artifactId 为项目自身的名字,请根据项目设置合适的名字。version 这次直接使用默认值即可。按下掉头。package 通常可以和 groupId 相同,因此使用默认值,按下掉头确认即可。
最后是配置内容的确认,没有问题的话请按下
键。
若输出 BUILD SUCCESS ,就算成功了。Maven 会生成名为 sample 的目录,进入该目录。
$ cd sample可以确认 sample 目录下生成了如下目录结构。
$ tree . ├─── pom.xml └─── src ├─── main │ └─── java │ └─── com │ └─── gmail │ └─── ikeike443 │ └─── App.java └─── test └─── java └─── com └─── gmail └─── ikeike443 └─── AppTest.java 11 directories, 3 filessrc/main/java 是程序代码的目录。src/test/java 是测试代码的目录。像这样,Maven 能够将程序代码和测试代码存放在同一工程的不同目录下。请注意这里的“同一工程”是重点。
为了有效地执行 CI,将应用程序代码和测试代码一同置于版本管理系统中是非常重要的。Maven 就是一款能够简单地实现上述需求的工具。其他的语言也有类似的工具,可以自行选择合适的工具。
Maven 的构成如表 5.2 所示 25 。
25 Maven 还可以用于 Java 以外的 JVM 语言的 build。这时 Maven 一般会在 Java 目录的同一层次中创建以 groovy、scala、jruby 等语言命名的目录。
表 5.2 Maven 的构成
| 目录 / 文件 | 说明 |
|---|---|
| pom.xml | 工程的 build 定义 |
| src/main/java | 程序代码 |
| src/main/resources | 程序资源 |
| src/main/webapp | WEB-INF、JSP 文件等 Web 相关的资源 |
| src/test/java | 测试代码 |
| src/test/resources | 仅供测试使用的资源 |
| target | Class、jar、测试结果等文件 |
●…… 依赖关系的定义
第 3 章中已经提到过,通过在 pom.xml 中使用 <dependencies> 标签定义依赖关系,Maven 会处理所依赖库的传递依赖,将所需要的库添加到 classpath 中。
例如本次的工程雏形中,像下面这样定义 junit 的依赖关系。
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies>这里定义了 JUnit3.8.1,由于 3.8.1 太旧了,请手动改写为 4.1.1 等当时的最新版本。
那么就让我们来试着编译一下。执行如下命令。
$ mvn compile编译后 Maven 会在 target 目录下生成 Class 文件。
●…… 执行测试
这次我们来试着执行测试。虽然 AppTest.java 依赖了 junit,但因为已经在 pom.xml 中定义了依赖关系,所以可以直接执行测试。
$ mvn test [INFO] Scanning for projects… [INFO] [INFO] —————————————————————————————- [INFO] Building sample 1.0-SNAPSHOT [INFO] —————————————————————————————- 略 ———————————————————————————- T E S T S ———————————————————————————- Running com.gmail.ikeike443.AppTest Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.049 sec Results : Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 [INFO] —————————————————————————————- [INFO] BUILD SUCCESS [INFO] —————————————————————————————- [INFO] Total time: 13.282s [INFO] Finished at: Thu May 23 18:06:32 JST 2013 [INFO] Final Memory: 15M/145M [INFO] —————————————————————————————-Maven 会自动处理对 JUnit 的依赖,编译代码并执行测试。
测试结果会在 target/surefire-reports/ 目录下生成,以文本文件和 XML 文件两种形式存储。这个 XML 文件在 Jenkins 生成报告时会起到作用。
使用 Maven 插件,测试结果报告还可以自定义为 HTML 等各类形式,这方面的内容请参考相关资料。
●…… 导入 Eclipse
最后让我们试着导入 Eclipse。运行以下命令即可生成 Eclipse 专用的 .classpath 和 .project 文件。
$ mvn eclipse:eclipse只要从 Eclipse 的菜单导入生成的 .project 文件,就可以用 Eclipse 打开 Maven 工程了。IntelliJ IDEA 和 Netbeans26 也有支持同样功能的插件,可以根据需要使用。
相反,通过 IDE 的 GUI 也可以初始化 Maven 的工程。Eclipse 从 3.7 版(Indigo)开始默认支持 Maven27 。基本上通过新建工程向导就能够创建 Maven 工程。根据向导的提示,一步一步地执行即可。再重复一下,充分使用命令行对于有效地执行 CI 是非常重要的,因此尽可能地 通过命令行来使用 Maven。
27 3.6 版之前的版本需要另行安装名为 m2eclipse 的插件。
5.2.2 为已有工程添加自动 build 功能
新建工程时,使用 Maven 这样的 CoC 的 build 工具来初始化工程是最简单的,但同样存在已有的没有使用 build 工具的工程。这样的情况下,如果是 Java 工程,可以使用 Ant 进行 build。
Ant 不像 Maven 这样有着固定的规则。另外,因为 Ant 运行在 JVM 之上,所以有着不同于 Make 依赖于执行环境的特点。从目录的构成到依赖关系的处理、测试的执行都可以自由地进行定义。因此根据已有的工程编写 build.xml 即可。
Ant 默认定义有 compile 、test 、package 这样的任务,可以利用这些任务快速地进行 build。
但是 Ant 没有默认进行依赖关系管理,因此推荐使用 Ivy28 这款工具。Ivy 是将 Maven 的依赖关系管理功能独立出来的工具,可以结合 Ant 使用。
5.2.3 build 工具的总结
为了实施 CI,首先实现 build 的自动化是非常重要的,可以说是必不可少的。这里以 Java 工程为例,简单地介绍了 build 工具的使用方法。
新建工程请使用 Maven,已有工程请使用 Ant,来开始实施 build 自动化。也可以使用 Gradle。不管选择哪款工具,实现 build 的自动化是非常重要的。
利用 Java 开发 Web 应用程序的情况下,通过结合 Maven 或 Ant 对 jetty、Struts2、Spring、Hibernate 这样的 servlet 容器或各类框架进行 build,可以实现 build 的自动化。
另外也可以使用全栈式的 Play Framework29 作为 Java 的 Web 应用程序框架。Play Framework 虽然不使用 Maven 和 Ant,但默认支持自动化编译以及自动化测试的机制,因此是非常适合于 CI 的框架。
