Repository URL to install this package:
|
Version:
2.0.0-0-7666ec3 ▾
|
import org.jenkinsci.plugins.pipeline.modeldefinition.Utils
def dockerImage = "<%= image %>"
def standardEnvironments = ['staging', 'preproduction', 'production'];
def defaultConfig = [lint: true, test: true, build: true, deploy: false, chart: '<%= chart %>', charts_repository: 'https://charts.internal.doodle-test.com']
node ('jenkins') {
properties([
parameters([
booleanParam(name: 'lint', defaultValue: false, description: 'Execute linting stage'),
booleanParam(name: 'test', defaultValue: false, description: 'Execute test stage'),
booleanParam(name: 'build', defaultValue: false, description: 'Execute build stage'),
booleanParam(name: 'deploy', defaultValue: false, description: 'Execute deploy stage'),
[$class: 'GitParameterDefinition', name: 'deploy_tag', defaultValue: '', selectedValue: 'NONE', sortMode: 'DESCENDING_SMART', description: 'Which GitHub Release Tag to deploy', type: 'PT_TAG', quickFilterEnabled: true],
choiceParam(name: 'target', choices: (['choose:', 'sandbox', 'custom namespace'] + standardEnvironments).join('\n'), defaultValue: 'choose:', description: 'Which environment to deploy to'),
stringParam(name: 'host', defaultValue: '', description: '$host.kubernetes.doodle-test.com'),
stringParam(name: 'custom_namespace', defaultValue: '', description: 'Custom target namespace name\n💡 Only required when target "custom namespace" is selected'),
stringParam(name: 'custom_values_override', defaultValue: '', description: 'Custom chart values override filename\n💡 Only required when target "custom namespace" is selected'),
stringParam(name: 'chart', defaultValue: defaultConfig.chart, description: 'Helm Chart name'),
stringParam(name: 'charts_repository', defaultValue: defaultConfig.charts_repository, description: 'Helm Charts repository URL'),
booleanParam(name: 'confirm', defaultValue: false, description: 'Confirm manual run\n🚨 Please review you settings carefully!')
])
])
stage('checkout') {
config = defaultConfig + [branch: env.BRANCH_NAME, tag: env.TAG_NAME, force: true]
config.hash = checkout(scm).GIT_COMMIT
config.shortHash = sh(returnStdout: true, script: "git rev-parse --short ${config.hash}").trim()
if (params.confirm) { // manually parametrized job
config << params
config << [
deploy_tag: params.deploy_tag ? params.deploy_tag : config.shortHash,
target: config.target == 'custom namespace' ? params.custom_namespace : config.target
]
} else if (config.tag) { // automatic run for git tag
config.tag = normalize(text: config.tag, dot: false, cut: false)
config << [lint: false, test: false, build: false]
config << [deploy: true, deploy_tag: config.tag, target: 'preproduction']
} else if (config.branch == 'master') { // automatic run for master
config.tag = normalize(text: 'latest', dot: false, cut: false)
config << [deploy: true, deploy_tag: config.shortHash, target: 'staging']
} else if (config.branch.toLowerCase().startsWith('release')) { // automatic run for release branches
config << [deploy: true, deploy_tag: config.shortHash, target: 'preproduction']
}
unstable = false
env.GIT_COMMIT = config.hash
echo """
=====================================================
lint | ${!config.lint ? '❌' : '✅' }
test | ${!config.test ? '❌' : '✅' }
build | ${!config.build ? '❌' : '✅' }
tag | ${!config.tag ? '❌' : config.tag}
deploy | ${!config.deploy ? '❌' : '✅'}
-----------------------------------------------------
target : ${!config.deploy ? '' : config.target}
deploy_tag : ${!config.deploy ? '' : config.deploy_tag}
hash : ${config.hash}
=====================================================
"""
}
stage ('prepare') {
if (!(config.lint || config.test)) return skipStage()
sh 'yarn install'
}
parallel (
lint: {
stage ('lint') {
if (!config.lint) return skipStage()
try {
sh 'yarn run lint -f checkstyle -o checkstyle.xml'
} catch (e) {
currentBuild.result = 'UNSTABLE'
}
}
},
test: {
stage ('test') {
if (!config.test) return skipStage()
sh 'yarn run test --ci'
}
},
build: {
stage ('build') {
if (!config.build) return skipStage()
dockerLogin()
sh "docker build -t $dockerImage:${config.shortHash} ."
sh "docker push $dockerImage:${config.shortHash}"
}
},
)
stage ('reports') {
if (!(config.lint || config.test)) return skipStage()
if (config.test) {
junit 'junit.xml'
}
if (config.lint) {
step([$class: 'CheckStylePublisher', pattern: 'checkstyle.xml'])
}
}
stage ('tag') {
if (!config.tag) return skipStage()
dockerLogin()
sh "docker pull $dockerImage:${config.shortHash}"
sh "docker tag $dockerImage:${config.shortHash} $dockerImage:${config.tag}"
sh "docker push $dockerImage:${config.tag}"
}
stage ('deploy') {
if (!config.deploy) return skipStage();
def escQuot = '\\'.multiply(2) + '"'
helmOptions = [
namespace: config.target,
release: config.chart,
valuesFile: '',
setOverrides: [
"frontend.image.tag=${escQuot + config.deploy_tag + escQuot}",
"gitBranch=${config.branch}"
],
chartsRepository: config.charts_repository
]
if (config.force) {
uuid = sh(returnStdout: true, script: "cat /proc/sys/kernel/random/uuid | xargs echo -n").trim()
helmOptions.setOverrides += ["frontend.redeployUUID=${uuid}"]
}
if (standardEnvironments.contains(config.target)) {
helmOptions.valuesFile = "${config.target}.yaml"
} else if (config.target == 'custom namespace') {
helmOptions << [valuesFile: config.custom_values_override, namespace: config.custom_namespace]
helmOptions.setOverrides << "frontend.ingress.host=${config.custom_namespace}.kubernetes.doodle-test.com"
} else if (config.target == 'sandbox') {
helmOptions << [release: "${config.chart}-${config.host}"]
helmOptions.setOverrides << "frontend.ingress.host=${config.host}.kubernetes.doodle-test.com"
helmOptions.setOverrides << "frontend.sandboxHost=${config.host}"
}
kubernetesSetup(config)
helmUpgrade(config + helmOptions)
}
}
def normalize(Map args) {
def options = [text: '', slash: true, dot: true, cut: true, lower: true] + args
result = "${options.text}"
if (options.slash) result = result.replaceAll('/', '-')
if (options.dot) result = result.replaceAll('\\.', '-')
if (options.cut) result = sh (script: "echo \"${result}\" | cut -d '-' -f1,2,3", returnStdout: true).trim()
if (options.lower) result = result.toLowerCase()
return result
}
def skipStage() {
return Utils.markStageSkippedForConditional(STAGE_NAME)
}
def dockerLogin() {
withCredentials([[
$class: 'UsernamePasswordMultiBinding',
credentialsId: 'nexus',
usernameVariable: 'NEXUS_USER',
passwordVariable: 'NEXUS_PASSWORD'
]]) {
sh "docker login nexus.doodle.com:5000 -u ${env.NEXUS_USER} -p ${env.NEXUS_PASSWORD}"
}
}
def kubernetesSetup(Map args = [:]) {
def options = [
target: '', // required
namespace: args.target, // required
server: 'https://api.kubernetes.doodle-test.com',
credentialsIdKToken: 'doodle-jenkins-stg-token',
credentialsIdCa: 'kubernetes-stg-ca.crt'
] + args;
if(!options.target || !options.namespace) throw new IllegalArgumentException('missing options')
if (options.target == 'production') {
options << [
server: 'https://api.prod.doodle.com',
credentialsIdKToken: 'doodle-jenkins-prod-token',
credentialsIdCa: 'kubernetes-prd-ca.crt'
]
}
withCredentials([
string(credentialsId: options.credentialsIdKToken, variable: 'KTOKEN'),
file(credentialsId: options.credentialsIdCa, variable: 'CA')
]) {
sh """
kubectl config set-credentials jenkins --token=${env.KTOKEN}
kubectl config set-cluster ${options.target}-cluster \
--server=${options.server} \
--certificate-authority=${env.CA} \
--embed-certs=true
kubectl config set-context ${options.target}-context \
--cluster=${options.target}-cluster \
--user=jenkins \
--namespace=${options.namespace}
kubectl config use-context ${options.target}-context
"""
}
}
def helmUpgrade(Map args = [:]) {
def options = [
release: '', // required
namespace: '', // required
tillerNamespace: args.namespace, // required
chart: '', // required
valuesFile: '', // optional
setOverrides: [], // optional
chartsRepository: 'https://charts.internal.doodle-test.com',
chartsDirectory: "${pwd tmp: true}/charts"
] + args;
if(!options.release || !options.namespace || !options.chart) throw new IllegalArgumentException('missing options')
values = options.valuesFile ? "--values ${options.chartsDirectory}/${options.chart}/${options.valuesFile}" : ''
overrides = options.setOverrides ? "--set ${options.setOverrides.join(' --set ')}" : ''
sh """
helm init -c
helm fetch ${options.chart} --repo ${options.chartsRepository} --untar --untardir ${options.chartsDirectory}
helm upgrade \
--install \
--namespace ${options.namespace} \
--tiller-namespace ${options.tillerNamespace} \
${values} \
${overrides} \
${options.release} ${options.chartsDirectory}/${options.chart}
"""
}