import hudson.tasks.test.AbstractTestResultAction pipeline { agent any options { buildDiscarder(logRotator( numToKeepStr: env.BRANCH_NAME.equals("master") ? '15' : '3', daysToKeepStr: env.BRANCH_NAME.equals("master") || env.BRANCH_NAME.startsWith("rel-") ? '' : '7', artifactDaysToKeepStr: env.BRANCH_NAME.equals("master") || env.BRANCH_NAME.startsWith("rel-") ? '' : '3', artifactNumToKeepStr: env.BRANCH_NAME.equals("master") || env.BRANCH_NAME.startsWith("rel-") ? '' : '1' )) disableConcurrentBuilds() skipStagesAfterUnstable() } environment { PATH = "/usr/local/bin/:$PATH" COMPOSE_PROJECT_NAME = "${env.JOB_NAME}-${BRANCH_NAME}" } stages { stage('Preparation') { steps { checkout scm withCredentials([usernamePassword( credentialsId: "cad2f741-7b1e-4ddd-b5ca-2959d40f62c2", usernameVariable: "USER", passwordVariable: "PASS" )]) { sh 'set +x' sh 'docker login -u $USER -p $PASS' } script { def properties = readProperties file: 'project.properties' if (!properties.version) { error("version property not found") } VERSION = properties.version currentBuild.displayName += " - " + VERSION } } post { failure { script { notifyAfterFailure() } } } } stage('Build') { steps { withCredentials([file(credentialsId: '8da5ba56-8ebb-4a6a-bdb5-43c9d0efb120', variable: 'ENV_FILE')]) { script { try { sh ''' sudo rm -f .env cp $ENV_FILE .env if [ "$GIT_BRANCH" != "master" ]; then sed -i '' -e "s#^TRANSIFEX_PUSH=.*#TRANSIFEX_PUSH=false#" .env 2>/dev/null || true fi docker-compose pull docker-compose down --volumes docker-compose run --entrypoint /dev-ui/build.sh offline-ui docker-compose build image docker-compose down --volumes ''' currentBuild.result = processTestResults('SUCCESS') } catch (exc) { currentBuild.result = processTestResults('FAILURE') if (currentBuild.result == 'FAILURE') { error(exc.toString()) } } } } } post { success { archive 'build/styleguide/*, build/styleguide/**/*, build/docs/*, build/docs/**/*, build/messages/*' } unstable { script { notifyAfterFailure() } } failure { script { notifyAfterFailure() } } cleanup { script { sh "sudo rm -rf ${WORKSPACE}/{*,.*} || true" } } } } stage('Build reference-ui') { when { expression { return "${env.GIT_BRANCH}" == 'master' && VERSION.endsWith("SNAPSHOT") } } steps { sh "docker tag openlmis/offline-ui:latest openlmis/offline-ui:${VERSION}" sh "docker push openlmis/offline-ui:${VERSION}" build job: 'OpenLMIS-reference-ui-pipeline/master', wait: false } post { failure { script { notifyAfterFailure() } } } } stage('Sonar analysis') { when { expression { return VERSION.endsWith("SNAPSHOT") } } steps { withSonarQubeEnv('Sonar OpenLMIS') { withCredentials([string(credentialsId: 'SONAR_LOGIN', variable: 'SONAR_LOGIN'), string(credentialsId: 'SONAR_PASSWORD', variable: 'SONAR_PASSWORD')]) { script { sh ''' set +x sudo rm -f .env touch .env SONAR_LOGIN_TEMP=$(echo $SONAR_LOGIN | cut -f2 -d=) SONAR_PASSWORD_TEMP=$(echo $SONAR_PASSWORD | cut -f2 -d=) echo "SONAR_LOGIN=$SONAR_LOGIN_TEMP" >> .env echo "SONAR_PASSWORD=$SONAR_PASSWORD_TEMP" >> .env echo "SONAR_BRANCH=$GIT_BRANCH" >> .env docker-compose run --entrypoint ./sonar.sh offline-ui docker-compose down --volumes sudo rm -rf node_modules/ ''' // workaround because sonar plugin retrieve the path directly from the output sh 'echo "Working dir: ${WORKSPACE}/.sonar"' } } } timeout(time: 1, unit: 'HOURS') { script { def gate = waitForQualityGate() if (gate.status != 'OK') { echo 'Quality Gate FAILED' currentBuild.result = 'UNSTABLE' } } } } post { unstable { script { notifyAfterFailure() } } failure { script { notifyAfterFailure() } } cleanup { script { sh "sudo rm -rf ${WORKSPACE}/{*,.*} || true" } } } } stage('Push image') { when { expression { return env.GIT_BRANCH == 'master' || env.GIT_BRANCH =~ /rel-.+/ } } steps { sh "docker tag openlmis/offline-ui:latest openlmis/offline-ui:${VERSION}" sh "docker push openlmis/offline-ui:${VERSION}" } post { success { script { if (!VERSION.endsWith("SNAPSHOT")) { currentBuild.setKeepLog(true) } } } failure { script { notifyAfterFailure() } } } } } post { fixed { script { BRANCH = "${env.GIT_BRANCH}".trim() if (BRANCH.equals("master") || BRANCH.startsWith("rel-")) { slackSend color: 'good', message: "${env.JOB_NAME} - #${env.BUILD_NUMBER} Back to normal" } } } } } def notifyAfterFailure() { messageColor = 'danger' if (currentBuild.result == 'UNSTABLE') { messageColor = 'warning' } BRANCH = "${env.GIT_BRANCH}".trim() if (BRANCH.equals("master") || BRANCH.startsWith("rel-")) { slackSend color: "${messageColor}", message: "${env.JOB_NAME} - #${env.BUILD_NUMBER} ${env.STAGE_NAME} ${currentBuild.result} (<${env.BUILD_URL}|Open>)" } emailext subject: "${env.JOB_NAME} - #${env.BUILD_NUMBER} ${env.STAGE_NAME} ${currentBuild.result}", body: """
${env.JOB_NAME} - #${env.BUILD_NUMBER} ${env.STAGE_NAME} ${currentBuild.result}
Check console output to view the results.
""", recipientProviders: [[$class: 'CulpritsRecipientProvider'], [$class: 'DevelopersRecipientProvider']] } def processTestResults(status) { junit '**/build/test/test-results/*.xml' AbstractTestResultAction testResultAction = currentBuild.rawBuild.getAction(AbstractTestResultAction.class) if (testResultAction != null) { failuresCount = testResultAction.failCount echo "Failed tests count: ${failuresCount}" if (failuresCount > 0) { echo "Setting build unstable due to test failures" status = 'UNSTABLE' } } return status }