├── License.md ├── README.md └── vars ├── buildMavenCacheImage.groovy ├── deployAnalytics.groovy ├── dockerBuildDockerHubPush.groovy ├── dockerBuildPublish.groovy ├── dockerBuildPublish.txt ├── dockerBuildPush.groovy ├── dockerCloudDeploy.groovy ├── dockerCloudDeploy.txt ├── dockerDeploy.groovy ├── gitShortCommit.groovy ├── githubProtectBranch.groovy ├── githubProtectBranch.txt ├── helloWorld.groovy ├── mavenProject.groovy └── mavenProject.txt /License.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 CloudBees, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Beedemo Pipeline Shared Library 2 | Pipeline Shared Library for SA Jenkins demo environments. 3 | 4 | For more information on setting up and using Pipeline Global Libraries please see the documentation on GitHub: https://github.com/jenkinsci/workflow-cps-global-lib-plugin. 5 | 6 | It is good practice to maintain your Pipeline Global Libraries in an external SCM, in addition to pushing to the Jenkins hosted workflowLibs Pipeline Global Library Git repoisitory. This also helps to manage sharing a Pipeline Global Library across multipe masters. Also, you could use a script such at [this one](https://github.com/cloudbees/jenkins-scripts/blob/master/pipeline-global-lib-init.groovy) to pull in externally managed Pipeline Global Libraries to the embedded Pipeline Global Library Git repository. 7 | 8 | Pipline Global Libraries may be configured at the master, folder or job level. 9 | 10 | ## Global Steps 11 | #### mavenProject 12 | Provides a template for maven builds. Additionally, it provides automated creation/updates of customized build images using `docker commit` to include caching all maven dependencies inside of the repo specific custom build image; dramatically speeding up build times. 13 | ###### configuration: 14 | - `mavenProject`: provides simple config as Pipeline for maven based projects 15 | - org: GitHub organization or user repo is under 16 | - repo: GitHub repository being built 17 | - hipChatRoom: id or name of HipChat room to send build messages 18 | - jdk: version of JDK to use for build as string value 19 | - maven: version of Maven to use for build as string value 20 | - rebuildBuildImage: boolean that controls whether or not to refresh existing repo specific Docker build image based on the `maven' image 21 | - protectedBranches: allows to specify name(s) of branch(es) to protected and use Jenkins to control status, uses the `githubProtrectBranch` step documented below 22 | 23 | ###### Example: 24 | ```groovy 25 | mavenProject { 26 | org = 'sa-team' 27 | repo = 'todo-api' 28 | hipChatRoom = '1613593' 29 | jdk = '8' 30 | maven = '3.3.3' 31 | rebuildBuildImage = true 32 | protectedBranches = ['master'] 33 | } 34 | ``` 35 | #### githubProtectBranch 36 | Uses the GitHub API to set up protected branches on repository being built. 37 | ###### configuration: 38 | - `githubProtectBranch`: sets protection status of rep branch(es) 39 | - branches: list of strings specifying branches to set protected status on 40 | - API URL: GitHub API URL to use 41 | - Credentials ID: ID of GitHub username/password credentials set to use from Jenkins 42 | - org: org/user of repo - for example sa-demo in `sa-demo/todo-api` 43 | - repo: name of repo of branch 44 | 45 | ###### *Example:* 46 | ```groovy 47 | githubProtectBranch(['master','feature-one'], 48 | 'https://github.enterprise.com/api/v3', 49 | '3ebff2f8-1013-42ff-a1e4-6d74e99f4ca1', 50 | 'sa-team', 51 | 'todo-api') 52 | ``` 53 | -------------------------------------------------------------------------------- /vars/buildMavenCacheImage.groovy: -------------------------------------------------------------------------------- 1 | //must be called from within a node block that supports Docker 2 | def call(org, name, pushCredId) { 3 | echo "creating mvn cache image" 4 | try { 5 | sh "docker rm -f mvn-cache" 6 | } catch (e) { 7 | echo "nothing to clean up" 8 | } 9 | sh "docker run --name mvn-cache -v ${WORKSPACE}:${WORKSPACE} -w ${WORKSPACE} maven:3.3.9-jdk-8-alpine mvn -Dmaven.repo.local=/usr/share/maven/ref clean package" 10 | try { 11 | //create a repo specific build image based on previous run 12 | sh "docker commit mvn-cache ${org}/${name}" 13 | sh "docker rm -f mvn-cache" 14 | } catch (e) { 15 | echo "error stopping and removing container" 16 | } 17 | //sign in to registry 18 | withDockerRegistry(registry: [credentialsId: "$pushCredId"]) { 19 | //push repo specific image to Docker registry (DockerHub in this case) 20 | sh "docker push ${org}/${name}" 21 | } 22 | } -------------------------------------------------------------------------------- /vars/deployAnalytics.groovy: -------------------------------------------------------------------------------- 1 | import groovy.json.* 2 | 3 | @NonCPS 4 | def jsonParse(def json) { 5 | new groovy.json.JsonSlurperClassic().parseText(json) 6 | } 7 | 8 | def call(esHost, esHttpReqAuthId, environment, applicationName, artifact, deployUrl, completed, deployId, result) { 9 | //set up path for index 10 | def dateSuffix = new Date().format( 'yyyy-MM' ) 11 | def esIndex = "deploys-$dateSuffix" 12 | 13 | def tokens = "${env.JOB_NAME}".tokenize('/') 14 | def name = tokens[tokens.size()-1] 15 | def url = "${esHost}/${esIndex}/deploy/${deployId}" 16 | 17 | def deployJson = """ 18 | { 19 | "scm_branch": "$name", 20 | "job_name": "$env.JOB_NAME", 21 | "job_url": "$env.JOB_URL", 22 | "build_url": "$env.BUILD_URL", 23 | "environment": "$environment", 24 | "application_name": "$applicationName", 25 | "artifact": "$artifact", 26 | "deploy_url": "$deployUrl", 27 | "result": "$result", 28 | "@timestamp": "$completed" 29 | } 30 | """ 31 | def resp = httpRequest acceptType: 'APPLICATION_JSON', contentType: 'APPLICATION_JSON', httpMode: 'PUT', requestBody: deployJson, authentication: "$esHttpReqAuthId", url: "$url", validResponseCodes: '100:500' 32 | def respObj = jsonParse(resp.content) 33 | println "es resp: ${respObj}" 34 | } 35 | -------------------------------------------------------------------------------- /vars/dockerBuildDockerHubPush.groovy: -------------------------------------------------------------------------------- 1 | // vars/dockerBuildPublish.groovy 2 | def call(body) { 3 | // evaluate the body block, and collect configuration into the object 4 | def config = [:] 5 | body.resolveStrategy = Closure.DELEGATE_FIRST 6 | body.delegate = config 7 | body() 8 | 9 | def dockerImage 10 | def tagAsLatest 11 | def dockerHubCredentialsId 12 | def dockerUserOrg 13 | def dockerRepoName 14 | def dockerTag 15 | def dockerBuildArgs 16 | def pushBranch 17 | node('docker') { 18 | timestamps { 19 | stage('Configure Properties') { 20 | //need to check for properties file from SCM 21 | checkout scm 22 | //tagAsLatest defaults to latest 23 | // github-organization-plugin jobs are named as 'org/repo/branch' 24 | tokens = "${env.JOB_NAME}".tokenize('/') 25 | org = tokens[tokens.size()-3] 26 | repo = tokens[tokens.size()-2] 27 | tag = tokens[tokens.size()-1] 28 | 29 | def d = [org: org, repo: repo, tag: tag, passTag: false, useTriggerTag: false, pushBranch: false, dockerHubCredentialsId: config.dockerHubCredentialsId] 30 | def props = readProperties defaults: d, file: 'dockerBuildPublish.properties' 31 | 32 | tagAsLatest = config.tagAsLatest ?: true 33 | dockerHubCredentialsId = props['dockerHubCredentialsId'] 34 | dockerUserOrg = props['org'] 35 | dockerRepoName = props['repo'] 36 | dockerTag = props['tag'] 37 | dockerBuildArgs = ' .' 38 | 39 | def dockerHubTriggerImage = props['dockerHubTriggerImage'] 40 | def tagArg = '' 41 | pushBranch = props['pushBranch'] 42 | echo "push non master branch: $pushBranch" 43 | if(dockerHubTriggerImage) { 44 | properties([pipelineTriggers(triggers: [[$class: 'DockerHubTrigger', options: [[$class: 'TriggerOnSpecifiedImageNames', repoNames: [dockerHubTriggerImage] as Set]]]]), 45 | [$class: 'BuildDiscarderProperty', strategy: [$class: 'LogRotator', artifactDaysToKeepStr: '', artifactNumToKeepStr: '', daysToKeepStr: '', numToKeepStr: '5']]]) 46 | //check if trigger tag should be passed in as build argument 47 | if(props['passTag'] && env.DOCKER_TRIGGER_TAG) { 48 | echo "passing trigger tags as build-arg: ${env.DOCKER_TRIGGER_TAG}" 49 | dockerBuildArgs = "--build-arg TAG_FROM_TRIGGER=${env.DOCKER_TRIGGER_TAG}" + dockerBuildArgs 50 | } 51 | if(props['useTriggerTag'] && env.DOCKER_TRIGGER_TAG) { 52 | echo "using trigger tags as image tag: ${env.DOCKER_TRIGGER_TAG}" 53 | dockerTag = env.DOCKER_TRIGGER_TAG 54 | } 55 | } 56 | 57 | //config.dockerHubCredentialsId is required 58 | if(!dockerHubCredentialsId) { 59 | error 'dockerHubCredentialsId is required' 60 | } 61 | } 62 | stage('Build Docker Image') { 63 | dockerImage = docker.build("${dockerUserOrg}/${dockerRepoName}:${dockerTag}", dockerBuildArgs) 64 | if(env.BRANCH_NAME=="master" || pushBranch) { 65 | stage 'Publish Docker Image' 66 | withDockerRegistry(registry: [credentialsId: "${dockerHubCredentialsId}"]) { 67 | dockerImage.push() 68 | if(tagAsLatest) { 69 | dockerImage.push("latest") 70 | } 71 | } 72 | } else { 73 | echo "Skipped push for non-master branch" 74 | } 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /vars/dockerBuildPublish.groovy: -------------------------------------------------------------------------------- 1 | // vars/dockerBuildPublish.groovy 2 | def call(body) { 3 | // evaluate the body block, and collect configuration into the object 4 | def config = [:] 5 | body.resolveStrategy = Closure.DELEGATE_FIRST 6 | body.delegate = config 7 | body() 8 | 9 | def dockerImage 10 | node('docker-cloud') { 11 | stage 'Configure Properties' 12 | //need to check for properties file from SCM 13 | checkout scm 14 | //tagAsLatest defaults to latest 15 | // github-organization-plugin jobs are named as 'org/repo/branch' 16 | tokens = "${env.JOB_NAME}".tokenize('/') 17 | org = tokens[tokens.size()-3] 18 | repo = tokens[tokens.size()-2] 19 | tag = tokens[tokens.size()-1] 20 | 21 | def d = [org: org, repo: repo, tag: tag, passTag: false, useTriggerTag: false, pushBranch: false] 22 | def props = readProperties defaults: d, file: 'dockerBuildPublish.properties' 23 | 24 | def tagAsLatest = config.tagAsLatest ?: true 25 | def dockerUserOrg = props['org'] 26 | def dockerRepoName = props['repo'] 27 | def dockerTag = props['tag'] 28 | def dockerHubTriggerImage = props['dockerHubTriggerImage'] 29 | def dockerBuildArgs = ' .' 30 | def tagArg = '' 31 | def pushBranch = props['pushBranch'] 32 | echo "push non master branch: $pushBranch" 33 | if(dockerHubTriggerImage) { 34 | properties([pipelineTriggers(triggers: [[$class: 'DockerHubTrigger', options: [[$class: 'TriggerOnSpecifiedImageNames', repoNames: [dockerHubTriggerImage] as Set]]]]), 35 | [$class: 'BuildDiscarderProperty', strategy: [$class: 'LogRotator', artifactDaysToKeepStr: '', artifactNumToKeepStr: '', daysToKeepStr: '', numToKeepStr: '5']]]) 36 | //check if trigger tag should be passed in as build argument 37 | if(props['passTag'] && env.DOCKER_TRIGGER_TAG) { 38 | echo "passing trigger tags as build-arg: ${env.DOCKER_TRIGGER_TAG}" 39 | dockerBuildArgs = "--build-arg TAG_FROM_TRIGGER=${env.DOCKER_TRIGGER_TAG}" + dockerBuildArgs 40 | } 41 | if(props['useTriggerTag'] && env.DOCKER_TRIGGER_TAG) { 42 | echo "using trigger tags as image tag: ${env.DOCKER_TRIGGER_TAG}" 43 | dockerTag = env.DOCKER_TRIGGER_TAG 44 | } 45 | } 46 | 47 | //config.dockerHubCredentialsId is required 48 | if(!config.dockerHubCredentialsId) { 49 | error 'dockerHubCredentialsId is required' 50 | } 51 | stage 'Build Docker Image' 52 | dockerImage = docker.build("${dockerUserOrg}/${dockerRepoName}:${dockerTag}", dockerBuildArgs) 53 | if(env.BRANCH_NAME=="master" || pushBranch) { 54 | stage 'Publish Docker Image' 55 | withDockerRegistry(registry: [credentialsId: "${config.dockerHubCredentialsId}"]) { 56 | dockerImage.push() 57 | if(tagAsLatest) { 58 | dockerImage.push("latest") 59 | } 60 | } 61 | } else { 62 | echo "Skipped push for non-master branch" 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /vars/dockerBuildPublish.txt: -------------------------------------------------------------------------------- 1 |
3 | Provides a custom step to build and push a Docker image to Docker Hub based on a Dockerfile in a branch of a GitHub Organziation Folder Pipeline project. 4 | 5 | Optionally, you may provide a `dockerBuildPublish.properties` file with the following configuration that will override defaults: 6 |
orgWill override use of GitHub Organization/User as Docker org/user for image name.
repoWill override use of GitHub Repository as for Docker image name.
tagWill override use of branch name as tag.
false- defaults to
true
The following example would result in a Docker image with the name and tag of 'beedemo/mobile-deposit-api:1.1' being built and pushed.
22 |23 | dockerBuildPublish { 24 | dockerHubCredentialsId = 'beedemo-docker-hub-credentials' 25 | tagAsLatest = false 26 | } 27 |28 | -------------------------------------------------------------------------------- /vars/dockerBuildPush.groovy: -------------------------------------------------------------------------------- 1 | //must be called from an agent that supports Docker 2 | def call(org, name, tag, dir, pushCredId) { 3 | dockerImage = docker.build("$org/$name:$tag", "$dir") 4 | withDockerRegistry(registry: [credentialsId: "$pushCredId"]) { 5 | dockerImage.push() 6 | } 7 | } -------------------------------------------------------------------------------- /vars/dockerCloudDeploy.groovy: -------------------------------------------------------------------------------- 1 | // vars/dockerCloudDeploy.groovy 2 | 3 | import com.cloudbees.groovy.cps.NonCPS 4 | import groovy.json.* 5 | 6 | @NonCPS 7 | def jsonParse(def json) { 8 | new groovy.json.JsonSlurperClassic().parseText(json) 9 | } 10 | 11 | def call(nodeLabel, imageTag, name, innerPort, outerPort, httpRequestAuthId) { 12 | 13 | node(nodeLabel) { 14 | def getServiceResp = httpRequest acceptType: 'APPLICATION_JSON', httpMode: 'GET', authentication: "$httpRequestAuthId", url: "https://cloud.docker.com/api/app/v1/service/?name=$name", validResponseCodes: '100:500' 15 | def getServiceRespObj = jsonParse(getServiceResp.content) 16 | println("Status: "+getServiceResp.status) 17 | println("Content: "+getServiceRespObj) 18 | def uuid = null 19 | if(getServiceRespObj.meta.total_count == 0 || getServiceRespObj.objects[0].state=='Terminated') { 20 | def createServiceJson = """ 21 | { 22 | "image": "$imageTag", 23 | "name": "$name", 24 | "target_num_containers": 1, 25 | "container_ports": [{"protocol": "tcp", "inner_port": $innerPort, "outer_port": $outerPort}], 26 | "autorestart": "ALWAYS" 27 | } 28 | """ 29 | println("createServiceJson: "+createServiceJson) 30 | def resp = httpRequest acceptType: 'APPLICATION_JSON', contentType: 'APPLICATION_JSON', httpMode: 'POST', requestBody: createServiceJson, authentication: "$httpRequestAuthId", url: 'https://cloud.docker.com/api/app/v1/service/', validResponseCodes: '100:500' 31 | def respObj = jsonParse(resp.content) 32 | println("Status: "+resp.status) 33 | println("Content: "+respObj) 34 | uuid = respObj.uuid 35 | println "uuid: $uuid" 36 | } else { 37 | uuid = getServiceRespObj.objects[0].uuid 38 | println "uuid: $uuid" 39 | //need to update to use latest image version 40 | def updateServiceJson = """ 41 | { 42 | "image": "$imageTag", 43 | "container_ports": [{"protocol": "tcp", "inner_port": $innerPort, "outer_port": $outerPort}] 44 | } 45 | """ 46 | println("updateServiceJson: "+updateServiceJson) 47 | def updateServiceResp = httpRequest acceptType: 'APPLICATION_JSON', contentType: 'APPLICATION_JSON', httpMode: 'PATCH', requestBody: updateServiceJson, authentication: "$httpRequestAuthId", url: "https://cloud.docker.com/api/app/v1/service/$uuid/", validResponseCodes: '100:500' 48 | def updateServiceObj = jsonParse(updateServiceResp.content) 49 | println("Status: "+updateServiceResp.status) 50 | println("Content: "+updateServiceObj) 51 | println("Headers: "+updateServiceResp.headers) 52 | } 53 | //deploy the service 54 | //POST /api/app/v1/service/(uuid)/redeploy/ 55 | def deployServiceResp = httpRequest acceptType: 'APPLICATION_JSON', httpMode: 'POST', authentication: "$httpRequestAuthId", url: "https://cloud.docker.com/api/app/v1/service/$uuid/redeploy/", validResponseCodes: '100:500' 56 | def deployServiceObj = jsonParse(deployServiceResp.content) 57 | println("Status: "+deployServiceResp.status) 58 | println("Redeploy response: "+deployServiceObj) 59 | def artifact = deployServiceObj.image_name 60 | def deployUrl = deployServiceObj.container_ports[0].endpoint_uri 61 | println("service endpoint: "+deployUrl) 62 | def deployActionEndpoint = deployServiceResp.headers['X-DockerCloud-Action-URI'] 63 | println("X-DockerCloud-Action-URI: "+deployActionEndpoint) 64 | // WAIT FOR DOCKER CLOUD DEPLOYMENT 65 | def deployActionObj = null 66 | sleep 5 //sleep for 5 seconds before making first check 67 | timeout(time: 2, unit: 'MINUTES') { //if deployment is not completed in 2 minutes then assume that it failed 68 | 69 | waitUntil { 70 | def deployActionResp = httpRequest acceptType: 'APPLICATION_JSON', httpMode: 'GET', authentication: "$httpRequestAuthId", url: "https://cloud.docker.com$deployActionEndpoint", validResponseCodes: '100:500' 71 | deployActionObj = jsonParse(deployActionResp.content) 72 | println("Status: "+deployActionResp.status) 73 | println("Deployment Action State: "+deployActionObj.state) 74 | if(deployActionObj.state == "Failed") { 75 | error "Deployment failed" 76 | } 77 | return deployActionObj.state == "Success" 78 | } 79 | } 80 | println("deploy action response: " + deployActionObj) 81 | deployAnalytics("http://elasticsearch.jenkins.beedemo.net", "es-auth", "docker cloud", "mobile-deposit-api", artifact, deployUrl, deployActionObj.end_date, deployActionObj.uuid, deployActionObj.state) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /vars/dockerCloudDeploy.txt: -------------------------------------------------------------------------------- 1 |
Uses Docker Cloud REST API to deploy image to Docker Cloud.
3 | -------------------------------------------------------------------------------- /vars/dockerDeploy.groovy: -------------------------------------------------------------------------------- 1 | //simple docker deployment via Docker Pipeline plugin and `docker.image.run` 2 | 3 | def call(label, org, name, innerPort, outerPort, imageTag) { 4 | node("$label") { 5 | //DOCKER_DEPLOY_PROD_HOST and DOCKER_DEPLOY_PROD_CERT_ID must be set as environment properties (master, folder or job level) 6 | docker.withServer("$DOCKER_DEPLOY_PROD_HOST", "$DOCKER_DEPLOY_PROD_CERT_ID"){ 7 | try { 8 | sh "docker stop $name" 9 | sh "docker rm $name" 10 | } catch (Exception _) { 11 | echo "no container with name $name to stop" 12 | } 13 | //will pull specified image:tag and then run on $dockerHost 14 | docker.image("$org/$name:$imageTag").run("--name $name -p $innerPort:$outerPort") 15 | } 16 | println("successfully deployed app: " + name) 17 | //deployAnalytics("$ES_HOST", "es-auth", "docker-prod", name, "$org/$name:$imageTag", "$DOCKER_DEPLOY_PROD_HOST", new Date().format("EEE, d MMM yyyy HH:mm:ss Z"), imageTag, "Success") 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /vars/gitShortCommit.groovy: -------------------------------------------------------------------------------- 1 | //will set an environmental variable to short commit, must of git repo in workspace 2 | def call(size) { 3 | size = size ?: 7 4 | env.SHORT_COMMIT = sh(returnStdout: true, script: "git rev-parse HEAD | cut -c1-${size} | tr -d '\n'") 5 | } 6 | -------------------------------------------------------------------------------- /vars/githubProtectBranch.groovy: -------------------------------------------------------------------------------- 1 | // vars/githubProtectBranch.groovy 2 | def call(branches, apiUrl, credentialsId, org, repo) { 3 | // The map to store the parallel steps in before executing them. 4 | def stepsForParallel = [:] 5 | 6 | // The standard 'for (String s: stringsToEcho)' syntax also doesn't work, so we 7 | // need to use old school 'for (int i = 0...)' style for loops. 8 | echo "updating protected status on ${org}/${repo}" 9 | for (int i = 0; i < branches.size(); i++) { 10 | // Get the actual string here. 11 | def s = branches.get(i) 12 | 13 | // Transform that into a step and add the step to the map as the value, with 14 | // a name for the parallel step as the key. Here, we'll just use something 15 | // like "echoing (string)" 16 | def stepName = "echoing ${s}" 17 | 18 | stepsForParallel[stepName] = { 19 | echo "setting protected status for ${s} branch" 20 | node('docker-cloud') { 21 | withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: credentialsId, usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD']]) { 22 | sh """curl -u ${env.USERNAME}:${env.PASSWORD} '${apiUrl}/repos/${org}/${repo}/branches/${s}' \ 23 | -XPATCH \ 24 | -H 'Content-Type: application/json' \ 25 | -H 'Accept: application/vnd.github.loki-preview+json' \ 26 | -d '{"protection":{"enabled": true,"required_status_checks": {"enforcement_level": "everyone","contexts": ["Jenkins"]}}}' 27 | """ 28 | } 29 | } 30 | } 31 | } 32 | 33 | // Actually run the steps in parallel - parallel takes a map as an argument, 34 | // hence the above. 35 | parallel stepsForParallel 36 | } -------------------------------------------------------------------------------- /vars/githubProtectBranch.txt: -------------------------------------------------------------------------------- 1 |sa-demo/todo-api
todo-api
18 | githubProtectBranch(['master','feature-one'],'https://github.beescloud.com/api/v3','3ebff2f8-1013-42ff-a1e4-6d74e99f4ca1','sa-team','todo-api') 19 |-------------------------------------------------------------------------------- /vars/helloWorld.groovy: -------------------------------------------------------------------------------- 1 | // vars/helloWorld.groovy 2 | def call(name) { 3 | // you can call any valid step functions from your code, just like you can from Pipeline scripts 4 | echo "Hello ${name}" 5 | echo "Have a great day!" 6 | } 7 | -------------------------------------------------------------------------------- /vars/mavenProject.groovy: -------------------------------------------------------------------------------- 1 | // vars/mavenProject.groovy 2 | def call(body) { 3 | // evaluate the body block, and collect configuration into the object 4 | def config = [:] 5 | body.resolveStrategy = Closure.DELEGATE_FIRST 6 | body.delegate = config 7 | body() 8 | //used for analytics indexing 9 | def short_commit 10 | 11 | //github team specific hipchat room 12 | def hipchatRoom 13 | //don't need to build again if done as part of creating or updating custom Docker build image 14 | def doBuild = true 15 | //default to 'clean install' 16 | def mvnBuildCmd = config.mavenBuildCommand ?: 'clean install' 17 | //default to jdk 8 18 | def jdkVersion = config.jdk ?: 8 19 | def mavenVersion = config.maven ?: '3.3.3' 20 | echo "building with JDK ${jdkVersion}" 21 | //if any maven dependency changes are detected, then will auto-update 22 | def autoUpdateBuildImage = config.autoUpdateBuildImage ?: true 23 | def rebuildBuildImage = config.rebuildBuildImage ?: false 24 | //will use docker commit and push to update custom build image 25 | def updateBuildImage = config.updateBuildImage ?: false 26 | properties([[$class: 'BuildDiscarderProperty', strategy: [$class: 'LogRotator', artifactDaysToKeepStr: '', artifactNumToKeepStr: '5', daysToKeepStr: '', numToKeepStr: '5']]]) 27 | def githubCredentialsId = 'beedemo-user-github-token' 28 | stage 'update protected branches' 29 | if(config.protectedBranches!=null && !config.protectedBranches.empty){ 30 | //set up GitHub protected branches for specified branches 31 | def apiUrl = 'https://github.beescloud.com/api/v3' 32 | githubProtectBranch(config.protectedBranches, apiUrl, githubCredentialsId, config.org, config.repo) 33 | } else { 34 | echo 'no branches set to protect' 35 | } 36 | stage 'create/update build image' 37 | node('docker-cloud') { 38 | def buildImage 39 | try { 40 | buildImage = docker.image("beedemo/${config.repo}-build").pull() 41 | echo "buildImage already built for ${config.repo}" 42 | if(rebuildBuildImage){ 43 | echo "rebuild of buildImage ${config.repo}-build requested" 44 | error "rebuild of buildImage ${config.repo}-build requested" 45 | } else if(updateBuildImage) { 46 | echo "buildImage to be updated and pushed for ${config.repo}" 47 | def workspaceDir = pwd() 48 | checkout scm 49 | sh('git rev-parse HEAD > GIT_COMMIT') 50 | git_commit=readFile('GIT_COMMIT') 51 | short_commit=git_commit.take(7) 52 | //refreshed image, useful if there are one or more new dependencies 53 | sh "docker run --name maven-build -v ${workspaceDir}:${workspaceDir} -w ${workspaceDir} beedemo/${config.repo}-build mvn -Dmaven.repo.local=/maven-repo ${mvnBuildCmd}" 54 | //create a repo specific build image based on previous run 55 | sh "docker commit maven-build beedemo/${config.repo}-build" 56 | sh "docker rm -f maven-build" 57 | //sign in to registry 58 | withDockerRegistry(registry: [credentialsId: 'docker-hub-beedemo']) { 59 | //push repo specific image to Docker registry (DockerHub in this case) 60 | sh "docker push beedemo/${config.repo}-build" 61 | } 62 | //stash an set skip build 63 | stash name: "target-stash", includes: "target/*" 64 | doBuild = false 65 | } 66 | } catch (e) { 67 | echo "buildImage needs to be built and pushed for ${config.repo}" 68 | def workspaceDir = pwd() 69 | checkout scm 70 | //using specific maven repo directory '/maven-repo' to cache dependencies for later builds 71 | def shCmd = "docker run --name maven-build -v ${workspaceDir}:${workspaceDir} -w ${workspaceDir} kmadel/maven:${mavenVersion}-jdk-${jdkVersion} mvn -Dmaven.repo.local=/maven-repo ${mvnBuildCmd}" 72 | echo shCmd 73 | sh shCmd 74 | //create a repo specific build image based on previous run 75 | sh "docker commit maven-build beedemo/${config.repo}-build" 76 | sh "docker rm -f maven-build" 77 | //sign in to registry 78 | withDockerRegistry(registry: [credentialsId: 'docker-hub-beedemo']) { 79 | //push repo specific image to Docker registry (DockerHub in this case) 80 | sh "docker push beedemo/${config.repo}-build" 81 | } 82 | //stash an set skip build 83 | stash name: "target-stash", includes: "target/*" 84 | doBuild = false 85 | } 86 | } 87 | stage 'build' 88 | // now build, based on the configuration provided, 89 | //if not already built as part of creating or upgrading custom Docker build image 90 | if(doBuild) { 91 | node('docker-cloud') { 92 | //get github repo team to use as hipchat room 93 | withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: githubCredentialsId, usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD']]) { 94 | hipchatRoom = sh(returnStdout: true, script: "curl -s -u ${env.USERNAME}:${env.PASSWORD} 'https://api.github.com/repos/beedemo/${config.repo}/teams' | jq -r '.[0] | .name' | tr -d '\n'") 95 | } 96 | echo "hipchat room from GitHub team: ${hipchatRoom}" 97 | try { 98 | checkout scm 99 | sh('git rev-parse HEAD > GIT_COMMIT') 100 | git_commit=readFile('GIT_COMMIT') 101 | short_commit=git_commit.take(7) 102 | //build with repo specific build image 103 | docker.image("beedemo/${config.repo}-build").inside(){ 104 | sh "mvn -Dmaven.repo.local=/maven-repo ${mvnBuildCmd}" 105 | } 106 | echo 'stashing target directory' 107 | stash name: "target-stash", includes: "target/*" 108 | currentBuild.result = "success" 109 | hipchatSend color: 'GREEN', textFormat: true, message: "(super) Pipeline for ${config.org}/${config.repo} complete - Job Name: ${env.JOB_NAME} Build Number: ${env.BUILD_NUMBER} status: ${currentBuild.result} ${env.BUILD_URL}", room: hipchatRoom, server: 'cloudbees.hipchat.com', token: 'A6YX8LxNc4wuNiWUn6qHacfO1bBSGXQ6E1lELi1z', v2enabled: true 110 | } catch (e) { 111 | currentBuild.result = "failure" 112 | hipchatSend color: 'RED', textFormat: true, message: "(angry) Pipeline for ${config.org}/${config.repo} complete - Job Name: ${env.JOB_NAME} Build Number: ${env.BUILD_NUMBER} status: ${currentBuild.result} ${env.BUILD_URL}", room: hipchatRoom, server: 'cloudbees.hipchat.com', token: 'A6YX8LxNc4wuNiWUn6qHacfO1bBSGXQ6E1lELi1z', v2enabled: true 113 | } 114 | } 115 | } else { 116 | echo "already completed build in 'create/update build image' stage" 117 | } 118 | if(env.BRANCH_NAME==config.deployBranch){ 119 | stage name: 'Deploy to Prod', concurrency: 1 120 | if(config.deployType=='websphereLibertyContainer') { 121 | //build and push deployment image 122 | node('docker-cloud') { 123 | unstash "target-stash" 124 | dockerBuildPush("beedemo", config.repo, "${BUILD_NUMBER}", "target", "docker-hub-beedemo") 125 | dockerDeploy("docker-cloud","beedemo", config.repo, 9080, 9080, "${BUILD_NUMBER}") 126 | } 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /vars/mavenProject.txt: -------------------------------------------------------------------------------- 1 |
sa-demo/todo-api
todo-api
8- defaults to 8
3.3.3- defaults to 3.3.3
package -DskipTests- defaults to 'clean install'
true
['master','branch-two']
24 | mavenProject { 25 | org = 'sa-team' 26 | repo = 'todo-api' 27 | hipChatRoom = '1613593' 28 | jdk = '8' 29 | maven = '3.3.3' 30 | mavenBuildCommand = 'package' 31 | rebuildBuildImage = true 32 | protectedBranches = ['master'] 33 | } 34 |35 | --------------------------------------------------------------------------------