From 6e82d494882cec2730653920945d69246477a5d2 Mon Sep 17 00:00:00 2001 From: Eyck-Alexander Jentzsch Date: Tue, 31 Mar 2026 16:13:53 +0200 Subject: [PATCH] adds Jenkinsfile --- Jenkinsfile | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 Jenkinsfile diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..5b10ef9 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,153 @@ +def suites = ['threadx', 'smp'] +def presets = ['Debug32', 'Release32'] + +def runOneRegression(String suite, String preset, String simulatorPath) { + def suiteDir = "test/${suite}" + def buildDir = "../../build/${preset}/test/${suite}" + + stage("${suite}-${preset}") { + dir(suiteDir) { + sh """ + set -eu + test -n "${simulatorPath}" + test -x "${simulatorPath}" + cmake --preset "${preset}" \\ + -DTHREADX_TEST_SIMULATOR="${simulatorPath}" + cmake --build "${buildDir}" --parallel "\$(nproc)" + ctest \\ + --test-dir "${buildDir}" \\ + --output-on-failure \\ + --output-junit "${buildDir}/ctest-results.xml" \\ + --parallel "1" + """ + } + } +} + +def resolveImageCommit(String image) { + sh( + script: """ + set -eu + docker pull "${image}" >/dev/null + docker image inspect --format='{{ index .Config.Labels "git-commit" }}' "${image}" + """, + returnStdout: true + ).trim() +} + +def runRegressionLane(String image, String simulatorPath, boolean allowFailure) { + def parallelTasks = [:] + + for (String suite : suites) { + for (String preset : presets) { + def suiteName = suite + def presetName = preset + def taskName = "${suiteName}-${presetName}" + parallelTasks[taskName] = { + if (allowFailure) { + catchError(buildResult: 'UNSTABLE', stageResult: 'UNSTABLE') { + runOneRegression(suiteName, presetName, simulatorPath) + } + } else { + runOneRegression(suiteName, presetName, simulatorPath) + } + } + } + } + + docker.image(image).inside { + sh ''' + set -eu + cmake --version + ctest --version + ''' + parallel parallelTasks + } +} + +properties([ + parameters([ + string( + name: 'SIMULATOR_IMAGE_PINNED', + defaultValue: 'git.minres.com/here/here-vp:ac4f736', + description: 'Version-pinned Docker image used for the blocking regression lane' + ), + string( + name: 'SIMULATOR_IMAGE_LATEST', + defaultValue: 'git.minres.com/here/here-vp:latest', + description: 'Moving Docker image tag used for the canary lane' + ), + string( + name: 'THREADX_TEST_SIMULATOR', + defaultValue: '/usr/local/bin/riscv-vp', + description: 'Absolute path to the simulator executable inside the Docker image' + ) + ]) +]) + +def canaryShouldRun = true + +node { + timestamps { + ansiColor('xterm') { + try { + stage('Checkout') { + checkout scm + } + + stage('Check Canary Divergence') { + def pinnedCommit = resolveImageCommit(params.SIMULATOR_IMAGE_PINNED) + def latestCommit = resolveImageCommit(params.SIMULATOR_IMAGE_LATEST) + + if (!pinnedCommit) { + error "Missing git-commit label on ${params.SIMULATOR_IMAGE_PINNED}" + } + if (!latestCommit) { + error "Missing git-commit label on ${params.SIMULATOR_IMAGE_LATEST}" + } + + canaryShouldRun = (pinnedCommit != latestCommit) + + if (canaryShouldRun) { + echo "Canary enabled: ${params.SIMULATOR_IMAGE_LATEST} (${latestCommit}) diverges from ${params.SIMULATOR_IMAGE_PINNED} (${pinnedCommit})" + } else { + echo "Canary skipped: ${params.SIMULATOR_IMAGE_LATEST} and ${params.SIMULATOR_IMAGE_PINNED} both use git-commit ${pinnedCommit}" + } + } + + stage('Stable Regression') { + runRegressionLane(params.SIMULATOR_IMAGE_PINNED, params.THREADX_TEST_SIMULATOR, false) + } + + stage('Simulator Canary') { + if (canaryShouldRun) { + runRegressionLane(params.SIMULATOR_IMAGE_LATEST, params.THREADX_TEST_SIMULATOR, true) + } else { + echo 'Skipping canary lane because latest and pinned images are identical.' + } + } + } catch (err) { + currentBuild.result = 'FAILURE' + throw err + } finally { + junit allowEmptyResults: true, testResults: 'build/*/test/*/ctest-results.xml' + archiveArtifacts artifacts: 'build/*/test/*/*.map,build/*/test/*/*.dis,build/*/test/*/Testing/**', allowEmptyArchive: true + + if (currentBuild.currentResult == 'SUCCESS') { + rocketSend ":thumbsup: ThreadX regression run passed, results at ${env.RUN_DISPLAY_URL} " + } else if (currentBuild.currentResult == 'UNSTABLE') { + rocketSend ":warning: ThreadX canary regression is unstable on ${params.SIMULATOR_IMAGE_LATEST}, please check ${env.RUN_DISPLAY_URL} " + } else if (currentBuild.currentResult == 'FAILURE') { + archiveArtifacts artifacts: 'failed_seeds_*.txt', followSymlinks: false, onlyIfSuccessful: false + rocketSend ":thumbsdown: ThreadX regression failed, please check ${env.RUN_DISPLAY_URL} " + emailext recipientProviders: [culprits(), requestor()], + subject: "ThreadX Pipeline Failed: ${currentBuild.fullDisplayName}", + body: """ +

Build Status: ${currentBuild.currentResult}

+

Check logs at Build Console Logs or at Overview

+ """ + } + } + } + } +}