代码拉取完成,页面将自动刷新
pipeline {
agent any
parameters {
choice(name: 'command', choices: ['部署', '回滚', '交付'], description: '选择要进行的操作: ')
gitParameter branch: '', branchFilter: 'origin/(.*)', defaultValue: 'master', description: '选择上线分支或标签', name: 'branch_tag', quickFilterEnabled: false, selectedValue: 'DEFAULT', sortMode: 'NONE', tagFilter: '*', type: 'PT_BRANCH_TAG'
string(name: 'version_id', defaultValue: '0', description: '操作为回滚时生效,默认回滚到上一次构建,如需要回滚到更早构建,请输入对应构建ID,只支持最近五次构建的回滚,部署请忽略此参数')
choice(name: 'remote_ip', choices: ['host101', 'host102'], description: '选择远程的服务器: \n host101 -> 10.10.100.101(开发) \n host104 -> 10.10.100.102(测试)')
}
environment {
harbor_user = 'admin'
harbor_pwd = 'Abcd_1234'
harbor_address = '10.10.100.106:80'
harbor_repo = 'cave'
container_port = 80
host_port = 80
JOB_NAME = jobNameSplitWithBackslash()
git_url = 'https://gitee.com/zqgoodboy/shanghai-stone-cave.git'
host101 = 'http://10.10.100.101'
host102 = 'http://10.10.100.102'
build_directive = 'build:prod'
}
options {
//保存最近历史构建记录的数量。设置此选项后会自动清理pipeline 的构建历史。
buildDiscarder(logRotator(numToKeepStr: '10'))
//不允许管道的并发执行。可以用于防止对共享资源的同时访问
disableConcurrentBuilds()
//如果控制器重新启动,则不允许管道恢复
disableResume()
//允许覆盖分支索引触发器的默认处理。如果在多分支或组织标签处禁用分支索引触发器
overrideIndexTriggers(true)
//保留已完成构建的暂存列表,以便在stage重新启动时使用。
preserveStashes(buildCount: 5)
//为Pipeline设置静默期(以秒为单位)
quietPeriod(5)
//失败时,重试整个管道指定的次数,该次数包含第一次失败
retry(1)
//在所有由Pipeline运行生成的控制台输出之前加上行发出的时间
timestamps()
//为Pipeline运行设置一个超时时间,在此之后Jenkins应该中止Pipeline。
timeout(15)
}
stages {
stage('部署') {
when {
expression { params.command.trim() == '部署' }
}
steps {
script {
try {
checkOut("${branch_tag}", "${git_url}")
npmBuild("${build_directive}")
sonarqubeAnalysis("${JOB_NAME}", "${BRANCH_NAME}")
sonarqubeQualityGate()
buildImage()
pushToHarbor()
publishOverSSH("${remote_ip}")
savedAsLegacy()
} catch (e) {
currentBuild.result='FAILURE'
setCurrentBuildDescription(e.getMessage() + '\n CauseBy:' + e.getCause())
}
}
}
post {
success {
archiveArtifact("${JOB_NAME}-${branch_tag}-${BUILD_ID}.tar")
setCurrentBuildDescription(command+':'+branch_tag)
}
}
}
stage('回滚') {
when {
expression { params.command.trim() == '回滚' }
}
environment {
description = "${currentBuild.previousSuccessfulBuild.description}"
def operations = "${description}".split(":")
branch_tag = "${operations[1]}"
previousBuildDir = "${currentBuild.previousSuccessfulBuild.rawBuild.getArtifactsDir()}"
}
steps {
script {
try {
loadFromLegacy(version_id)
pushToHarbor()
publishOverSSH("${remote_ip}")
savedAsLegacy()
} catch (e) {
currentBuild.result='FAILURE'
setCurrentBuildDescription(e.getMessage() + '\nCauseBy:' + e.getCause())
}
}
}
post {
success {
archiveArtifact("${JOB_NAME}-${branch_tag}-${BUILD_ID}.tar")
setCurrentBuildDescription('RollBackTo'+rollBackVersion()+':'+branch_tag)
}
}
}
stage('交付') {
when {
expression { params.command.trim() == '交付' }
}
steps {
echo '还没写交付'
}
}
}
post {
success {
dingtalk(
robot: 'DingTalk-Bot',
type: 'MARKDOWN',
title: "${currentBuild.fullDisplayName}",
text: ["### **${currentBuild.fullDisplayName}-CI** \n" +
"- 任务: <font color=blue>${BUILD_DISPLAY_NAME}</font> \n" +
"- 状态: <font color=green>${currentBuild.currentResult}</font> \n" +
"- 操作: ${command} \n" +
"- 发起人: ${currentBuild.getBuildCauses().shortDescription} \n" +
"- 持续时间: ${currentBuild.durationString} \n" +
"- 与上次构建成功文件变更:" + getChangedFiles() + " \n" +
"- 最近5次成功构建: " + getLatestSuccessBuildLegacyDir() + " \n" +
"- 任务描述: ${currentBuild.description} \n" +
"- Sonar检测结果: \n" +
"### **${currentBuild.fullDisplayName}-CD** \n" +
"- 部署项目: ${currentBuild.fullProjectName} \n" +
"- 部署环境: "+julENV()+" \n" +
"- 项目地址: "+groupUrl()+" \n"]
)
}
failure {
dingtalk(
robot: 'DingTalk-Error',
type: 'MARKDOWN',
title: "${currentBuild.fullDisplayName}",
text: ["### **${currentBuild.fullDisplayName}-ERROR** \n" +
"- 任务: <font color=blue>${BUILD_DISPLAY_NAME}</font> \n" +
"- 状态: <font color=red>${currentBuild.result}</font> \n" +
"- 操作: ${command} \n" +
"- 发起人: ${currentBuild.getBuildCauses().shortDescription} \n" +
"- 持续时间: ${currentBuild.durationString} \n" +
"- 任务描述: ${currentBuild.description} \n"]
)
}
}
}
/*
检出代码-scmGit
* */
def checkOut(tag, url) {
checkout scmGit(
branches: [[name: tag]],
doGenerateSubmoduleConfigurations: false,
extensions: [],
gitTool: 'Default',
submoduleCfg: [],
userRemoteConfigs: [[credentialsId: 'gitEECredential', url: url]]
)
}
/*
npm install build
* */
def npmBuild(directives) {
sh 'npm install --registry=https://registry.npmmirror.com'
sh 'npm run '+directives
}
/*
代码质量检测-SonarQube
credentialsId:SonarQube-AccessToken
* */
def sonarqubeAnalysis(job_name,branch_name) {
withSonarQubeEnv(installationName: 'SonarQubeServer1', credentialsId: 'a704b599-c8dd-4942-b67e-347bfc1f9a7e') {
sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner ' +
' -Dsonar.analysis.branch=' + branch_name +
' -Dsonar.projectName=' + job_name + ':'+ branch_name +
' -Dsonar.projectKey=' + job_name
}
}
/*
暂停流水线,等待SonarQube返回检测结果
结果将以参数形式用于展示在钉钉通知上
webhookSecretId:已经在Configure System > SonarQube Server > Advanced > Webhook Secret内配置
* */
def sonarqubeQualityGate() {
timeout(1) {
waitForQualityGate abortPipeline: true
}
}
/*
构建镜像-DockerBuild/DockerComposeBuild
* */
def buildImage() {
sh 'rm -rf ./docker/dist'
sh 'mv -f ./dist ./docker'
sh 'docker build -t ${JOB_NAME}:${branch_tag} ./docker'
}
/*
推送镜像到Harbor
自动清理无Tag镜像
Harbor设置项:自动清理无Tag镜像
* */
def pushToHarbor() {
sh 'docker login -u ${harbor_user} -p ${harbor_pwd} ${harbor_address}'
sh 'docker tag ${JOB_NAME}:${branch_tag} ${harbor_address}/${harbor_repo}/${JOB_NAME}:${branch_tag}'
sh 'docker push ${harbor_address}/${harbor_repo}/${JOB_NAME}:${branch_tag}'
sh 'docker logout ${harbor_address}'
sh script: 'docker images|grep none|awk \'{print $3 }\'|xargs -r -n 1 docker rmi -f'
}
/*
通知远程服务器部署
* */
def publishOverSSH(remote_ip) {
sshPublisher(
publishers: [
sshPublisherDesc(
configName: remote_ip,
transfers: [
sshTransfer(
cleanRemote: false,
excludes: '',
execCommand: "deploy.sh ${harbor_address} ${harbor_repo} ${JOB_NAME} ${branch_tag} ${container_port} ${host_port}",
execTimeout: 720000,
flatten: false,
makeEmptyDirs: false,
noDefaultExcludes: false,
patternSeparator: '[, ]+',
remoteDirectory: '',
remoteDirectorySDF: false,
removePrefix: '',
sourceFiles: ''
)
],
usePromotionTimestamp: false,
useWorkspaceInPromotion: false,
verbose: false
)
]
)
}
/*
保存成品;删除镜像
* */
def savedAsLegacy() {
sh 'docker save -o ${JOB_NAME}-${branch_tag}-${BUILD_ID}.tar ${JOB_NAME}:${branch_tag}'
sh script: 'docker images|grep ${JOB_NAME}|awk \'{print $3 }\'|xargs -r -n 1 docker rmi -f'
}
/*
归档成品-archiveArtifact
只归归档成功流水线
* */
def archiveArtifact(artifacts) {
archiveArtifacts artifacts: artifacts, followSymlinks: false, onlyIfSuccessful: true
sh 'mkdir -p bak/${BUILD_ID}'
sh 'mv ${JOB_NAME}-${branch_tag}-${BUILD_ID}.tar bak/${BUILD_ID}'
//保存5次成功构建的成品,用于回滚
def count_a = sh returnStdout: true, script: 'ls -lrt bak/ |grep "^d" |wc -l'
def count_b = count_a?.isInteger() ? count_a as Integer : false
if (count_b > 5) {
def num_l = sh returnStdout: true, script: 'ls -rt bak/ |head -n 1'
sh 'rm -rf bak/'+num_l
}
}
/*
设置当前构建的Description
* */
def setCurrentBuildDescription(action) {
currentBuild.setDescription(action)
}
/*
统计哪些文件发生了变化
系统安全配置:程序内脚本授权
* */
@NonCPS
def getChangedFiles() {
def changed_files = [] as Set
def changeLogSets = currentBuild.rawBuild.changeSets
changeLogSets.each {
it.items.each {
it.affectedFiles.each {
changed_files.add(it.editType.name+':'+it.path + '\n')
}
}
}
return changed_files.toSorted()
}
/*
加载Artifact
* */
def loadFromLegacy(v_id) {
if(v_id == "0") {
dir(previousBuildDir) {
sh 'docker load -i *.tar'
}
} else {
dir("bak/${v_id}") {
sh 'docker load -i *.tar'
}
sh script: 'rm -rf bak/'+v_id+'@tmp'
}
}
/*
多分支流水线jobName含有斜杠
* */
def jobNameSplitWithBackslash() {
def jobName = "${JOB_NAME}".split("\\/")
return jobName[0]
}
/*
获取最近5次成功构建的成品
* */
def getLatestSuccessBuildLegacyDir() {
def r_list = sh returnStdout: true, script: 'ls -t bak/ | awk \' BEGIN { ORS = ""; print "["; } { print $0","; } END { print "]"; }\' |sed "s^,]^]^g"'
return r_list
}
String groupUrl() {
switch (remote_ip) {
case "host101":
return "${host101}:${host_port}"
break
case "host102":
return "${host101}:${host_port}"
break
}
return null
}
String julENV() {
switch (remote_ip) {
case "host101":
return "开发"
break
case "host102":
return "测试"
break
}
return null
}
String rollBackVersion() {
switch (version_id) {
case "0":
return "LatestSuccessBuild"
break
default:
return '#'+version_id
break
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。