mycroft-core/Jenkinsfile

343 lines
17 KiB
Groovy

pipeline {
agent any
options {
// Running builds concurrently could cause a race condition with
// building the Docker image.
disableConcurrentBuilds()
buildDiscarder(logRotator(numToKeepStr: '5'))
}
stages {
// Run the build in the against the dev branch to check for compile errors
stage('Add CLA label to PR') {
options {
lock(resource: "lock_${env.JOB_NAME}")
}
environment {
//spawns GITHUB_USR and GITHUB_PSW environment variables
GITHUB=credentials('DevOps-CLA-Checker-Github-Key')
}
steps {
// Using an install of Github repo CLA tagger
// (https://github.com/forslund/github-repo-cla)
sh '~/github-repo-cla/mycroft-core-cla-check.sh'
}
}
stage('Run Integration Tests') {
when {
anyOf {
branch 'dev'
branch 'master'
changeRequest target: 'dev'
}
}
options {
lock(resource: "lock_${env.JOB_NAME}")
}
environment {
// Some branches have a "/" in their name (e.g. feature/new-and-cool)
// Some commands, such as those tha deal with directories, don't
// play nice with this naming convention. Define an alias for the
// branch name that can be used in these scenarios.
BRANCH_ALIAS = sh(
script: 'echo $BRANCH_NAME | sed -e "s#/#-#g"',
returnStdout: true
).trim()
}
steps {
echo 'Building Mark I Voight-Kampff Docker Image'
sh 'docker build -f test/Dockerfile \
--target voight_kampff_builder \
--build-arg platform=mycroft_mark_1 \
--label build=${JOB_NAME} \
-t voight-kampff-mark-1:${BRANCH_ALIAS} .'
echo 'Running Mark I Voight-Kampff Test Suite'
timeout(time: 90, unit: 'MINUTES')
{
sh 'mkdir -p $HOME/core/$BRANCH_ALIAS/allure'
sh 'mkdir -p $HOME/core/$BRANCH_ALIAS/mycroft-logs'
sh 'docker run \
-v "$HOME/voight-kampff/identity:/root/.config/mycroft/identity" \
-v "$HOME/core/$BRANCH_ALIAS/allure:/root/allure" \
-v "$HOME/core/$BRANCH_ALIAS/mycroft-logs:/var/log/mycroft" \
--label build=${JOB_NAME} \
voight-kampff-mark-1:${BRANCH_ALIAS} \
-f allure_behave.formatter:AllureFormatter \
-o /root/allure/allure-result --tags ~@xfail'
}
}
post {
always {
echo 'Report Test Results'
echo 'Changing ownership of Allure results...'
sh 'docker run \
-v "$HOME/core/$BRANCH_ALIAS/allure:/root/allure" \
--entrypoint=/bin/bash \
--label build=${JOB_NAME} \
voight-kampff-mark-1:${BRANCH_ALIAS} \
-x -c "chown $(id -u $USER):$(id -g $USER) \
-R /root/allure/"'
echo 'Changing ownership of Allure results...'
sh 'docker run \
-v "$HOME/core/$BRANCH_ALIAS/mycroft-logs:/var/log/mycroft" \
--entrypoint=/bin/bash \
--label build=${JOB_NAME} \
voight-kampff-mark-1:${BRANCH_ALIAS} \
-x -c "chown $(id -u $USER):$(id -g $USER) \
-R /var/log/mycroft"'
echo 'Transferring...'
sh 'rm -rf allure-result/*'
sh 'mv $HOME/core/$BRANCH_ALIAS/allure/allure-result allure-result'
// This directory should now be empty, rmdir will intentionally fail if not.
sh 'rmdir $HOME/core/$BRANCH_ALIAS/allure'
script {
allure([
includeProperties: false,
jdk: '',
properties: [],
reportBuildPolicy: 'ALWAYS',
results: [[path: 'allure-result']]
])
}
unarchive mapping:['allure-report.zip': 'allure-report.zip']
sh 'zip mycroft-logs.zip -r $HOME/core/$BRANCH_ALIAS/mycroft-logs'
sh 'rm -rf $HOME/core/$BRANCH_ALIAS/mycroft-logs'
// This directory should now be empty, rmdir will intentionally fail if not.
sh 'rmdir $HOME/core/$BRANCH_ALIAS'
sh (
label: 'Publish Report to Web Server',
script: '''
ssh root@157.245.127.234 "mkdir -p ~/allure-reports/core/${BRANCH_ALIAS}";
scp allure-report.zip root@157.245.127.234:~/allure-reports/core/${BRANCH_ALIAS};
ssh root@157.245.127.234 "unzip -o ~/allure-reports/core/${BRANCH_ALIAS}/allure-report.zip -d ~/allure-reports/core/${BRANCH_ALIAS}/";
ssh root@157.245.127.234 "rm -rf /var/www/voight-kampff/core/${BRANCH_ALIAS}";
ssh root@157.245.127.234 "mv ~/allure-reports/core/${BRANCH_ALIAS}/allure-report /var/www/voight-kampff/core/${BRANCH_ALIAS}"
ssh root@157.245.127.234 "rm ~/allure-reports/core/${BRANCH_ALIAS}/allure-report.zip";
ssh root@157.245.127.234 "rmdir ~/allure-reports/core/${BRANCH_ALIAS}";
ssh root@157.245.127.234 "mkdir -p ~/mycroft-logs/core/${BRANCH_ALIAS}";
scp mycroft-logs.zip root@157.245.127.234:~/mycroft-logs/core/${BRANCH_ALIAS}/;
ssh root@157.245.127.234 "mkdir -p /var/www/voight-kampff/core/${BRANCH_ALIAS}/logs"
ssh root@157.245.127.234 "unzip -oj ~/mycroft-logs/core/${BRANCH_ALIAS}/mycroft-logs.zip -d /var/www/voight-kampff/core/${BRANCH_ALIAS}/logs/";
ssh root@157.245.127.234 "rm ~/mycroft-logs/core/${BRANCH_ALIAS}/mycroft-logs.zip";
ssh root@157.245.127.234 "rmdir ~/mycroft-logs/core/${BRANCH_ALIAS}";
'''
)
echo 'Report Published'
}
failure {
script {
def comment_text = 'Voight Kampff Integration Test Failed ([Results](https://reports.mycroft.ai/core/' + env.BRANCH_ALIAS + ')). ' +
'\nMycroft logs are also available: ' +
'[skills.log](https://reports.mycroft.ai/core/' + env.BRANCH_ALIAS + '/logs/skills.log), ' +
'[audio.log](https://reports.mycroft.ai/core/' + env.BRANCH_ALIAS + '/logs/audio.log), ' +
'[voice.log](https://reports.mycroft.ai/core/' + env.BRANCH_ALIAS + '/logs/voice.log), ' +
'[bus.log](https://reports.mycroft.ai/core/' + env.BRANCH_ALIAS + '/logs/bus.log), ' +
'[enclosure.log](https://reports.mycroft.ai/core/' + env.BRANCH_ALIAS + '/logs/enclosure.log)'
// Create comment for Pull Requests
if (env.CHANGE_ID) {
def found_comment = false
for (comment in pullRequest.comments) {
echo "Author: ${comment.user}"
if (comment.user == "devops-mycroft" &&
comment.body.contains("Voight Kampff")) {
echo "Updating comment..."
found_comment = true
pullRequest.editComment(
comment.id,
comment_text
)
}
}
if (!found_comment) {
echo 'Sending PR comment'
pullRequest.comment(comment_text)
}
}
}
// Send failure email containing a link to the Jenkins build
// the results report and the console log messages to Mycroft
// developers, the developers of the pull request and the
// developers that caused the build to fail.
echo 'Sending Failure Email'
emailext (
attachLog: true,
subject: "FAILED - Core Integration Tests - Build ${BRANCH_NAME} #${BUILD_NUMBER}",
body: """
<p>
One or more integration tests failed. Use the
resources below to identify the issue and fix
the failing tests.
</p>
<br>
<p>
<a href='${BUILD_URL}'>
Jenkins Build Details
</a>
&nbsp(Requires account on Mycroft's Jenkins instance)
</p>
<br>
<p>
<a href='https://reports.mycroft.ai/core/${BRANCH_ALIAS}'>
Report of Test Results
</a>
</p>
<br>
<p>
Mycroft logs are also available:
<ul>
<li><a href='https://reports.mycroft.ai/core/${BRANCH_ALIAS}/logs/skills.log'>skills.log</a></li>
<li><a href='https://reports.mycroft.ai/core/${BRANCH_ALIAS}/logs/audio.log'>audio.log</a></li>
<li><a href='https://reports.mycroft.ai/core/${BRANCH_ALIAS}/logs/voice.log'>voice.log</a></li>
<li><a href='https://reports.mycroft.ai/core/${BRANCH_ALIAS}/logs/bus.log'>bus.log</a></li>
<li><a href='https://reports.mycroft.ai/core/${BRANCH_ALIAS}/logs/enclosure.log'>enclosure.log</a></li>
</ul>
</p>
<br>
<p>Console log is attached.</p>""",
replyTo: 'devops@mycroft.ai',
to: 'dev@mycroft.ai',
recipientProviders: [
[$class: 'RequesterRecipientProvider'],
[$class:'CulpritsRecipientProvider'],
[$class:'DevelopersRecipientProvider']
]
)
}
success {
script {
if (env.CHANGE_ID) {
def comment_text = 'Voight Kampff Integration Test Succeeded ([Results](https://reports.mycroft.ai/core/' + env.BRANCH_ALIAS + '))'
def found_comment = false
for (comment in pullRequest.comments) {
echo "Author: ${comment.user}"
if (comment.user == "devops-mycroft" &&
comment.body.contains("Voight Kampff")) {
echo "Updating comment!"
found_comment = true
pullRequest.editComment(
comment.id,
comment_text
)
break
}
}
if (!found_comment) {
echo 'Sending PR comment'
pullRequest.comment(comment_text)
}
}
}
// Send success email containing a link to the Jenkins build
// and the results report to Mycroft developers, the developers
// of the pull request and the developers that caused the
// last failed build.
echo 'Sending Success Email'
emailext (
subject: "SUCCESS - Core Integration Tests - Build ${BRANCH_NAME} #${BUILD_NUMBER}",
body: """
<p>
All integration tests passed. No further action required.
</p>
<br>
<p>
<a href='${BUILD_URL}'>
Jenkins Build Details
</a>
&nbsp(Requires account on Mycroft's Jenkins instance)
</p>
<br>
<p>
<a href='https://reports.mycroft.ai/core/${BRANCH_ALIAS}'>
Report of Test Results
</a>
</p>""",
replyTo: 'devops@mycroft.ai',
to: 'dev@mycroft.ai',
recipientProviders: [
[$class: 'RequesterRecipientProvider'],
[$class:'CulpritsRecipientProvider'],
[$class:'DevelopersRecipientProvider']
]
)
}
}
}
// Build snap package for release
stage('Build development Snap package') {
when {
anyOf {
branch 'dev'
}
}
steps {
echo "Launching package build for ${env.BRANCH_NAME}"
build (job: '../Mycroft-snap/dev', wait: false,
parameters: [[$class: 'StringParameterValue',
name: 'BRANCH', value: env.BRANCH_NAME]])
}
}
stage('Build Release Snap package') {
when {
tag "release/v*.*.*"
}
steps {
echo "Launching package build for ${env.TAG_NAME}"
build (job: '../Mycroft-snap/dev', wait: false,
parameters: [[$class: 'StringParameterValue',
name: 'BRANCH', value: env.TAG_NAME]])
}
}
// Build a voight_kampff image for major releases. This will be used
// by the mycroft-skills repository to test skill changes. Skills are
// tested against major releases to determine if they play nicely with
// the breaking changes included in said release.
stage('Build Major Release Image') {
when {
tag "release/v*.*.0"
}
environment {
// Tag name is usually formatted like "20.2.0" whereas skill
// branch names are usually "20.02". Reformat the tag name
// to the skill branch format so this image will be easy to find
// in the mycroft-skill repository.
SKILL_BRANCH = sh(
script: 'echo $TAG_NAME | sed -e "s/v//g" -e "s/[.]0//g" -e "s/[.]/.0/g"',
returnStdout: true
).trim()
}
steps {
echo 'Building ${TAG_NAME} Docker Image for Skill Testing'
sh 'docker build -f test/Dockerfile \
--target voight_kampff_builder \
--build-arg platform=mycroft_mark_1 \
-t voight-kampff-mark-1:${SKILL_BRANCH} .'
}
}
}
post {
success {
// Docker images should remain upon failure for troubleshooting purposes. However,
// if the stage is successful, there is no reason to look back at the Docker image. In theory
// broken builds will eventually be fixed so this step should run eventually for every PR
sh(
label: 'Delete Docker Image on Success',
script: '''
docker image prune --all --force --filter label=build=${JOB_NAME};
'''
)
}
cleanup {
sh(
label: 'Docker Container and Image Cleanup',
script: '''
docker container prune --force;
docker image prune --force;
'''
)
}
}
}