* Added pytest-json-report plugin - modifying app-opts in setup.cfg - adding hook to all conftest.py files in repo - setting report to be saved to test_root/log/warnings.json - Writing custom logic to save json report to avoid overwrite if pytest called twice This was created to allow us to easily parse through test warnings in jenkins
272 lines
12 KiB
Plaintext
272 lines
12 KiB
Plaintext
def runPythonTests() {
|
|
// Determine git refspec, branch, and clone type
|
|
git_branch = xdist_git_branch()
|
|
git_refspec = xdist_git_refspec()
|
|
sshagent(credentials: ['jenkins-worker', 'jenkins-worker-pem'], ignoreMissing: true) {
|
|
checkout changelog: false, poll: false, scm: [$class: 'GitSCM', branches: [[name: git_branch]],
|
|
doGenerateSubmoduleConfigurations: false, extensions: [[$class: 'CloneOption', honorRefspec: true,
|
|
noTags: true, shallow: true]], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'jenkins-worker',
|
|
refspec: git_refspec, url: "git@github.com:edx/${REPO_NAME}.git"]]]
|
|
sh 'bash scripts/all-tests.sh'
|
|
stash includes: 'reports/**/*coverage*,test_root/log/*.json', name: "${TEST_SUITE}-reports"
|
|
}
|
|
}
|
|
|
|
def pythonTestCleanup() {
|
|
archiveArtifacts allowEmptyArchive: true, artifacts: 'reports/**/*,test_root/log/**/*.log,test_root/log/*.json,**/nosetests.xml,*.log'
|
|
sendSplunkFile excludes: '', includes: '**/timing*.log', sizeLimit: '10MB'
|
|
junit '**/nosetests.xml'
|
|
sh '''source $HOME/edx-venv-$PYTHON_VERSION/edx-venv/bin/activate
|
|
bash scripts/xdist/terminate_xdist_nodes.sh'''
|
|
}
|
|
|
|
def createWarningsReport(fileExtension){
|
|
println "Creating warnings report for ${fileExtension}"
|
|
warning_filename = "warning_report_${fileExtension}.html"
|
|
sh """source $HOME/edx-venv-$PYTHON_VERSION/edx-venv/bin/activate
|
|
python openedx/core/process_warnings.py --dir-path test_root/log --html-path reports/pytest_warnings/${warning_filename}"""
|
|
|
|
publishHTML([allowMissing: false, alwaysLinkToLastBuild: false, keepAll: true,
|
|
reportDir: 'reports/pytest_warnings', reportFiles: "${warning_filename}",
|
|
reportName: "${warning_filename}", reportTitles: ''])
|
|
archiveArtifacts allowEmptyArchive: true, artifacts: 'reports/pytest_warnings/*.html'
|
|
}
|
|
|
|
|
|
def xdist_git_branch() {
|
|
if (env.ghprbActualCommit) {
|
|
return "${ghprbActualCommit}"
|
|
} else {
|
|
return "${BRANCH_NAME}"
|
|
}
|
|
}
|
|
|
|
def xdist_git_refspec() {
|
|
if (env.ghprbActualCommit) {
|
|
return "+refs/pull/${ghprbPullId}/*:refs/remotes/origin/pr/${ghprbPullId}/*"
|
|
} else {
|
|
return "+refs/heads/${BRANCH_NAME}:refs/remotes/origin/${BRANCH_NAME}"
|
|
}
|
|
}
|
|
|
|
pipeline {
|
|
agent { label "jenkins-worker" }
|
|
options {
|
|
sendSplunkConsoleLog()
|
|
timestamps()
|
|
timeout(60)
|
|
}
|
|
environment {
|
|
XDIST_GIT_BRANCH = xdist_git_branch()
|
|
XDIST_GIT_REFSPEC = xdist_git_refspec()
|
|
XDIST_INSTANCE_TYPE = "c5d.large"
|
|
XDIST_WORKER_AMI = credentials('XDIST_WORKER_AMI')
|
|
XDIST_WORKER_IAM_PROFILE_ARN = credentials('XDIST_WORKER_IAM_PROFILE_ARN')
|
|
XDIST_WORKER_KEY_NAME = "jenkins-worker"
|
|
XDIST_WORKER_SUBNET = credentials('XDIST_WORKER_SUBNET')
|
|
XDIST_WORKER_SECURITY_GROUP = credentials('XDIST_WORKER_SECURITY_GROUP')
|
|
WTW_CONTEXT = "python"
|
|
}
|
|
stages {
|
|
stage('Mark build as pending on Github') {
|
|
when {
|
|
// Only run github-build-status for master builds
|
|
expression { env.ghprbActualCommit == null }
|
|
}
|
|
steps {
|
|
script {
|
|
commit_sha = sh(returnStdout: true, script: 'git rev-parse HEAD').trim()
|
|
build job: 'github-build-status',
|
|
parameters: [
|
|
string(name: 'GIT_SHA', value: commit_sha),
|
|
string(name: 'GITHUB_ORG', value: 'edx'),
|
|
string(name: 'GITHUB_REPO', value: "${REPO_NAME}"),
|
|
string(name: 'TARGET_URL', value: "${BUILD_URL}"),
|
|
string(name: 'DESCRIPTION', value: 'Pending'),
|
|
string(name: 'CONTEXT', value: "${GITHUB_CONTEXT}"),
|
|
string(name: 'CREATE_DEPLOYMENT', value: 'false'),
|
|
string(name: 'BUILD_STATUS', value: 'pending')
|
|
],
|
|
propagate: false, wait: false
|
|
}
|
|
}
|
|
}
|
|
stage('Run Tests') {
|
|
parallel {
|
|
stage("lms-unit") {
|
|
agent { label "jenkins-worker" }
|
|
environment {
|
|
TEST_SUITE = "lms-unit"
|
|
XDIST_NUM_WORKERS = 10
|
|
XDIST_REMOTE_NUM_PROCESSES = 1
|
|
}
|
|
steps {
|
|
script {
|
|
runPythonTests()
|
|
}
|
|
}
|
|
post {
|
|
always {
|
|
script {
|
|
pythonTestCleanup()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
stage("cms-unit") {
|
|
agent { label "jenkins-worker" }
|
|
environment {
|
|
TEST_SUITE = "cms-unit"
|
|
XDIST_NUM_WORKERS = 3
|
|
XDIST_REMOTE_NUM_PROCESSES = 1
|
|
}
|
|
steps {
|
|
script {
|
|
runPythonTests()
|
|
}
|
|
}
|
|
post {
|
|
always {
|
|
script {
|
|
pythonTestCleanup()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
stage("commonlib-unit") {
|
|
agent { label "jenkins-worker" }
|
|
environment {
|
|
TEST_SUITE = "commonlib-unit"
|
|
XDIST_NUM_WORKERS = 3
|
|
XDIST_REMOTE_NUM_PROCESSES = 1
|
|
}
|
|
steps {
|
|
script {
|
|
runPythonTests()
|
|
}
|
|
}
|
|
post {
|
|
always {
|
|
script {
|
|
pythonTestCleanup()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
stage('Run coverage') {
|
|
environment {
|
|
CODE_COV_TOKEN = credentials('CODE_COV_TOKEN')
|
|
SUBSET_JOB = "null" // Keep this variable until we can remove the $SUBSET_JOB path from .coveragerc
|
|
}
|
|
steps {
|
|
script {
|
|
if (env.ghprbActualCommit) {
|
|
git_branch = "${ghprbActualCommit}"
|
|
git_refspec = "+refs/pull/${ghprbPullId}/*:refs/remotes/origin/pr/${ghprbPullId}/*"
|
|
ci_branch = "${ghprbSourceBranch}"
|
|
target_branch = "origin/${ghprbTargetBranch}"
|
|
} else {
|
|
git_branch = "${BRANCH_NAME}"
|
|
git_refspec = "+refs/heads/${BRANCH_NAME}:refs/remotes/origin/${BRANCH_NAME}"
|
|
ci_branch = "${BRANCH_NAME}"
|
|
target_branch = "origin/${BRANCH_NAME}"
|
|
}
|
|
sshagent(credentials: ['jenkins-worker'], ignoreMissing: true) {
|
|
checkout changelog: false, poll: false, scm: [$class: 'GitSCM', branches: [[name: git_branch]],
|
|
doGenerateSubmoduleConfigurations: false, extensions: [[$class: 'CloneOption',
|
|
honorRefspec: true, noTags: true, shallow: true]], submoduleCfg: [],
|
|
userRemoteConfigs: [[credentialsId: 'jenkins-worker',
|
|
refspec: git_refspec, url: "git@github.com:edx/${REPO_NAME}.git"]]]
|
|
unstash 'lms-unit-reports'
|
|
unstash 'cms-unit-reports'
|
|
unstash 'commonlib-unit-reports'
|
|
sh """export CI_BRANCH=$ci_branch
|
|
export TARGET_BRANCH=$target_branch
|
|
./scripts/jenkins-report.sh"""
|
|
createWarningsReport("all")
|
|
}
|
|
}
|
|
}
|
|
post {
|
|
always {
|
|
script {
|
|
archiveArtifacts allowEmptyArchive: true, artifacts: 'reports/*.coverage'
|
|
sendSplunkFile excludes: '', includes: '**/timing*.log', sizeLimit: '10MB'
|
|
publishHTML([allowMissing: false, alwaysLinkToLastBuild: false, keepAll: true,
|
|
reportDir: 'reports/cover', reportFiles: 'index.html',
|
|
reportName: 'Coverage.py Report', reportTitles: ''])
|
|
|
|
if (env.ghprbPullId != null) {
|
|
publishHTML([allowMissing: false, alwaysLinkToLastBuild: false, keepAll: true,
|
|
reportDir: 'reports', reportFiles: 'diff_coverage_combined.html',
|
|
reportName: 'Diff Coverage Report', reportTitles: ''])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
post {
|
|
always {
|
|
script {
|
|
if (env.ghprbPullId != null) {
|
|
// For PR jobs, run the edx-platform-test-notifier for PR reporting
|
|
build job: 'edx-platform-test-notifier', parameters: [string(name: 'REPO', value: "${REPO_NAME}"), string(name: 'PR_NUMBER', value: "${ghprbPullId}")], wait: false
|
|
} else {
|
|
// For master jobs run github-build-status and report to slack when necessary
|
|
if (currentBuild.currentResult == "SUCCESS") {
|
|
create_deployment = "true"
|
|
build_status = "success"
|
|
build_description = "Build Passed"
|
|
}
|
|
else {
|
|
create_deployment = "false"
|
|
build_status = "failure"
|
|
build_description = "Build Failed"
|
|
}
|
|
|
|
commit_sha = sh(returnStdout: true, script: 'git rev-parse HEAD').trim()
|
|
build job: 'github-build-status',
|
|
parameters: [
|
|
string(name: 'GIT_SHA', value: commit_sha),
|
|
string(name: 'GITHUB_ORG', value: 'edx'),
|
|
string(name: 'GITHUB_REPO', value: "${REPO_NAME}"),
|
|
string(name: 'TARGET_URL', value: "${BUILD_URL}"),
|
|
string(name: 'DESCRIPTION', value: build_description),
|
|
string(name: 'CONTEXT', value: "${GITHUB_CONTEXT}"),
|
|
string(name: 'CREATE_DEPLOYMENT', value: create_deployment),
|
|
string(name: 'BUILD_STATUS', value: build_status)
|
|
],
|
|
propagate: false, wait: false
|
|
|
|
if (currentBuild.currentResult != "SUCCESS"){
|
|
slackSend botUser: true,
|
|
message: "`${JOB_NAME}` #${BUILD_NUMBER}: ${currentBuild.currentResult} after ${currentBuild.durationString.replace(' and counting', '')}\n${BUILD_URL}"
|
|
|
|
email_body = "See: <${BUILD_URL}>\n\nChanges:\n"
|
|
change_sets = currentBuild.changeSets
|
|
for (int j = 0; j < change_sets.size(); j++) {
|
|
change_set_items = change_sets[j].items
|
|
for (int k = 0; k < change_set_items.length; k++) {
|
|
item = change_set_items[k]
|
|
email_body = email_body + "\n Commit: ${item.commitId} by ${item.author}: ${item.msg}"
|
|
}
|
|
}
|
|
emailext body: email_body,
|
|
subject: "Build failed in Jenkins: ${JOB_NAME} #${BUILD_NUMBER}", to: 'testeng@edx.org'
|
|
} else if (currentBuild.currentResult == "SUCCESS" && currentBuild.previousBuild.currentResult != "SUCCESS") {
|
|
slackSend botUser: true,
|
|
message: "`${JOB_NAME}` #${BUILD_NUMBER}: Back to normal after ${currentBuild.durationString.replace(' and counting', '')}\n${BUILD_URL}"
|
|
emailext body: "See <${BUILD_URL}>",
|
|
subject: "Jenkins Build is back to normal: ${JOB_NAME} #${BUILD_NUMBER}", to: 'testeng@edx.org'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|