|
| 1 | +/* groovylint-disable CompileStatic, LineLength, VariableTypeRequired */ |
| 2 | +// This Jenkinsfile defines internal MarkLogic build pipeline. |
| 3 | + |
| 4 | +//Shared library definitions: https://github.com/marklogic/MarkLogic-Build-Libs/tree/1.0-declarative/vars |
| 5 | + |
| 6 | +import groovy.json.JsonSlurperClassic |
| 7 | + |
| 8 | + |
| 9 | +gitCredID = '550650ab-ee92-4d31-a3f4-91a11d5388a3' |
| 10 | +JIRA_ID = '' |
| 11 | +JIRA_ID_PATTERN = /CLD-\d{3,4}/ |
| 12 | +LINT_OUTPUT = '' |
| 13 | +SCAN_OUTPUT = '' |
| 14 | +IMAGE_INFO = 0 |
| 15 | + |
| 16 | +// Define local funtions |
| 17 | +void preBuildCheck() { |
| 18 | + // Initialize parameters as env variables as workaround for https://issues.jenkins-ci.org/browse/JENKINS-41929 |
| 19 | + evaluate """${ def script = ''; params.each { k, v -> script += "env.${k } = '''${v}'''\n" }; return script}""" |
| 20 | + |
| 21 | + JIRA_ID = extractJiraID() |
| 22 | + echo 'Jira ticket number: ' + JIRA_ID |
| 23 | + |
| 24 | + if (env.GIT_URL) { |
| 25 | + githubAPIUrl = GIT_URL.replace('.git', '').replace('github.com', 'api.github.com/repos') |
| 26 | + echo 'githubAPIUrl: ' + githubAPIUrl |
| 27 | + } else { |
| 28 | + echo 'Warning: GIT_URL is not defined' |
| 29 | + } |
| 30 | + |
| 31 | + if (env.CHANGE_ID) { |
| 32 | + if (prDraftCheck()) { sh 'exit 1' } |
| 33 | + if (getReviewState().equalsIgnoreCase('CHANGES_REQUESTED')) { |
| 34 | + println(reviewState) |
| 35 | + sh 'exit 1' |
| 36 | + } |
| 37 | + } |
| 38 | +} |
| 39 | + |
| 40 | +@NonCPS |
| 41 | +def extractJiraID() { |
| 42 | + // Extract Jira ID from one of the environment variables |
| 43 | + def match |
| 44 | + if (env.CHANGE_TITLE) { |
| 45 | + match = env.CHANGE_TITLE =~ JIRA_ID_PATTERN |
| 46 | + } |
| 47 | + else if (env.BRANCH_NAME) { |
| 48 | + match = env.BRANCH_NAME =~ JIRA_ID_PATTERN |
| 49 | + } |
| 50 | + else if (env.GIT_BRANCH) { |
| 51 | + match = env.GIT_BRANCH =~ JIRA_ID_PATTERN |
| 52 | + } |
| 53 | + else { |
| 54 | + echo 'Warning: Jira ticket number not detected.' |
| 55 | + return '' |
| 56 | + } |
| 57 | + try { |
| 58 | + return match[0] |
| 59 | + } catch (any) { |
| 60 | + echo 'Warning: Jira ticket number not detected.' |
| 61 | + return '' |
| 62 | + } |
| 63 | +} |
| 64 | + |
| 65 | +def prDraftCheck() { |
| 66 | + withCredentials([usernameColonPassword(credentialsId: gitCredID, variable: 'Credentials')]) { |
| 67 | + PrObj = sh(returnStdout: true, script:''' |
| 68 | + curl -s -u $Credentials -X GET ''' + githubAPIUrl + '''/pulls/$CHANGE_ID |
| 69 | + ''') |
| 70 | + } |
| 71 | + def jsonObj = new JsonSlurperClassic().parseText(PrObj.toString().trim()) |
| 72 | + return jsonObj.draft |
| 73 | +} |
| 74 | + |
| 75 | +def getReviewState() { |
| 76 | + def reviewResponse |
| 77 | + def commitHash |
| 78 | + withCredentials([usernameColonPassword(credentialsId: gitCredID, variable: 'Credentials')]) { |
| 79 | + reviewResponse = sh(returnStdout: true, script:''' |
| 80 | + curl -s -u $Credentials -X GET ''' + githubAPIUrl + '''/pulls/$CHANGE_ID/reviews |
| 81 | + ''') |
| 82 | + commitHash = sh(returnStdout: true, script:''' |
| 83 | + curl -s -u $Credentials -X GET ''' + githubAPIUrl + '''/pulls/$CHANGE_ID |
| 84 | + ''') |
| 85 | + } |
| 86 | + def jsonObj = new JsonSlurperClassic().parseText(commitHash.toString().trim()) |
| 87 | + def commitId = jsonObj.head.sha |
| 88 | + println(commitId) |
| 89 | + def reviewState = getReviewStateOfPR reviewResponse, 2, commitId |
| 90 | + echo reviewState |
| 91 | + return reviewState |
| 92 | +} |
| 93 | + |
| 94 | +void resultNotification(message) { |
| 95 | + def author, authorEmail, emailList |
| 96 | + if (env.CHANGE_AUTHOR) { |
| 97 | + author = env.CHANGE_AUTHOR.toString().trim().toLowerCase() |
| 98 | + authorEmail = getEmailFromGITUser author |
| 99 | + emailList = params.emailList + ',' + authorEmail |
| 100 | + } else { |
| 101 | + emailList = params.emailList |
| 102 | + } |
| 103 | + jira_link = "https://project.marklogic.com/jira/browse/${JIRA_ID}" |
| 104 | + email_body = "<b>Jenkins pipeline for</b> ${env.JOB_NAME} <br><b>Build Number: </b>${env.BUILD_NUMBER} <b><br><br>Lint Output: <br></b><pre><code>${LINT_OUTPUT}</code></pre><br><br><b>Build URL: </b><br>${env.BUILD_URL}" |
| 105 | + jira_email_body = "${email_body} <br><br><b>Jira URL: </b><br>${jira_link}" |
| 106 | + |
| 107 | + if (JIRA_ID) { |
| 108 | + def comment = [ body: "Jenkins pipeline build result: ${message}" ] |
| 109 | + jiraAddComment site: 'JIRA', idOrKey: JIRA_ID, failOnError: false, input: comment |
| 110 | + mail charset: 'UTF-8', mimeType: 'text/html', to: "${emailList}", body: "${jira_email_body}", subject: "${message}: ${env.JOB_NAME} #${env.BUILD_NUMBER}" |
| 111 | + } else { |
| 112 | + mail charset: 'UTF-8', mimeType: 'text/html', to: "${emailList}", body: "${email_body}", subject: "${message}: ${env.JOB_NAME} #${env.BUILD_NUMBER} - ${JIRA_ID}" |
| 113 | + } |
| 114 | +} |
| 115 | + |
| 116 | +void lint() { |
| 117 | + sh ''' |
| 118 | + # Added to fix 'Context loading failed error' |
| 119 | + go get ./... |
| 120 | + echo Installing golangci-lint |
| 121 | + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.50.0 |
| 122 | + make lint saveOutput=true path=./bin/ |
| 123 | + ''' |
| 124 | + |
| 125 | + LINT_OUTPUT = sh(returnStdout: true, script: 'echo helm template lint output: ;cat helm-lint-output.txt ;echo all tests lint output: ;cat test-lint-output.txt').trim() |
| 126 | + |
| 127 | + sh ''' |
| 128 | + rm -f helm-lint-output.txt test-lint-output.txt |
| 129 | + ''' |
| 130 | +} |
| 131 | + |
| 132 | +void publishTestResults() { |
| 133 | + junit allowEmptyResults:true, testResults: '**/test/test_results/*.xml' |
| 134 | + publishHTML allowMissing: true, alwaysLinkToLastBuild: true, keepAll: true, reportDir: 'test/test_results', reportFiles: 'report.html', reportName: 'Kubernetes Tests Report', reportTitles: '' |
| 135 | +} |
| 136 | + |
| 137 | +void pullImage() { |
| 138 | + withCredentials([usernamePassword(credentialsId: '8c2e0b38-9e97-4953-aa60-f2851bb70cc8', passwordVariable: 'docker_password', usernameVariable: 'docker_user')]) { |
| 139 | + sh """ |
| 140 | + echo "\$docker_password" | docker login --username \$docker_user --password-stdin ${dockerRegistry} |
| 141 | + docker pull ${dockerRepository}:${dockerVersion} |
| 142 | + """ |
| 143 | + } |
| 144 | +} |
| 145 | + |
| 146 | +pipeline { |
| 147 | + agent { |
| 148 | + label { |
| 149 | + label 'cld-kubernetes' |
| 150 | + } |
| 151 | + } |
| 152 | + options { |
| 153 | + checkoutToSubdirectory '.' |
| 154 | + buildDiscarder logRotator(artifactDaysToKeepStr: '7', artifactNumToKeepStr: '', daysToKeepStr: '30', numToKeepStr: '') |
| 155 | + skipStagesAfterUnstable() |
| 156 | + } |
| 157 | + triggers { |
| 158 | + parameterizedCron( env.BRANCH_NAME == 'develop' ? '''00 03 * * * % ML_SERVER_BRANCH=develop-10.0 |
| 159 | + 00 04 * * * % ML_SERVER_BRANCH=develop''' : '') |
| 160 | + } |
| 161 | + environment { |
| 162 | + timeStamp = sh(returnStdout: true, script: 'date +%Y%m%d').trim() |
| 163 | + dockerRegistry = 'ml-docker-dev.marklogic.com' |
| 164 | + dockerRepository = "${dockerRegistry}/marklogic/marklogic-server-centos" |
| 165 | + dockerVersion = "${ML_VERSION}-${timeStamp}-centos-1.0.0" |
| 166 | + } |
| 167 | + |
| 168 | + parameters { |
| 169 | + string(name: 'emailList', defaultValue: emailList, description: 'List of email for build notification', trim: true) |
| 170 | + choice(name: 'ML_VERSION', choices: '10.0\n11.0\n9.0', description: 'MarkLogic version. used to pick appropriate docker image') |
| 171 | + booleanParam(name: 'KUBERNETES_TESTS', defaultValue: true, description: 'Run kubernetes tests') |
| 172 | + } |
| 173 | + |
| 174 | + stages { |
| 175 | + stage('Pre-Build-Check') { |
| 176 | + steps { |
| 177 | + preBuildCheck() |
| 178 | + } |
| 179 | + } |
| 180 | + |
| 181 | + stage('Pull-Image') { |
| 182 | + steps { |
| 183 | + pullImage() |
| 184 | + } |
| 185 | + } |
| 186 | + |
| 187 | + stage('Lint') { |
| 188 | + steps { |
| 189 | + lint() |
| 190 | + } |
| 191 | + } |
| 192 | + |
| 193 | + stage('Kubernetes-Run-Tests') { |
| 194 | + when { |
| 195 | + expression { return params.KUBERNETES_TESTS } |
| 196 | + } |
| 197 | + steps { |
| 198 | + sh """ |
| 199 | + export MINIKUBE_HOME=/space; |
| 200 | + make test dockerImage=${dockerRepository}:${dockerVersion} saveOutput=true |
| 201 | + """ |
| 202 | + } |
| 203 | + } |
| 204 | + } |
| 205 | + |
| 206 | + post { |
| 207 | + always { |
| 208 | + sh ''' |
| 209 | + docker system prune --force --filter "until=720h" |
| 210 | + docker volume prune --force |
| 211 | + docker image prune --force --all |
| 212 | + minikube delete --all --purge |
| 213 | + ''' |
| 214 | + publishTestResults() |
| 215 | + } |
| 216 | + success { |
| 217 | + resultNotification('BUILD SUCCESS ✅') |
| 218 | + } |
| 219 | + failure { |
| 220 | + resultNotification('BUILD ERROR ❌') |
| 221 | + } |
| 222 | + unstable { |
| 223 | + resultNotification('BUILD UNSTABLE ❌') |
| 224 | + } |
| 225 | + } |
| 226 | +} |
0 commit comments