Skip to content

Instantly share code, notes, and snippets.

@radhakrishna4687
Forked from jonico/Jenkinsfile
Created March 4, 2021 06:47
Show Gist options
  • Save radhakrishna4687/c0f8e62d3cdc6d226a4832d8841db600 to your computer and use it in GitHub Desktop.
Save radhakrishna4687/c0f8e62d3cdc6d226a4832d8841db600 to your computer and use it in GitHub Desktop.
Example for a full blown Jenkins pipeline script with multiple stages, kubernetes templates, shared volumes, input steps, injected credentials, heroku deploy, sonarqube and artifactory integration, Docker containers, multiple Git commit statuses, PR merge vs branch build detection, REST API calls to GitHub deployment API, stage timeouts, stage c…
#!groovy
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
node {
// pull request or feature branch
if (env.BRANCH_NAME != 'master') {
checkout()
build()
unitTest()
// test whether this is a regular branch build or a merged PR build
if (!isPRMergeBuild()) {
// maybe disabled for ChatOps
// preview()
}
} // master branch / production
else {
checkout()
build()
allTests()
preProduction()
manualPromotion()
production()
}
}
def isPRMergeBuild() {
return (env.BRANCH_NAME ==~ /^PR-\d+$/)
}
def checkout () {
stage 'Checkout code'
context="continuous-integration/jenkins/"
context += isPRMergeBuild()?"branch/checkout":"pr-merge/checkout"
// newer versions of Jenkins do not seem to support setting custom statuses before running the checkout scm step ...
// setBuildStatus ("${context}", 'Checking out...', 'PENDING')
checkout scm
setBuildStatus ("${context}", 'Checking out completed', 'SUCCESS')
}
def build () {
stage 'Build'
// cache maven artifacts
shareM2 '/tmp/m2repo'
mvn 'clean install -DskipTests=true -Dmaven.javadoc.skip=true -Dcheckstyle.skip=true -B -V'
}
def unitTest() {
stage 'Unit tests'
mvn 'test -B -Dmaven.javadoc.skip=true -Dcheckstyle.skip=true'
step([$class: 'JUnitResultArchiver', testResults: '**/target/surefire-reports/TEST-*.xml'])
if (currentBuild.result == "UNSTABLE") {
sh "exit 1"
}
}
def allTests() {
stage 'All tests'
// don't skip anything
mvn 'test -B'
step([$class: 'JUnitResultArchiver', testResults: '**/target/surefire-reports/TEST-*.xml'])
if (currentBuild.result == "UNSTABLE") {
// input "Unit tests are failing, proceed?"
sh "exit 1"
}
}
def preview() {
herokuApp = "${env.HEROKU_PREVIEW}"
deployToStage("preview", herokuApp)
}
def preProduction() {
herokuApp = "${env.HEROKU_PREPRODUCTION}"
deployToStage("preproduction", herokuApp)
}
def manualPromotion() {
stage 'Manual Promotion'
// we need a first milestone step so that all jobs entering this stage are tracked an can be aborted if needed
milestone 1
// time out manual approval after ten minutes
timeout(time: 10, unit: 'MINUTES') {
input message: "Does Pre-Production look good?"
}
// this will kill any job which is still in the input step
milestone 2
}
def production() {
herokuApp = "${env.HEROKU_PRODUCTION}"
deployToStage("production", herokuApp)
step([$class: 'ArtifactArchiver', artifacts: '**/target/*.jar', fingerprint: true])
}
def deployToStage(stageName, herokuApp) {
stage name: "Deploy to ${stageName}", concurrency: 1
id = createDeployment(getBranch(), "${stageName}", "Deploying branch to ${stageName}")
echo "Deployment ID for ${stageName}: ${id}"
if (id != null) {
setDeploymentStatus(id, "pending", "https://${herokuApp}.herokuapp.com/", "Pending deployment to ${stageName}");
herokuDeploy "${herokuApp}"
setDeploymentStatus(id, "success", "https://${herokuApp}.herokuapp.com/", "Successfully deployed to ${stageName}");
}
}
def herokuDeploy (herokuApp) {
withCredentials([[$class: 'StringBinding', credentialsId: 'HEROKU_API_KEY', variable: 'HEROKU_API_KEY']]) {
mvn "heroku:deploy -DskipTests=true -Dmaven.javadoc.skip=true -B -V -D heroku.appName=${herokuApp}"
}
}
def mvn(args) {
// point to settings.xml with cached .m2 directory and proceed in case of test failures
sh "${tool 'Maven 3.x'}/bin/mvn -s settings.xml ${args} -Dmaven.test.failure.ignore"
}
def shareM2(file) {
// Set up a shared Maven repo so we don't need to download all dependencies on every build.
writeFile file: 'settings.xml',
text: "<settings><localRepository>${file}</localRepository></settings>"
}
def getRepoSlug() {
tokens = "${env.JOB_NAME}".tokenize('/')
org = tokens[tokens.size()-3]
repo = tokens[tokens.size()-2]
return "${org}/${repo}"
}
def getBranch() {
tokens = "${env.JOB_NAME}".tokenize('/')
branch = tokens[tokens.size()-1]
return "${branch}"
}
def createDeployment(ref, environment, description) {
withCredentials([[$class: 'StringBinding', credentialsId: 'GITHUB_TOKEN', variable: 'GITHUB_TOKEN']]) {
def payload = JsonOutput.toJson(["ref": "${ref}", "description": "${description}", "environment": "${environment}", "required_contexts": []])
def apiUrl = "https://octodemo.com/api/v3/repos/${getRepoSlug()}/deployments"
def response = sh(returnStdout: true, script: "curl -s -H \"Authorization: Token ${env.GITHUB_TOKEN}\" -H \"Accept: application/json\" -H \"Content-type: application/json\" -X POST -d '${payload}' ${apiUrl}").trim()
def jsonSlurper = new JsonSlurper()
def data = jsonSlurper.parseText("${response}")
return data.id
}
}
void setDeploymentStatus(deploymentId, state, targetUrl, description) {
withCredentials([[$class: 'StringBinding', credentialsId: 'GITHUB_TOKEN', variable: 'GITHUB_TOKEN']]) {
def payload = JsonOutput.toJson(["state": "${state}", "target_url": "${targetUrl}", "description": "${description}"])
def apiUrl = "https://octodemo.com/api/v3/repos/${getRepoSlug()}/deployments/${deploymentId}/statuses"
def response = sh(returnStdout: true, script: "curl -s -H \"Authorization: Token ${env.GITHUB_TOKEN}\" -H \"Accept: application/json\" -H \"Content-type: application/json\" -X POST -d '${payload}' ${apiUrl}").trim()
}
}
void setBuildStatus(context, message, state) {
// partially hard coded URL because of https://issues.jenkins-ci.org/browse/JENKINS-36961, adjust to your own GitHub instance
step([
$class: "GitHubCommitStatusSetter",
contextSource: [$class: "ManuallyEnteredCommitContextSource", context: context],
errorHandlers: [[$class: "ChangingBuildStatusErrorHandler", result: "UNSTABLE"]],
reposSource: [$class: "ManuallyEnteredRepositorySource", url: "https://github.com/${getRepoSlug()}"],
statusResultSource: [ $class: "ConditionalStatusResultSource", results: [[$class: "AnyBuildResult", message: message, state: state]] ]
]);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment