-
-
Save wux5/fbf2f98b16f99ab5db06254404be4403 to your computer and use it in GitHub Desktop.
Example for a full blown Jenkins pipeline script with multiple stages, input steps, injected credentials, heroku deploy, sonarqube and artifactory integration, multiple Git commit statuses, PR merge vs branch build detection, REST API calls to GitHub deployment API, stage timeouts, stage concurrency constraints, ...
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!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" | |
| 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