Created
December 21, 2017 14:44
-
-
Save rcbop/80369f293ee24c0db61039a67c6c5ee3 to your computer and use it in GitHub Desktop.
Jenkinsfile for REST API + Oracle instant client download + Docker image build
This file contains 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
// ########################################################################## | |
// # REST API jenkinsfile + oracle client | |
// ########################################################################## | |
// # Mantainer rcbpeixoto@gmail.com | |
// ########################################################################## | |
env.DOCKER_TAG="${params.BRANCH}" | |
env.BRANCH="${params.BRANCH}" | |
env.DOCKER_IMAGE="${env.JOB_BASE_NAME}" | |
env.DOCKER_NAME="${env.DOCKER_IMAGE}:${env.DOCKER_TAG}" | |
env.AWS_ENV="${env.DOCKER_IMAGE}-${env.DOCKER_TAG}" | |
env.ENV_TYPE="production" | |
env.CI_IMAGE_NAME="ci-img" | |
env.CI_TEST_NAME="${env.BUILD_TAG}" | |
env.SONAR_PROJECT_URL="http://<sonar-xxxxxxxxxxx>" | |
env.DEBUG="${params.DEBUG}" | |
env.ISSUE_PATTERN="<jira-issue-pattern-xxx>" | |
env.AWS_KEY="xxxxxxxxx" | |
env.AWS_SECRET="xxxxxxxxxx" | |
env.AWS_PROFILE="aws-deploy" | |
env.AWS_BUCKET_REGION="us-east-1" | |
env.AWS_S3_PREFIX="third-party" | |
env.AWS_S3_BUCKET="deploy-packages" | |
env.CHANGELOG="<div> - No changes </div>" | |
env.gitUrl = "ssh://git@xxxxxxxxxxxxxxxxxx/${env.DOCKER_IMAGE}.git" | |
env.EMAIL_LIST = 'xxxx,xxxxx,xxxxx,xxxxx,xxxxx' | |
timestampedNode('master') { | |
stage('Checkout') { | |
// checkout given branch | |
gitCheckoutBranch() | |
lastChanges() | |
} | |
stage('Download deps'){ | |
downloadOracleInstantClient() | |
} | |
stage('Build base img'){ | |
buildBaseImage() | |
} | |
stage('Build test img') { | |
// build ci container | |
removePreviousTestContainer() | |
buildTestsContainer() | |
} | |
stage('Unit Tests') { | |
// run mocha + sonar + istanbul | |
runTests("unit") | |
// coverage report | |
copyTestResults("/app/coverage") | |
publishHtmlReport( | |
"coverage/lcov-report", | |
"$JOB_BASE_NAME-coverage", | |
"index.html") | |
// mocha report | |
copyTestResults("/app/mocha-report") | |
publishHtmlReport( | |
"mocha-report", | |
"$JOB_BASE_NAME-mocha", | |
"unit-tests.html") | |
// xunit | |
copyTestResults("/app/test-results.xml") | |
junit 'test-results.xml' | |
} | |
stage('Build deploy img') { | |
// builds production container | |
buildProdContainer() | |
} | |
stage('Ship to ECR') { | |
ecrLogin() | |
// creates ecr docker image repository | |
createEcrRepositoryIfNotExists() | |
// creates eb application | |
createElasticBeanstalkApplicationIfNotExist() | |
// tags docker image and sends to aws ecr | |
dockerTagAndPushToECR() | |
} | |
stage('Deploy on EB') { | |
// removes anything but Dockerrun.aws.json from workspace | |
cleanWorkdir() | |
// initialize CLI application | |
initializeElasticBeanstalkCLI() | |
// new git branches creates new eb environments | |
def enviromentStatus = checkIfEnvironmentCreated() | |
if (enviromentStatus.contains('NOT-CREATED')) { | |
createEbEnvironment() | |
} else { | |
deployOnExistingEnvironment() | |
} | |
// displays eb application information | |
sh "eb status --verbose" | |
sh "eb setenv JENKINS_BUILD_NUMBER=${env.BUILD_NUMBER}" | |
sh "eb setenv JENKINS_PACKAGE_ID=AWS" | |
} | |
stage('API Tests') { | |
removePreviousTestContainer() | |
runTests("integration") | |
copyTestResults("/app/reports") | |
junit 'reports/**' | |
} | |
stage('Archive') { | |
sh "rm -rf *.tar.gz || echo 'Previous package not found'" | |
sh "tar zcf api-package.tar.gz *" | |
archiveArtifacts( | |
allowEmptyArchive: false, | |
artifacts: 'api-package.tar.gz', | |
onlyIfSuccessful: true) | |
} | |
stage('Close Issue') { | |
//checks commit logs for ISSUE_PATTERN env | |
def pattern = java.util.regex.Pattern.compile(env.ISSUE_PATTERN) | |
def issueKeyList = filterIssuesWithPattern(pattern) | |
closeGivenIssues(issueKeyList) | |
} | |
} | |
def timestampedNode(String label = "master", Closure body) { | |
node(label) { | |
def message = "" | |
try { | |
wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) { | |
wrap([$class: 'TimestamperBuildWrapper']) { | |
body.call(); | |
} | |
} | |
} catch (err) { | |
wrap([$class: 'BuildUser']) { | |
echo "CURRENT ERROR: ${err}" | |
currentBuild.result = "FAILED" | |
message = """ | |
<hr> | |
<div style='color: red;'><b>BUILD FAILURE CAUSE ::</b> ${err.getMessage()}</div> | |
""" | |
notifyFailed(); | |
} | |
} finally { | |
wrap([$class: 'BuildUser']) { | |
processGitHistoryAndCreateChangelog() | |
currentBuild.result = currentBuild.result ?: 'SUCCESS' | |
if (currentBuild.result != "ABORTED") { | |
emailNotification("${env.CHANGELOG}", "${message}", "${env.EMAIL_LIST}") | |
} | |
if (currentBuild.result == "SUCCESS"){ | |
notifySuccess() | |
} | |
} | |
} | |
} | |
} | |
def processGitHistoryAndCreateChangelog(){ | |
def passedBuilds = [] | |
lastSuccessfulBuild(passedBuilds, currentBuild); | |
env.CHANGELOG = getChangeLog(passedBuilds) | |
debug("${env.CHANGELOG}") | |
} | |
def notifySuccess() { | |
slackSend(color: '#00FF00', message: "SUCCESSFUL: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})") | |
} | |
def notifyFailed() { | |
slackSend(color: '#FF0000', message: "FAILED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})") | |
} | |
def lastSuccessfulBuild(passedBuilds, build) { | |
debug('lastSuccessfulBuild') | |
if ((build != null) && (build.result != 'SUCCESS')) { | |
passedBuilds.add(build) | |
lastSuccessfulBuild(passedBuilds, build.getPreviousBuild()) | |
} | |
} | |
@NonCPS | |
def getChangeLog(passedBuilds) { | |
def log = "<ul>" | |
def changes = [] | |
for (int x = 0; x < passedBuilds.size(); x++) { | |
def currentBuild = passedBuilds[x]; | |
def changeLogSets = currentBuild.rawBuild.changeSets | |
debug("${changeLogSets}") | |
for (int i = 0; i < changeLogSets.size(); i++) { | |
def entries = changeLogSets[i].items | |
debug("${entries}") | |
for (int j = 0; j < entries.length; j++) { | |
def entry = entries[j] | |
debug("${entry}") | |
changes.push("<li> - ${entry.msg} [${entry.author}]</li>") | |
} | |
} | |
} | |
if (changes.size() > 0){ | |
log = "${log}${changes.join('')}</ul>" | |
} else { | |
log = "<div><b>- No changes </b></div>" | |
} | |
return log; | |
} | |
def emailNotification(changelog, message, emailList){ | |
debug("emailNotification :: ${changelog} :: ${message} :: ${emailList}") | |
def bodyContent = """ | |
<div> <h2> ${env.JOB_NAME} Continuous Integration Report </h2> </div> | |
<hr> | |
<div style='color: blue;'><b>JENKINS JOB :: </b> ${env.JENKINS_URL}job/${env.JOB_NAME}/${env.BUILD_NUMBER}</div> | |
<hr> | |
<div style='color: blue;'><b>SONAR REPORT :: </b>${env.SONAR_PROJECT_URL}</div> | |
<hr> | |
<div style='color: blue;'><b>COVERAGE REPORT :: </b> ${JENKINS_URL}job/${env.JOB_NAME}/${env.JOB_NAME}-coverage/</div> | |
<hr> | |
<div style='color: blue;'><b>UNIT TESTS REPORT :: </b> ${JENKINS_URL}job/${env.JOB_NAME}/${env.JOB_NAME}-mocha/</div> | |
<hr> | |
<div style='color: blue;'><b>BUILD USER :: </b> ${env.BUILD_USER}</div> | |
<hr> | |
<div style='color: blue;'><b>BRANCH :: </b> ${env.BRANCH}</div> | |
${message} | |
<hr> | |
<div style='color: green;'><b> CHANGELOG </b></div> | |
<div> ${changelog} </div> | |
""" | |
emailext(body: "${bodyContent}", | |
mimeType: 'text/html', | |
replyTo: 'jenkins@mycompany.com', | |
subject: "[JENKINS] ${env.JOB_NAME} - BUILD #${env.BUILD_NUMBER} - ${currentBuild.result}!", | |
attachLog: true, | |
attachmentsPattern: "mocha-report/unit-tests.html", | |
recipientProviders: [ | |
[$class: 'CulpritsRecipientProvider'], | |
[$class: 'DevelopersRecipientProvider'], | |
[$class: 'RequesterRecipientProvider'] | |
], | |
to: emailList) | |
} | |
def gitCheckoutBranch(){ | |
checkout([$class: 'GitSCM', | |
branches: [[name: "*/${env.BRANCH}"]], | |
doGenerateSubmoduleConfigurations: false, | |
extensions: [[$class: 'LocalBranch', localBranch: "**"]], | |
submoduleCfg: [], | |
userRemoteConfigs: | |
[[credentialsId: '${env.CREDENTIAL_ID}', url: env.gitUrl ]]] | |
) | |
} | |
def ecrLogin(){ | |
sh "\$(aws ecr get-login --region ${env.AWS_DOCKER_REGION} --no-include-email --profile default)" | |
} | |
def createEcrRepositoryIfNotExists(){ | |
def repoList = sh script: "aws ecr describe-repositories --profile default", returnStdout: true | |
if (!repoList.contains(env.DOCKER_IMAGE)) { | |
sh "aws ecr create-repository --repository-name ${env.DOCKER_IMAGE} --profile default" | |
} | |
} | |
def createElasticBeanstalkApplicationIfNotExist(){ | |
def appList = sh script: "aws elasticbeanstalk describe-applications --profile default", returnStdout: true | |
if (!appList.contains(env.DOCKER_IMAGE)) { | |
sh "aws elasticbeanstalk create-application --application-name ${env.DOCKER_IMAGE} --profile default" | |
} | |
} | |
def dockerTagAndPushToECR(){ | |
sh "docker tag ${env.DOCKER_IMAGE}:${env.DOCKER_TAG} ${env.DOCKER_AWS}/${env.DOCKER_NAME}" | |
sh "docker push ${env.DOCKER_AWS}/${env.DOCKER_NAME}" | |
} | |
def cleanWorkdir(){ | |
sh 'DOCKER_RUN=$(cat Dockerrun.aws.json) && rm -rf * .git .gitignore .elasticbeanstalk && echo $DOCKER_RUN >> Dockerrun.aws.json' | |
} | |
def initializeElasticBeanstalkCLI(){ | |
sh "eb init ${env.DOCKER_IMAGE} -r ${env.AWS_DOCKER_REGION} --profile default" | |
} | |
def createEbEnvironment(){ | |
sh "eb create ${env.AWS_ENV} -r ${env.AWS_DOCKER_REGION} --single --profile default" | |
} | |
def checkIfEnvironmentCreated(){ | |
def value = sh script: 'eb list --profile default | grep $AWS_ENV || echo "NOT-CREATED"', returnStdout: true | |
return value | |
} | |
def deployOnExistingEnvironment(){ | |
sh "eb use ${env.AWS_ENV} -r ${env.AWS_DOCKER_REGION} --profile default" | |
sh "eb deploy ${env.AWS_ENV} --staged -r ${env.AWS_DOCKER_REGION} --profile default" | |
} | |
def runTests(type){ | |
sh "docker run -t --name ${CI_TEST_NAME} ${CI_IMAGE_NAME}:latest $type" | |
} | |
def removePreviousTestContainer(){ | |
sh "docker rm ${CI_TEST_NAME} || echo Container not created" | |
} | |
def copyTestResults(path){ | |
sh "docker cp ${CI_TEST_NAME}:$path . || echo Test result not found" | |
} | |
def configureAWSCLI(){ | |
sh """ | |
aws configure set aws_access_key_id $AWS_KEY --profile $AWS_PROFILE | |
aws configure set aws_secret_access_key $AWS_SECRET --profile $AWS_PROFILE | |
aws configure set output 'json' --profile $AWS_PROFILE --profile $AWS_PROFILE | |
aws configure set region $AWS_BUCKET_REGION --profile $AWS_PROFILE | |
""" | |
} | |
def downloadOracleInstantClient(){ | |
configureAWSCLI() | |
def folder = 'oracle-drivers' | |
def instantBasic = 'instantclient-basic-linux.x64-12.2.0.1.0.zip' | |
def instantSDK = 'instantclient-sdk-linux.x64-12.2.0.1.0.zip' | |
sh "mkdir -p ${folder}" | |
if (!fileExists("${folder}/${instantBasic}")){ | |
downloadOracleInstantClientFromS3(instantBasic, "${folder}/${instantBasic}") | |
} | |
if (!fileExists("${folder}/${instantSDK}")){ | |
downloadOracleInstantClientFromS3(instantSDK, "${folder}/${instantSDK}") | |
} | |
} | |
def downloadOracleInstantClientFromS3(file, destination){ | |
sh """ | |
aws s3 cp s3://$AWS_S3_BUCKET/$AWS_S3_PREFIX/${file} ${destination} --profile $AWS_PROFILE | |
""" | |
} | |
def buildBaseImage(){ | |
sh "bash ./scripts/docker/build-base-img.sh" | |
} | |
def buildTestsContainer(){ | |
sh """docker build -t ${CI_IMAGE_NAME}:latest \ | |
--build-arg SONAR_URL=${SONAR_URL} \ | |
--build-arg NODE_ENV=development \ | |
-f ./dockers/ci/Dockerfile . | |
""" | |
} | |
def buildProdContainer(){ | |
sh """ | |
DOCKER_IMAGE_NAME=${env.DOCKER_IMAGE} DOCKER_IMAGE_TAG=${env.DOCKER_TAG} ./scripts/docker/build-dkr-image.sh | |
""" | |
} | |
def publishHtmlReport(reportDir, reportName, reportFiles){ | |
publishHTML (target: [ | |
allowMissing: true, | |
alwaysLinkToLastBuild: false, | |
keepAll: true, | |
reportDir: "$reportDir", | |
reportFiles: "$reportFiles", | |
reportName: "$reportName" | |
]) | |
} | |
def filterIssuesWithPattern(pattern){ | |
def issueKeyList = [] | |
for (def list : currentBuild.rawBuild.changeSets) { | |
for (def change : list.getLogs()) { | |
def comment = change.getComment() | |
def matcher = pattern.matcher(comment) | |
while(matcher.find()) { | |
issueKeyList.push(matcher.group().trim()) | |
} | |
} | |
} | |
return issueKeyList | |
} | |
def closeGivenIssues(issueKeyList){ | |
for (def issueKey : issueKeyList) { | |
def issueList = jiraSearch "issuekey = " + issueKey | |
if (issueList.size() == 0) { | |
error "Issue " + issueKey + " not found." | |
} | |
step( | |
$class: 'JiraIssueUpdateBuilder', | |
jqlSearch: "issuekey = "+issueKey, | |
workflowActionName: 'Done', | |
comment: "Issue closed automatically by ${env.JOB_NAME} - Build #${env.BUILD_NUMBER}" | |
) | |
} | |
} | |
def debug(msg){ | |
if (env.DEBUG.toBoolean()){ | |
echo "DEBUG :: ${msg} ::" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment