Files
ThreadX4TGFS/Jenkinsfile
2026-03-31 17:28:03 +02:00

152 lines
5.0 KiB
Groovy

def suites = ['threadx', 'smp']
def presets = ['Debug32', 'Release32']
def simulatorImageLatest = 'git.minres.com/here/here-vp:latest'
def threadxTestSimulator = '/usr/local/bin/riscv-vp'
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) {
withCredentials([usernamePassword(
credentialsId: 'gitea-jenkins',
usernameVariable: 'REGISTRY_USER',
passwordVariable: 'REGISTRY_PASS'
)]) {
return sh(
script: """
set -eu
echo "\$REGISTRY_PASS" | docker login "git.minres.com" -u "\$REGISTRY_USER" --password-stdin >/dev/null
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, List suiteNames, List presetNames) {
def parallelTasks = [:]
for (String suite : suiteNames) {
for (String preset : presetNames) {
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'
)
])
])
def canaryShouldRun = true
node {
timestamps {
try {
stage('Checkout') {
checkout scm
}
stage('Check Canary Divergence') {
def pinnedCommit = resolveImageCommit(params.SIMULATOR_IMAGE_PINNED)
def latestCommit = resolveImageCommit(simulatorImageLatest)
if (!pinnedCommit) {
error "Missing git-commit label on ${params.SIMULATOR_IMAGE_PINNED}"
}
if (!latestCommit) {
error "Missing git-commit label on ${simulatorImageLatest}"
}
canaryShouldRun = (pinnedCommit != latestCommit)
if (canaryShouldRun) {
echo "Canary enabled: ${simulatorImageLatest} (${latestCommit}) diverges from ${params.SIMULATOR_IMAGE_PINNED} (${pinnedCommit})"
} else {
echo "Canary skipped: ${simulatorImageLatest} and ${params.SIMULATOR_IMAGE_PINNED} both use git-commit ${pinnedCommit}"
}
}
stage('Stable Regression') {
runRegressionLane(params.SIMULATOR_IMAGE_PINNED, threadxTestSimulator, false, suites, presets)
}
stage('Simulator Canary') {
if (canaryShouldRun) {
runRegressionLane(simulatorImageLatest, threadxTestSimulator, true, suites, presets)
} 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 ${simulatorImageLatest}, 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: """
<p>Build Status: ${currentBuild.currentResult}</p>
<p> Check logs at <a href='${env.BUILD_URL}console'> Build Console Logs </a> or at <a href='${env.RUN_DISPLAY_URL}'> Overview </a></p>
"""
}
}
}
}