Coding.net上的JenkinsCI简单使用
Jenkins
公司把所有的项目代码仓库都挪到了coding.net上。公司买的套餐有Jenkins功能,放着就浪费了,正好原来的本地GitLab服务器有点问题,就试着用一下coding的CI,编一个前后端分离的项目。
前端webpack,后端gradle,都比较简单,编译过程就是命令行执行两个命令(是的,就是 npm run build
和 ./gradlew clean build
)。
git仓库
因为编译流程需要用到两个仓库,好像目前(2021.5)coding还不能够用图形界面配出来,所以还是需要写jenkinsfile。如果编译只有一个代码仓库的项目,甚至可以纯鼠标操作。
oauth
coding自动生成了一些访问令牌,直接拼到url里就可以了:
script {
def backend_url = "https://${env.PROJECT_TOKEN_GK}:${env.PROJECT_TOKEN}@e.coding.net/seer-group/seed/SeerLaRDS.git"
env.BACKEND_URL = backend_url
def frontend_url = "https://${env.PROJECT_TOKEN_GK}:${env.PROJECT_TOKEN}@e.coding.net/seer-group/seed/SeerLaRDS-UI.git"
env.FRONTEND_URL = frontend_url
}
在构建快照里可以找到 PROJECT_TOKEN_GK
和 PROJEC_TOKEN
,用这个组合就可以访问项目中的所有代码仓库,很方便。
一开始我没找到这个办法,直接生成了一个访问令牌放在CI流程的启动参数里,也能编译,但不安全。
GitSCM
jenkins的git插件,可以在图形界面编辑,也可以在coding内嵌的monaco文本编辑器中编辑:
checkout([$class: 'GitSCM',
branches: [[name: GIT_BUILD_REF]],
userRemoteConfigs: [[url: env.BACKEND_URL,credentialsId: env.PROJECT_TOKEN]]])
主要就三个参数:分支、url、用户凭证。分支默认为master
,url是env.BACKEND_URL
,就是上面拼出来的url,凭证是自动生成的项目凭证env.PROJEC_TOKEN
。简单的流程配起来也比较简单。
制品
coding有制品库,上传到制品库的命令叫codingArtifactsGeneric
,有两个必填参数:文件列表、制品库名称,还有好几个可选参数,这次只用了版本号:
codingArtifactsGeneric(files: env.FILENAME, repoName: 'test', version: env.SEED_VERSION)
这条命令指定了文件名为 env.FILENAME
,用环境变量是因为加了版本号和时间;制品库名称为test
,版本号为env.SEED_VERSION
,是从gradle文件里取出来的。
总结
coding对jenkins的支持还是可以的。简单的流程配起来很方便,而且还有个检查功能:如果写完jenkinsfile不能切换到图形化编辑器,那就是语法不对,比如少个括号什么的。
附完整的jenkinsfile,以后老了记不起来怎么写了可以回来看看:
pipeline {
agent any
stages {
stage('检出后端') {
steps {
script {
def backend_url = "https://${env.PROJECT_TOKEN_GK}:${env.PROJECT_TOKEN}@e.coding.net/seer-group/seed/SeerLaRDS.git"
env.BACKEND_URL = backend_url
def frontend_url = "https://${env.PROJECT_TOKEN_GK}:${env.PROJECT_TOKEN}@e.coding.net/seer-group/seed/SeerLaRDS-UI.git"
env.FRONTEND_URL = frontend_url
}
sh 'mkdir -p backend'
dir('backend') {
checkout([$class: 'GitSCM',
branches: [[name: GIT_BUILD_REF]],
userRemoteConfigs: [[url: env.BACKEND_URL,credentialsId: env.PROJECT_TOKEN]]])
}
}
}
stage('编译后端') {
steps {
dir('backend') {
sh './gradlew clean'
sh './gradlew :app:assembleDist'
}
}
}
stage('检出前端') {
steps {
sh 'mkdir -p frontend'
dir('frontend') {
checkout([$class: 'GitSCM',
branches: [[name: GIT_BUILD_REF]],
userRemoteConfigs: [[url: env.FRONTEND_URL,credentialsId: env.PROJECT_TOKEN]]])
}
}
}
stage('编译前端') {
steps {
dir('frontend') {
sh 'npm install'
sh 'cd app && npm run release && zip ui.zip -r build'
}
}
}
stage('打包上传') {
steps {
script {
def zip_name = sh(returnStdout: true, script:'''ls backend/app/build/distributions -Art | grep zip | tail -n 1''')
env.SEED_ZIP_NAME=zip_name
println "zip_name: ${zip_name}"
// TODO shell parameter expansion in groovy script
// def fullname = sh(returnStdout: true, script: ''' echo ${SEED_ZIP_NAME%.zip} ''').trim()
// println "fullname: ${fullname} "
def folder_name = zip_name.minus('.zip').trim()
println "folder name: |${folder_name}|"
env.SEED_FOLDER_NAME = folder_name
def seed_version=sh(returnStdout: true, script: ''' echo ${SEED_ZIP_NAME} | cut -d - -f 2 | cut -d . -f 1-3 ''').trim()
println "seed version: |${seed_version}|"
def build_date = sh(returnStdout: true, script:''' date +%m%d-%H%M''').trim()
def snapshot_name = "${folder_name}-test-${build_date}"
env.SEED_VERSION=seed_version
env.FOLDER="seed-with-ui"
env.FILENAME="${snapshot_name}.zip"
env.SNAPSHOT_NAME=snapshot_name
}
sh 'echo $SEED_ZIP_NAME'
sh 'mkdir -p $FOLDER'
sh 'unzip backend/app/build/distributions/$SEED_ZIP_NAME -d $FOLDER'
sh 'unzip frontend/app/ui.zip -d $FOLDER/$SEED_FOLDER_NAME'
sh 'cd $FOLDER/$SEED_FOLDER_NAME && mv build ui'
sh 'cd $FOLDER && mv $SEED_FOLDER_NAME $SNAPSHOT_NAME'
sh 'cd $FOLDER && zip $FILENAME -r $SNAPSHOT_NAME'
sh 'mv $FOLDER/$FILENAME ./'
sh 'rm -r $FOLDER'
sh 'echo $SEED_VERSION'
codingArtifactsGeneric(files: env.FILENAME, repoName: 'test', version: env.SEED_VERSION)
}
}
}
}