(8) Build 编译
就是告诉 Jenkins 如何来构建系统,也就是说:Jenkins只是一个自动化的构建系统,具体的编译过程,可以由用户自己来决定,有如下选择项目:
我们这里选择直接执行脚本(Execute Shell),输入如下指令:
(9) Post-build Actions 编译后操作
告诉 Jenkins: 编译一个工程之后,需要做哪些事情?例如:发送邮件,触发下一个工程的自动编译等等,而且可以添加多个动作。可选项如下:
以上步骤配置好之后,Save 保存,此时在主界面就可以看到这个项目的全貌了,如下图:
在 Jenkins 后台中,这个项目的保存路径是:/var/lib/jenkins/jobs/Test1。
6. 手动触发编译一次
由于在上面的步骤(6)中,我们没有选择任何触发条件,所以需要我们在项目 Test1 的主界面中,手动单击左侧的 Build Now 按钮来触发。
此时,在左侧的 Build History 中,可以看到编译历史记录,单击某次编译记录编号,可以看到这一次编译的详细信息。
在编译详细信息中,单击左侧的 Console Output 按钮,可以看到编译的输出信息:成功编译得到可执行文件。
我们可以在 Jenkins 后台中看到,源代码被拉到 /var/lib/jenkins/jobs/Test1/workspace 目录中了:
到这里,你已经学会了 Jenkins 的最基本操作!
下面我们继续讲一下 git submodule 的使用,这部分才是核心内容!
三、git submodule 基本使用
1. git submodule 是什么?
git submodule 是用于多模块管理的工具,它允许一个项目作为 repository,其他项目作为子模块存在于在父项目中。
父项目和子项目的提交是分开的,也就是说父项目提交的信息只包含子项目的信息,而不会包含子项目的代码;子项目有自己独立的 commit,push,pull操作。
git submodule 一般用在比较大的项目中,为了便于复用,或者为了代码的安全性,常常需要分成若干个子项目来进行代码管理。
常用的指令包括:
添加子模块: git submodule add
更新子模块: git submodule update
初始化子模块: git submodule init递归的方式克隆整个项目: git clone--recursive
拉取所有子模块: git submodule foreach git pull
2. 利用三个小项目,来测试一下 submodule 的用法
为了便于演示,我们我们创建 3 个项目,把它们都推送到远程仓库中,这里使用 gitee。
Test1:编译得到一个动态库:libtest1.so;Test2:编译得到一个动态度:libtest2.so;Test3:编译得到一个可执行程序,加载、调用上面 2 个动态库中的函数。
为什么要这样设计模块: 安全!
开发人员A:负责 Test1,没有权限拿到其他模块的代码;开发人员B:负责 Test2,没有权限拿到其他模块的代码;项目经理:负责 Test3 和 代码整合,能拿到所有的代码;
项目经理需要把 Test1 和 Test2 作为 sub module,添加到 Test3 中,执行下面的指令:
1. git submodule add https://gitee.com/[你的账号]/test1.git test1
2. git submodule add https://gitee.com/[你的账号]/test2.git test2
把 Test1 和 Test2 作为子模块添加到 Test3 中之后,看一下文件有什么变化:
你还可以看一下 .gitmodules 文件中的内容,可以看出,git 工具就是通过这个配置文件来管理子模块的。
管理员需要对所有的模块进行整合、编译,因此,我们在 Test3 目录下添加一个脚本 build.sh,所有的编译指令,都写在这个脚本中,内容如下:
内容都是最最基本的,直接调用 make 指令即可,执行一下,输出:
到这里,我们就完成了子模块的添加功能。
3. 在一个空目录中来编译、验证一下可行性
我们在另一个空目录中,clone 一下 Test3 这个项目,可以发现:克隆下来的 test1 和 test2 文件夹中是空的,如下所示:
需要手动获取所有的子模块,执行指令:
git submodule update --init --recursive
此时,再使用 tree 命令看一下文件变化,可以看到 test1 和 test2 的文件都被拉取下来了。这里有一个问题需要注意:虽然子模块的代码被拉取下来了,但是其 head 并没有指向 master 分支,需要手动处理一下,如图:
这个时候,我们在 test3 目录下再次执行脚本 build.sh,就可以顺利编译所有的子模块了。
以上这几个步骤,我们是在本地的一个临时目录,手动测试 submodule 的编译过程。
下一个章节我们把这个过程部署到 Jenkins 系统中,所以刚才执行的这几个指令,就需要写在 build.sh 脚本中了。build.sh 的内容变为:
四、在 Jenkins 中使用 git module 来编译所有的模块
下面的操作,都是在浏览器的 Jenkins 面板中来操作的。
1. 重新配置项目
因为我们是在 Test3 中,来编译整个项目(Test1 和 Test2 被作为子模块包括进来),因此首先把之前添加的 Test1 项目删除掉,如图:
然后重新添加项目 Test3,复习一下步骤:
输入描述信息,选择自由风格项目;输入 git 仓库地址和账户信息,选择 master 分支;触发器不设置;编译环境不设置;编译:选择 Execute shell 执行脚本,输入编译指令:./build.sh。(刚才说了,Jenkins 这是一个自动化构建框架,具体的编译过程由用户决定,所以我们这里的编译过程就是执行 Test3 下的 build.sh 这个脚本。);编译后动作不设置;
当然,也可以直接在之前的 Test1 项目基础上进行修改。
此时,我们在 Jenkins 中直接点击 Build Now 按钮,如果不出意外的话,会提示编译错误(左侧的 Build History 下面出现红色的错误圆圈)。
点进去,看一下输出信息(Console Output 按钮),提示错误:
原因正如前文所说,子模块在获取之后,head 没有指向 master 分支,需要我们在第一次编译时手动修改一下(我没有找到其它方法,如果你知道的话,请不吝赐教!)
手动解决:在命令行窗口中,进入 Jenkins 系统的 Test3 目录 /var/lib/jenkins/jobs/Test3/workspace ,执行如下几条指令:
git submodule update --init --recursivecd test1/git checkout mastercd -cd test2/git checkout mastercd -
此时,重新触发编译一次,一定可以成功的!
五、总结
这篇文章是属于工具型的,一旦部署好之后,每次编译只需要在浏览器中点一下按钮就行,再也不用 ssh 登录到远程电脑中去手动操作了。
如果你还想继续深入一下的话,下面几件事情可以研究一下:
1. Jenkins 是如何保持编译历史记录的
在目录 /var/lib/jenkins/jobs/Test3/builds 下面,可以看到很多以数字命名的文件夹,记录了每一次的编译信息。
2. 编译后动作
在我们的编译脚本 build.sh 文件中,仅仅是生成了可执行文件,你还可以继续扩充功能,例如:自动部署。
或者在项目配置的 [Post-build Actions] 中,重新写一个专门用来自动部署的脚本文件。
3. git subtree 功能
它与 git submodule 很类似,但是本质不一样。
subtree直接把子模块代码拷贝到主模块中,使用命令简单;submodule 使用的是“指针”指向子模块,使用命令相对复杂一些,功能也更强大;4. 继续研究 Jenkins 中的插件功能