This is an automated email from the ASF dual-hosted git repository. tqchen pushed a commit to branch jenkins-cleanup-trusted-main in repository https://gitbox.apache.org/repos/asf/tvm.git
commit 025bec00f3d34b79ae0bed866db4cb4a7dc55006 Author: Tianqi Chen <[email protected]> AuthorDate: Thu Oct 15 11:39:52 2026 +0000 [CI] Use explicit node fallback and artifact upload helpers --- ci/jenkins/README.md | 16 +++++++++++-- ci/jenkins/generated/arm_jenkinsfile.groovy | 20 +++++++++------- ci/jenkins/generated/common.groovy | 36 ++++++++++++++++++++++++++++ ci/jenkins/generated/cpu_jenkinsfile.groovy | 25 ++++++++++++------- ci/jenkins/generated/gpu_jenkinsfile.groovy | 32 ++++++++++++++++--------- ci/jenkins/generated/wasm_jenkinsfile.groovy | 28 ++++++++++++---------- 6 files changed, 115 insertions(+), 42 deletions(-) diff --git a/ci/jenkins/README.md b/ci/jenkins/README.md index e33f38da4c..0f8062b0d9 100644 --- a/ci/jenkins/README.md +++ b/ci/jenkins/README.md @@ -55,13 +55,25 @@ expanding local or remote globs. Use `s3.py --artifacts NAME...` to select registry entries or `--paths PATH...` to select raw paths; the selections are mutually exclusive. Existing Jenkinsfiles can keep `--bundle` and `--items`, which are aliases with the same semantics. -The shared helper's legacy `upload(tag, options)` passes those options unchanged. +`upload_artifacts(tag, options)` passes those options unchanged, as does the +retained legacy `upload(tag, options)`. `artifacts.py` exposes the declarative `ARTIFACTS` registry; there is no `data.py` compatibility module. The shared helper groups internal dependencies first, public entry points next, and retained legacy functions last. Existing function signatures, shared variables, -startup and retry behavior remain available to the platform Jenkinsfiles. +startup and retry behavior remain available to existing Jenkinsfiles. + +Native build and test stages use `with_node(options, body)`. Callers provide exact +`instance` and optional `retry_instance` labels, a stage `name`, a workspace +`folder`, and optional environment `variables`. Skipped CI returns before node +allocation or setup. Each attempt checks out sources in its workspace and runs +the body under a timeout; callers explicitly run `docker_init(image)` in the body. +When a retry label is supplied, build and test failures use the same fallback +policy, retaining the newest-build guard. User cancellation and milestone interruptions propagate without retry, as does +failure of the fallback attempt. Agent loss and attempt timeouts remain eligible +for fallback. Omit `retry_instance` for a single attempt. +Stage and parallel layout remain in the platform files. Host-side commands live in `scripts/`. GitHub bot and release API helpers live in `../github/`. The retained `determine_docker_images.py` supports both diff --git a/ci/jenkins/generated/arm_jenkinsfile.groovy b/ci/jenkins/generated/arm_jenkinsfile.groovy index 2ac6165a7e..c826e2d104 100644 --- a/ci/jenkins/generated/arm_jenkinsfile.groovy +++ b/ci/jenkins/generated/arm_jenkinsfile.groovy @@ -19,12 +19,16 @@ ci = evaluate(readTrusted('ci/jenkins/generated/common.groovy')) ci.start() -ci.build('ARM-GRAVITON3', 'BUILD: arm', 'tvm/build-arm', images.ci_arm, 'arm') { - sh( - script: "${docker_run} ${images.ci_arm} ./tests/scripts/task_config_build_arm.sh build", - label: 'Create ARM CMake config', - ) - ci.cmake_build(images.ci_arm, 'build') - ci.make_cpp_tests(images.ci_arm, 'build') - ci.upload('arm', '--artifacts tvm_lib --artifacts cpptest') +stage('Build') { + ci.with_node(instance: 'ARM-GRAVITON3-SPOT', retry_instance: 'ARM-GRAVITON3', + name: 'BUILD: arm', folder: 'tvm/build-arm', variables: ['PLATFORM=arm']) { + ci.docker_init(images.ci_arm) + sh( + script: "${docker_run} ${images.ci_arm} ./tests/scripts/task_config_build_arm.sh build", + label: 'Create ARM CMake config', + ) + ci.cmake_build(images.ci_arm, 'build') + ci.make_cpp_tests(images.ci_arm, 'build') + ci.upload_artifacts('arm', '--artifacts tvm_lib --artifacts cpptest') + } } diff --git a/ci/jenkins/generated/common.groovy b/ci/jenkins/generated/common.groovy index 734deba37f..f7a87f3889 100644 --- a/ci/jenkins/generated/common.groovy +++ b/ci/jenkins/generated/common.groovy @@ -286,6 +286,42 @@ def run_on_node(label, name, folder, image, variables, body) { // Public entry points. +// The caller supplies exact node labels; omitting retry_instance disables fallback. +// Docker setup stays in the body so each attempt uses the caller's chosen image. +def with_node(options, body) { + if (skip_ci) { + Utils.markStageSkippedForConditional(options.name) + return + } + def run = { instance -> + node(instance) { + ws(per_exec_ws(options.folder)) { + init_git() + timeout(time: max_time, unit: 'MINUTES') { + withEnv(options.variables ?: []) { body() } + } + } + } + } + try { + run(options.instance) + } catch (Throwable ex) { + // Jenkins also uses FlowInterruptedException for agent loss and timeouts. + // Actual interruptions (user cancellation or a milestone) must not retry. + if (ex instanceof org.jenkinsci.plugins.workflow.steps.FlowInterruptedException) { + if (ex.isActualInterruption()) throw ex + } else if (ex instanceof InterruptedException) { + throw ex + } + if (!options.retry_instance) throw ex + retry_latest(ex) { run(options.retry_instance) } + } +} + +def upload_artifacts(tag, options) { + upload(tag, options) +} + def docker_init(image) { // Clear out all Docker images that aren't going to be used sh( diff --git a/ci/jenkins/generated/cpu_jenkinsfile.groovy b/ci/jenkins/generated/cpu_jenkinsfile.groovy index 881cd2cedc..edadf43273 100644 --- a/ci/jenkins/generated/cpu_jenkinsfile.groovy +++ b/ci/jenkins/generated/cpu_jenkinsfile.groovy @@ -19,19 +19,26 @@ ci = evaluate(readTrusted('ci/jenkins/generated/common.groovy')) ci.start() -ci.build('CPU', 'BUILD: CPU', 'tvm/build-cpu', images.ci_cpu, 'cpu') { - sh( - script: "${docker_run} ${images.ci_cpu} ./tests/scripts/task_config_build_cpu.sh build", - label: 'Create CPU CMake config', - ) - ci.cmake_build(images.ci_cpu, 'build') - ci.make_cpp_tests(images.ci_cpu, 'build') - ci.upload('cpu', '--artifacts tvm_lib --artifacts cpptest') +stage('Build') { + ci.with_node(instance: 'CPU-SPOT', retry_instance: 'CPU', + name: 'BUILD: CPU', folder: 'tvm/build-cpu', variables: ['PLATFORM=cpu']) { + ci.docker_init(images.ci_cpu) + sh( + script: "${docker_run} ${images.ci_cpu} ./tests/scripts/task_config_build_cpu.sh build", + label: 'Create CPU CMake config', + ) + ci.cmake_build(images.ci_cpu, 'build') + ci.make_cpp_tests(images.ci_cpu, 'build') + ci.upload_artifacts('cpu', '--artifacts tvm_lib --artifacts cpptest') + } } stage('Test') { parallel('unittest: CPU': { - ci.test('CPU', 'unittest: CPU', 'tvm/ut-python-cpu', images.ci_cpu, 'cpu') { + ci.with_node(instance: 'CPU-SPOT', retry_instance: 'CPU', + name: 'unittest: CPU', folder: 'tvm/ut-python-cpu', + variables: ['PLATFORM=cpu', 'TEST_STEP_NAME=unittest: CPU']) { + ci.docker_init(images.ci_cpu) ci.download('cpu') ci.cpp_unittest(images.ci_cpu) ci.python_unittest(images.ci_cpu) diff --git a/ci/jenkins/generated/gpu_jenkinsfile.groovy b/ci/jenkins/generated/gpu_jenkinsfile.groovy index 98c04b332e..668c0dadd2 100644 --- a/ci/jenkins/generated/gpu_jenkinsfile.groovy +++ b/ci/jenkins/generated/gpu_jenkinsfile.groovy @@ -19,21 +19,28 @@ ci = evaluate(readTrusted('ci/jenkins/generated/common.groovy')) ci.start() -ci.build('CPU', 'BUILD: GPU', 'tvm/build-gpu', images.ci_gpu, 'gpu') { - sh "${docker_run} --no-gpu ${images.ci_gpu} ./tests/scripts/task_config_build_gpu.sh build" - ci.cmake_build("${images.ci_gpu} --no-gpu", 'build') - ci.upload('gpu', '--artifacts tvm_lib --artifacts tvm_lib_gpu_extra') +stage('Build') { + ci.with_node(instance: 'CPU-SPOT', retry_instance: 'CPU', + name: 'BUILD: GPU', folder: 'tvm/build-gpu', variables: ['PLATFORM=gpu']) { + ci.docker_init(images.ci_gpu) + sh "${docker_run} --no-gpu ${images.ci_gpu} ./tests/scripts/task_config_build_gpu.sh build" + ci.cmake_build("${images.ci_gpu} --no-gpu", 'build') + ci.upload_artifacts('gpu', '--artifacts tvm_lib --artifacts tvm_lib_gpu_extra') - // Check the compiler-only GPU configuration after publishing the test build. - sh 'rm -rf build' - sh "${docker_run} --no-gpu ${images.ci_gpu} ./tests/scripts/task_config_build_gpu_other.sh build" - sh "${docker_run} --env CI_NUM_EXECUTORS ${images.ci_gpu} --no-gpu ./tests/scripts/task_build.py --sccache-bucket tvm-sccache-prod --sccache-region us-west-2 --cmake-target tvm_runtime --build-dir build" + // Check the compiler-only GPU configuration after publishing the test build. + sh 'rm -rf build' + sh "${docker_run} --no-gpu ${images.ci_gpu} ./tests/scripts/task_config_build_gpu_other.sh build" + sh "${docker_run} --env CI_NUM_EXECUTORS ${images.ci_gpu} --no-gpu ./tests/scripts/task_build.py --sccache-bucket tvm-sccache-prod --sccache-region us-west-2 --cmake-target tvm_runtime --build-dir build" + } } stage('Test') { parallel( 'unittest: GPU': { - ci.test('GPU', 'unittest: GPU', 'tvm/ut-python-gpu', images.ci_gpu, 'gpu') { + ci.with_node(instance: 'GPU-SPOT', retry_instance: 'GPU', + name: 'unittest: GPU', folder: 'tvm/ut-python-gpu', + variables: ['PLATFORM=gpu', 'TEST_STEP_NAME=unittest: GPU']) { + ci.docker_init(images.ci_gpu) ci.download('gpu') sh( script: "${docker_run} ${images.ci_gpu} ./tests/scripts/task_java_unittest.sh", @@ -46,13 +53,16 @@ stage('Test') { } }, 'docs: GPU': { - ci.test('GPU', 'docs: GPU', 'tvm/docs-python-gpu', images.ci_gpu, 'gpu') { + ci.with_node(instance: 'GPU-SPOT', retry_instance: 'GPU', + name: 'docs: GPU', folder: 'tvm/docs-python-gpu', + variables: ['PLATFORM=gpu', 'TEST_STEP_NAME=docs: GPU']) { + ci.docker_init(images.ci_gpu) ci.download('gpu') sh( script: "${docker_run} ${images.ci_gpu} ./tests/scripts/task_python_docs.sh", label: 'Build docs', ) - ci.upload('docs', '--paths docs.tgz') + ci.upload_artifacts('docs', '--paths docs.tgz') sh( script: "aws s3 cp --no-progress _docs s3://${s3_bucket}/${s3_prefix}/docs --recursive", label: 'Upload docs to S3', diff --git a/ci/jenkins/generated/wasm_jenkinsfile.groovy b/ci/jenkins/generated/wasm_jenkinsfile.groovy index ddf932529d..da38b1c237 100644 --- a/ci/jenkins/generated/wasm_jenkinsfile.groovy +++ b/ci/jenkins/generated/wasm_jenkinsfile.groovy @@ -19,16 +19,20 @@ ci = evaluate(readTrusted('ci/jenkins/generated/common.groovy')) ci.start() -ci.build('CPU', 'BUILD: WASM', 'tvm/build-wasm', images.ci_wasm, 'wasm') { - sh( - script: "${docker_run} ${images.ci_wasm} ./tests/scripts/task_config_build_wasm.sh build", - label: 'Create WASM CMake config', - ) - ci.cmake_build(images.ci_wasm, 'build') - ci.make_cpp_tests(images.ci_wasm, 'build') - ci.cpp_unittest(images.ci_wasm) - sh( - script: "${docker_run} ${images.ci_wasm} ./tests/scripts/task_web_wasm.sh", - label: 'Run WASM lint and tests', - ) +stage('Build') { + ci.with_node(instance: 'CPU-SPOT', retry_instance: 'CPU', + name: 'BUILD: WASM', folder: 'tvm/build-wasm', variables: ['PLATFORM=wasm']) { + ci.docker_init(images.ci_wasm) + sh( + script: "${docker_run} ${images.ci_wasm} ./tests/scripts/task_config_build_wasm.sh build", + label: 'Create WASM CMake config', + ) + ci.cmake_build(images.ci_wasm, 'build') + ci.make_cpp_tests(images.ci_wasm, 'build') + ci.cpp_unittest(images.ci_wasm) + sh( + script: "${docker_run} ${images.ci_wasm} ./tests/scripts/task_web_wasm.sh", + label: 'Run WASM lint and tests', + ) + } }
