我们一直使用的 jenkins 服务还是 2.0 以下不支持 pipeline 的版本。平时创建任务多数使用 maven 项目,构建后的 shell 部署命令都是在各个 job 中独立维护。这种方式的缺点就是:
1.脚本维护麻烦 (环境对应的服务器变更,构建入参更新等等状况);
2.不利于后期功能扩展 (例如 java 服务想接入覆盖率服务);
3.不利于 jenkins 项目迁移 (例如磁盘不足等原因)。
刚好上述原因都遇到了,所以计划迁移到新的 Jenkins 服务中,所有 job 都通过 pipeline 来管理。在使用 pipelin 之后的感觉用 2 个字来形容:真香
顺便感谢一下大佬,但是不知道他的 id,所以直接贴一下他的gitee 共享库项目地址
我的共享库项目中缝合了大佬很多代码,写的太好了,忍不住借鉴一下
迁移之初,参考了网上很多的 pipeline 使用教程。首先肯定不想在每个项目中,维护大量的 Jenkinsfile 文件 (万一需要修改,那不是得改到吐,虽然也可以用 git 项目来统一管理 jenkinsfile),最终采用了 Multibranch Pipeline with defaults(多分支流水线) + Pipeline: Multibranch with defaults 插件的方式,通过维护简单的 default jenkinfile 文件来实现 pipeline 的使用。第二个考虑的问题就是,后期对脚本的维护和扩展希望尽可能的简单,这自然就想到 pipeline 共享库的使用。
先展示下目前的成果:
1.创建 job
这里是说在 Jenkins 中配置简单,其实还有一些信息配置的,是保存在文件或者数据库中
2.job 参数配置
- default jenkinsfile 文件的维护 (仅仅负责调用共享库,所有的实现均在共享库项目中完成)
├─resources
│ app.json
│ base.json
│ host_info.json
├─src
│ │
│ └─com
│ │ common_util.groovy
│ │ exec_shell.groovy
│ │ Log.groovy
│ │
│ ├─beans
│ │ AppJobInfo.groovy
│ │ HostInfo.groovy
│ │ JavaJobInfo.groovy
│ │ JobInfo.groovy
│ │
│ ├─build
│ │ androidBuild.groovy
│ │ build.groovy
│ │ gradleBuild.groovy
│ │ mavenBuild.groovy
│ │ npmBuild.groovy
│ │ yarnBuild.groovy
│ │
│ ├─deploy
│ │ deploy.groovy
│ │
│ ├─enums
│ │ BuildType.groovy
│ │ PipelineType.groovy
│ │ ToolsType.groovy
│ │
│ ├─qikqiak
│ │ GlobalVars.groovy
│ │
│ └─services
│ JacocoHandle.groovy
└─vars
defaultPipeline.groovy
initParamsStage.groovy
loadPipeline.groovy
testPipeline.groovy
unknownPipeline.groovy
def call(PipelineType pipelineType) {
JobInfo jobInfo = creatJobInfo()
switch (pipelineType) {
case PipelineType.DefaultPipeline:
defaultPipeline jobInfo
break
case PipelineType.TestPipeline:
testPipeline jobInfo
break
default:
unknownPipeline null
break
}
}
/**
针对不同类型的项目,使用不同的jobInfo:JavaJobInfo/AppJobinfo
*/
class JobInfo {
/**
* 页面入参
*/
String jobName
String env
BuildType buildType
String branchName
JobInfo(Map map){
this.jobName = map.job_name
this.env = map.env
this.buildType = BuildType.getBuildTypeByKey(map.buildType)
this.branchName = map.branchName
}
/**
* 配置参数
*/
//通用字段
String groupName
ToolsType toolsType
Map<String, String> envMap
def setConfigParams(Map map){
this.groupName = map.groupName
this.toolsType = com.enums.ToolsType.getToolsTypeByKey(map.toolsType)
this.envMap = map.env_map
}
def getEnvKeyList(){
return this.envMap.keySet().toList()
}
def getHost(){
return this.envMap.get(this.env)
}
//默认项
/**
* 是否为自动构建
*/
boolean isAutoBuild = false
/**
* 自动构建时,默认构建的环境:加入构建指令需要环境参数时
*/
String defaultEnv = "test"
/**
* 默认构建方式:仅构建
*/
BuildType defaultBuildType = BuildType.BUILD
@NonCPS
def setAutoBuildParams(){
this.env = defaultEnv
this.buildType = defaultBuildType
}
@Override
@NonCPS
public String toString() {
return "JobInfo{" +
"jobName='" + jobName + '\'' +
", env='" + env + '\'' +
", buildType=" + buildType +
", branchName='" + branchName + '\'' +
", groupName='" + groupName + '\'' +
", toolsType=" + toolsType +
", envMap=" + envMap +
", isAutoBuild=" + isAutoBuild +
", defaultEnv='" + defaultEnv + '\'' +
", defaultBuildType=" + defaultBuildType +
'}';
}
}
stage("init params step"){
script{
log.info("start init params...")
/**
* 先根据构建工具,来构建不同的构建参数
* 后期如果同一个构建工具,针对不同的job,入参类型不同,那么在根据job处理
*/
switch (jobInfo.toolsType){
case ToolsType.MVN:
properties([
parameters([
choice(name:'env', choices:env_list, description:'选择构建环境'),
booleanParam(defaultValue:false, name: 'isCollectCoverage',description: '是否启用jacoco收集代码覆盖率'),
choice(name:'buildType', choices:['buildAndDeploy', 'build', 'deploy'],
description:'选择部署方式:编译并部署、仅编译、仅部署')
])
])
break
case ToolsType.GRADLE:
if(jobInfo instanceof AppJobInfo){
properties([
parameters([
choice(name:'env', choices:env_list, description:'选择构建环境'),
choice(name:'buildType', choices:['buildAndDeploy', 'build', 'deploy'],
description:'选择部署方式:编译并部署、仅编译、仅部署')
])
])
}else{
properties([
parameters([
choice(name:'env', choices:env_list, description:'选择构建环境'),
booleanParam(defaultValue:false, name: 'isCollectCoverage',description: '是否启用jacoco收集代码覆盖率'),
choice(name:'buildType', choices:['buildAndDeploy', 'build', 'deploy'],
description:'选择部署方式:编译并部署、仅编译、仅部署')
])
])
}
break
default:
properties([
parameters([
choice(name:'env', choices:env_list, description:'选择构建环境'),
choice(name:'buildType', choices:['buildAndDeploy', 'build', 'deploy'],
description:'选择部署方式:编译并部署、仅编译、仅部署')
])
])
}
}
}
java 服务增加 jacoco 覆盖率功能
1.维护 JavaAppInfo 对象
class JavaJobInfo extends JobInfo{
boolean isCollectCoverage
JavaJobInfo(Map map) {
super(map)
this.isCollectCoverage = map.isCollectCoverage
}
//Jacoco相关属性
String jacocoPort
String projectId //jacoco覆盖率服务中,coverage_app表中的project_id字段
String commitId
String includes //需要增强类的通配符表达式
String excludes //需要排除增强类的通配符表达式
}
2.在部署时,启动 jacoco
def exec_jar(JavaJobInfo jobInfo){
def util = new common_util()
def log = new Log()
def jacocoHandle = new JacocoHandle()
//判断是否要启用jacoco服务
if(jobInfo.isCollectCoverage){
//先获取jacoco port
jacocoHandle.getJacocoPort(jobInfo)
//在获取本次构建代码最新的commit id
jacocoHandle.getCommitId(jobInfo)
def shell_str = "ssh root@${jobInfo.getHost()} '/home/deployscripts/deploy.sh -d jar //省略 "
if(jobInfo.includes !=""){
shell_str += " -I ${jobInfo.includes}"
}
if(jobInfo.excludes != ""){
shell_str += " -E ${jobInfo.excludes}"
}
shell_str += "'"
sh "${shell_str}"
}else{
sh "ssh root@${jobInfo.getHost()} '/home/deployscripts/deploy.sh -d jar //省略 "
}
}