705 lines
21 KiB
Groovy
Generated
705 lines
21 KiB
Groovy
Generated
// Licensed to the Apache Software Foundation (ASF) under one
|
|
// or more contributor license agreements. See the NOTICE file
|
|
// distributed with this work for additional information
|
|
// regarding copyright ownership. The ASF licenses this file
|
|
// to you under the Apache License, Version 2.0 (the
|
|
// "License"); you may not use this file except in compliance
|
|
// with the License. You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing,
|
|
// software distributed under the License is distributed on an
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations
|
|
// under the License.
|
|
// -*- mode: groovy -*-
|
|
|
|
// Licensed to the Apache Software Foundation (ASF) under one
|
|
// or more contributor license agreements. See the NOTICE file
|
|
// distributed with this work for additional information
|
|
// regarding copyright ownership. The ASF licenses this file
|
|
// to you under the Apache License, Version 2.0 (the
|
|
// "License"); you may not use this file except in compliance
|
|
// with the License. You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing,
|
|
// software distributed under the License is distributed on an
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
// Jenkins pipeline
|
|
// See documents at https://jenkins.io/doc/book/pipeline/jenkinsfile/
|
|
|
|
// Docker env used for testing
|
|
// Different image may have different version tag
|
|
// because some of them are more stable than anoter.
|
|
//
|
|
// Docker images are maintained by PMC, cached in dockerhub
|
|
// and remains relatively stable over the time.
|
|
// Flow for upgrading docker env(need commiter)
|
|
//
|
|
// - Send PR to upgrade build script in the repo
|
|
// - Build the new docker image
|
|
// - Tag the docker image with a new version and push to a binary cache.
|
|
// - Update the version in the Jenkinsfile, send a PR
|
|
// - Fix any issues wrt to the new image version in the PR
|
|
// - Merge the PR and now we are in new version
|
|
// - Tag the new version as the lates
|
|
// - Periodically cleanup the old versions on local workers
|
|
//
|
|
|
|
// ============================= IMPORTANT NOTE =============================
|
|
// This file is generated by 'jenkins/generate.py'. Do not edit this file directly!
|
|
// Make edits to 'jenkins/Jenkinsfile.j2' and regenerate this with
|
|
// 'python3 jenkins/generate.py'
|
|
// Note: This timestamp is here to ensure that updates to the Jenkinsfile are
|
|
// always rebased on main before merging:
|
|
// Generated at 2026-07-05T12:52:04.884879
|
|
|
|
import org.jenkinsci.plugins.pipeline.modeldefinition.Utils
|
|
// These are set at runtime from data in ci/jenkins/docker-images.yml, update
|
|
// image tags in that file
|
|
ci_gpu = ''
|
|
ci_cpu = ''
|
|
ci_minimal = ''
|
|
ci_wasm = ''
|
|
ci_cortexm = ''
|
|
ci_arm = ''
|
|
ci_riscv = ''
|
|
|
|
// Parameters to allow overriding (in Jenkins UI), the images
|
|
// to be used by a given build. When provided, they take precedence
|
|
// over default values above.
|
|
properties([
|
|
parameters([
|
|
string(name: 'ci_arm_param', defaultValue: ''),
|
|
string(name: 'ci_cpu_param', defaultValue: ''),
|
|
string(name: 'ci_gpu_param', defaultValue: ''),
|
|
string(name: 'ci_wasm_param', defaultValue: ''),
|
|
])
|
|
])
|
|
|
|
// Placeholders for newly built Docker image names (if rebuild_docker_images
|
|
// is used)
|
|
built_ci_arm = null;
|
|
built_ci_cpu = null;
|
|
built_ci_gpu = null;
|
|
built_ci_wasm = null;
|
|
|
|
// Global variable assigned during Sanity Check that holds the sha1 which should be
|
|
// merged into the PR in all branches.
|
|
upstream_revision = null
|
|
|
|
// command to start a docker container
|
|
docker_run = 'docker/bash.sh --env CI --env PLATFORM --env SKIP_SLOW_TESTS --env TEST_STEP_NAME'
|
|
docker_build = 'docker/build.sh'
|
|
// timeout in minutes
|
|
max_time = 180
|
|
rebuild_docker_images = false
|
|
|
|
s3_bucket = 'tvm-jenkins-artifacts-prod'
|
|
s3_prefix = "tvm/${env.BRANCH_NAME}/${env.BUILD_NUMBER}"
|
|
|
|
// Jenkins script root directory
|
|
jenkins_scripts_root = "ci/scripts/jenkins"
|
|
|
|
|
|
// General note: Jenkins has limits on the size of a method (or top level code)
|
|
// that are pretty strict, so most usage of groovy methods in these templates
|
|
// are purely to satisfy the JVM
|
|
def per_exec_ws(folder) {
|
|
return "workspace/exec_${env.EXECUTOR_NUMBER}/" + folder
|
|
}
|
|
|
|
// initialize source codes
|
|
def init_git() {
|
|
retry(5) {
|
|
checkout scm
|
|
}
|
|
|
|
// Add more info about job node
|
|
sh (
|
|
script: './tests/scripts/task_show_node_info.sh',
|
|
label: 'Show executor node info',
|
|
)
|
|
|
|
// Determine merge commit to use for all stages
|
|
if (env.CHANGE_TARGET) {
|
|
// This is a PR build, so merge with the latest of the PR's target branch
|
|
// (e.g. main or a release branch like v0.25.0).
|
|
merge_with_target()
|
|
} else {
|
|
// This is a branch build (main or a release branch). Only set
|
|
// upstream_revision to HEAD and skip merging to avoid a race with another
|
|
// commit merged to the branch.
|
|
update_upstream_revision("HEAD")
|
|
}
|
|
|
|
sh(
|
|
script: """
|
|
set -eux
|
|
. ${jenkins_scripts_root}/retry.sh
|
|
retry 3 timeout 5m git submodule update --init --recursive -f --jobs 0
|
|
""",
|
|
label: 'Update git submodules',
|
|
)
|
|
checkout_trusted_files()
|
|
}
|
|
|
|
def update_upstream_revision(git_ref) {
|
|
if (upstream_revision == null) {
|
|
upstream_revision = sh(
|
|
script: "git log -1 ${git_ref} --format=\'%H\'",
|
|
label: 'Determine upstream revision',
|
|
returnStdout: true,
|
|
).trim()
|
|
}
|
|
}
|
|
|
|
def merge_with_target() {
|
|
def target = env.CHANGE_TARGET
|
|
sh (
|
|
script: "git fetch origin ${target}",
|
|
label: "Fetch target branch ${target}",
|
|
)
|
|
update_upstream_revision("FETCH_HEAD")
|
|
sh (
|
|
script: "git -c user.name=TVM-Jenkins -c user.email=jenkins@tvm.apache.org merge ${upstream_revision}",
|
|
label: "Merge to origin/${target}"
|
|
)
|
|
}
|
|
|
|
def docker_init(image) {
|
|
// Clear out all Docker images that aren't going to be used
|
|
sh(
|
|
script: """
|
|
set -eux
|
|
docker image ls --all
|
|
IMAGES=\$(docker image ls --all --format '{{.Repository}}:{{.Tag}} {{.ID}}')
|
|
|
|
echo -e "Found images:\\n\$IMAGES"
|
|
echo "\$IMAGES" | { grep -vE '${image}' || test \$? = 1; } | { xargs docker rmi || test \$? = 123; }
|
|
|
|
docker image ls --all
|
|
""",
|
|
label: 'Clean old Docker images',
|
|
)
|
|
|
|
if (image.contains("amazonaws.com")) {
|
|
// If this string is in the image name it's from ECR and needs to be pulled
|
|
// with the right credentials
|
|
ecr_pull(image)
|
|
} else {
|
|
sh(
|
|
script: """
|
|
set -eux
|
|
. ${jenkins_scripts_root}/retry.sh
|
|
retry 5 docker pull ${image}
|
|
""",
|
|
label: 'Pull docker image',
|
|
)
|
|
}
|
|
}
|
|
|
|
def ecr_pull(full_name) {
|
|
aws_account_id = sh(
|
|
returnStdout: true,
|
|
script: 'aws sts get-caller-identity | grep Account | cut -f4 -d\\"',
|
|
label: 'Get AWS ID'
|
|
).trim()
|
|
|
|
try {
|
|
withEnv([
|
|
"AWS_ACCOUNT_ID=${aws_account_id}",
|
|
'AWS_DEFAULT_REGION=us-west-2',
|
|
"AWS_ECR_REPO=${aws_account_id}.dkr.ecr.us-west-2.amazonaws.com"]) {
|
|
sh(
|
|
script: '''
|
|
set -eux
|
|
aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ECR_REPO
|
|
''',
|
|
label: 'Log in to ECR'
|
|
)
|
|
sh(
|
|
script: """
|
|
set -eux
|
|
. ${jenkins_scripts_root}/retry.sh
|
|
retry 5 docker pull ${full_name}
|
|
""",
|
|
label: 'Pull image from ECR'
|
|
)
|
|
}
|
|
} finally {
|
|
withEnv([
|
|
"AWS_ACCOUNT_ID=${aws_account_id}",
|
|
'AWS_DEFAULT_REGION=us-west-2',
|
|
"AWS_ECR_REPO=${aws_account_id}.dkr.ecr.us-west-2.amazonaws.com"]) {
|
|
sh(
|
|
script: 'docker logout $AWS_ECR_REPO',
|
|
label: 'Clean up login credentials'
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
def should_skip_slow_tests(pr_number) {
|
|
withCredentials([string(
|
|
credentialsId: 'tvm-bot-jenkins-reader',
|
|
variable: 'GITHUB_TOKEN',
|
|
)]) {
|
|
// Exit code of 1 means run slow tests, exit code of 0 means skip slow tests
|
|
result = sh (
|
|
returnStatus: true,
|
|
script: "./${jenkins_scripts_root}/should_run_slow_tests.py --pr '${pr_number}'",
|
|
label: 'Check if CI should run slow tests',
|
|
)
|
|
}
|
|
return result == 0
|
|
}
|
|
|
|
def cancel_previous_build() {
|
|
// cancel previous build if it is not on main.
|
|
if (env.BRANCH_NAME != 'main') {
|
|
def buildNumber = env.BUILD_NUMBER as int
|
|
// Milestone API allows us to cancel previous build
|
|
// with the same milestone number
|
|
if (buildNumber > 1) milestone(buildNumber - 1)
|
|
milestone(buildNumber)
|
|
}
|
|
}
|
|
|
|
def is_last_build() {
|
|
// check whether it is last build
|
|
try {
|
|
return currentBuild.number == currentBuild.rawBuild.project.getLastBuild().number
|
|
} catch (Throwable ex) {
|
|
echo 'Error during check is_last_build ' + ex.toString()
|
|
return false
|
|
}
|
|
}
|
|
|
|
def checkout_trusted_files() {
|
|
// trust everything from branch builds
|
|
if (env.BRANCH_NAME == null || !env.BRANCH_NAME.startsWith('PR-')) {
|
|
return;
|
|
}
|
|
|
|
// trust peoople listed in CONTRIBUTING.md
|
|
grep_code = sh(
|
|
returnStatus: true,
|
|
script: "git show '${upstream_revision}:CONTRIBUTORS.md' | grep '@${env.CHANGE_AUTHOR}'",
|
|
label: 'Check if change is from a contributor',
|
|
)
|
|
|
|
if (grep_code == 1) {
|
|
// Any scripts that run on the bare host and not inside a Docker container
|
|
// (especially those that access secrets) should be checked out here so
|
|
// only trusted versions are used in CI
|
|
sh(
|
|
script: "git checkout ${upstream_revision} ${jenkins_scripts_root}/.",
|
|
label: 'Check out trusted files',
|
|
)
|
|
}
|
|
}
|
|
|
|
def should_skip_ci(pr_number) {
|
|
if (env.BRANCH_NAME == null || !env.BRANCH_NAME.startsWith('PR-')) {
|
|
// never skip CI on build sourced from a branch
|
|
return false
|
|
}
|
|
glob_skip_ci_code = sh (
|
|
returnStatus: true,
|
|
script: "./${jenkins_scripts_root}/git_skip_ci_globs.py",
|
|
label: 'Check if CI should be skipped due to changed files',
|
|
)
|
|
if (glob_skip_ci_code == 0) {
|
|
return true
|
|
}
|
|
withCredentials([string(
|
|
credentialsId: 'tvm-bot-jenkins-reader',
|
|
variable: 'GITHUB_TOKEN',
|
|
)]) {
|
|
// Exit code of 1 means run full CI (or the script had an error, so run
|
|
// full CI just in case). Exit code of 0 means skip CI.
|
|
git_skip_ci_code = sh (
|
|
returnStatus: true,
|
|
script: "./${jenkins_scripts_root}/git_skip_ci.py --pr '${pr_number}'",
|
|
label: 'Check if CI should be skipped',
|
|
)
|
|
}
|
|
return git_skip_ci_code == 0
|
|
}
|
|
|
|
def prepare(node_type) {
|
|
stage('Prepare') {
|
|
node(node_type) {
|
|
ws("workspace/exec_${env.EXECUTOR_NUMBER}/tvm/prepare") {
|
|
init_git()
|
|
|
|
if (env.DETERMINE_DOCKER_IMAGES == 'yes') {
|
|
sh(
|
|
script: "./${jenkins_scripts_root}/determine_docker_images.py ci_arm ci_cpu ci_gpu ci_wasm ",
|
|
label: 'Decide whether to use tlcpack or tlcpackstaging for Docker images',
|
|
)
|
|
// Pull image names from the results of should_rebuild_docker.py
|
|
ci_arm = sh(
|
|
script: "cat .docker-image-names/ci_arm",
|
|
label: "Find docker image name for ci_arm",
|
|
returnStdout: true,
|
|
).trim()
|
|
ci_cpu = sh(
|
|
script: "cat .docker-image-names/ci_cpu",
|
|
label: "Find docker image name for ci_cpu",
|
|
returnStdout: true,
|
|
).trim()
|
|
ci_gpu = sh(
|
|
script: "cat .docker-image-names/ci_gpu",
|
|
label: "Find docker image name for ci_gpu",
|
|
returnStdout: true,
|
|
).trim()
|
|
ci_wasm = sh(
|
|
script: "cat .docker-image-names/ci_wasm",
|
|
label: "Find docker image name for ci_wasm",
|
|
returnStdout: true,
|
|
).trim()
|
|
}
|
|
|
|
ci_arm = params.ci_arm_param ?: ci_arm
|
|
ci_cpu = params.ci_cpu_param ?: ci_cpu
|
|
ci_gpu = params.ci_gpu_param ?: ci_gpu
|
|
ci_wasm = params.ci_wasm_param ?: ci_wasm
|
|
|
|
sh (script: """
|
|
echo "Docker images being used in this build:"
|
|
echo " ci_arm = ${ci_arm}"
|
|
echo " ci_cpu = ${ci_cpu}"
|
|
echo " ci_gpu = ${ci_gpu}"
|
|
echo " ci_wasm = ${ci_wasm}"
|
|
""", label: 'Docker image names')
|
|
|
|
is_docs_only_build = sh (
|
|
returnStatus: true,
|
|
script: "./${jenkins_scripts_root}/git_change_docs.sh",
|
|
label: 'Check for docs only changes',
|
|
)
|
|
skip_ci = should_skip_ci(env.CHANGE_ID)
|
|
skip_slow_tests = should_skip_slow_tests(env.CHANGE_ID)
|
|
rebuild_docker_images = sh (
|
|
returnStatus: true,
|
|
script: "./${jenkins_scripts_root}/git_change_docker.sh",
|
|
label: 'Check for any docker changes',
|
|
)
|
|
|
|
if (skip_ci) {
|
|
// Don't rebuild when skipping CI
|
|
rebuild_docker_images = false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
def python_unittest(image) {
|
|
sh (
|
|
script: "${docker_run} ${image} ./tests/scripts/task_python_unittest.sh",
|
|
label: 'Run Python unit tests',
|
|
)
|
|
}
|
|
|
|
def make_cpp_tests(image, build_dir) {
|
|
sh (
|
|
script: """
|
|
set -eux
|
|
${docker_run} ${image} python3 ./tests/scripts/task_build.py \
|
|
--sccache-bucket tvm-sccache-prod \
|
|
--sccache-region us-west-2 \
|
|
--cmake-target cpptest \
|
|
--build-dir ${build_dir}
|
|
""",
|
|
label: 'Make C++ tests',
|
|
)
|
|
}
|
|
|
|
def cmake_build(image, path) {
|
|
sh (
|
|
script: "${docker_run} --env CI_NUM_EXECUTORS ${image} ./tests/scripts/task_build.py --sccache-bucket tvm-sccache-prod --sccache-region us-west-2 --build-dir ${path}",
|
|
label: 'Run CMake build',
|
|
)
|
|
}
|
|
def cpp_unittest(image) {
|
|
sh (
|
|
script: "${docker_run} --env CI_NUM_EXECUTORS ${image} ./tests/scripts/task_cpp_unittest.sh",
|
|
label: 'Run C++ tests',
|
|
)
|
|
}
|
|
|
|
cancel_previous_build()
|
|
|
|
try {
|
|
prepare('CPU-SMALL-SPOT')
|
|
} catch(Exception ex) {
|
|
prepare('CPU-SMALL')
|
|
}
|
|
def run_build(node_type) {
|
|
if (!skip_ci) {
|
|
echo 'Begin running node_type ' + node_type
|
|
node(node_type) {
|
|
ws("workspace/exec_${env.EXECUTOR_NUMBER}/tvm/build-gpu") {
|
|
init_git()
|
|
docker_init(ci_gpu)
|
|
timeout(time: max_time, unit: 'MINUTES') {
|
|
|
|
withEnv([
|
|
'PLATFORM=gpu',
|
|
], {
|
|
sh "${docker_run} --no-gpu ${ci_gpu} ./tests/scripts/task_config_build_gpu.sh build"
|
|
cmake_build("${ci_gpu} --no-gpu", 'build')
|
|
sh(
|
|
script: "./${jenkins_scripts_root}/s3.py --action upload --bucket ${s3_bucket} --prefix ${s3_prefix}/gpu --bundle tvm_lib --bundle tvm_lib_gpu_extra",
|
|
label: 'Upload artifacts to S3',
|
|
)
|
|
|
|
|
|
// compiler test
|
|
sh "rm -rf build"
|
|
sh "${docker_run} --no-gpu ${ci_gpu} ./tests/scripts/task_config_build_gpu_other.sh build"
|
|
sh "${docker_run} --env CI_NUM_EXECUTORS ${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"
|
|
})
|
|
}
|
|
}
|
|
}
|
|
echo 'End running node_type ' + node_type
|
|
} else {
|
|
Utils.markStageSkippedForConditional('BUILD: GPU')
|
|
}
|
|
}
|
|
def build() {
|
|
stage('Build') {
|
|
try {
|
|
run_build('CPU-SPOT')
|
|
} catch (hudson.AbortException abortEx) {
|
|
echo "Received normal AbortException, exit now. Details:" + abortEx.toString()
|
|
throw abortEx
|
|
} catch (Throwable ex) {
|
|
echo 'Exception during SPOT run ' + ex.toString()
|
|
if (is_last_build()) {
|
|
// retry if we are currently at last build
|
|
// mark the current stage as success
|
|
// and try again via on demand node
|
|
echo 'Retry on-demand given it is last build'
|
|
currentBuild.result = 'SUCCESS'
|
|
run_build('CPU')
|
|
} else {
|
|
echo 'Exit since it is not last build'
|
|
throw ex
|
|
}
|
|
}
|
|
}
|
|
}
|
|
build()
|
|
|
|
|
|
def run_unittest_GPU(node_type) {
|
|
echo 'Begin running on node_type ' + node_type
|
|
if (!skip_ci && is_docs_only_build != 1) {
|
|
node(node_type) {
|
|
ws("workspace/exec_${env.EXECUTOR_NUMBER}/tvm/ut-python-gpu") {
|
|
// NOTE: if exception happens, it will be caught outside
|
|
init_git()
|
|
docker_init(ci_gpu)
|
|
timeout(time: max_time, unit: 'MINUTES') {
|
|
withEnv([
|
|
'PLATFORM=gpu',
|
|
'TEST_STEP_NAME=unittest: GPU',
|
|
"SKIP_SLOW_TESTS=${skip_slow_tests}"], {
|
|
sh(
|
|
script: "./${jenkins_scripts_root}/s3.py --action download --bucket ${s3_bucket} --prefix ${s3_prefix}/gpu",
|
|
label: 'Download artifacts from S3',
|
|
)
|
|
|
|
sh (
|
|
script: "${docker_run} ${ci_gpu} ./tests/scripts/task_java_unittest.sh",
|
|
label: 'Run Java unit tests',
|
|
)
|
|
sh (
|
|
script: "${docker_run} ${ci_gpu} ./tests/scripts/task_python_unittest_gpuonly.sh",
|
|
label: 'Run Python GPU unit tests',
|
|
)
|
|
})
|
|
}
|
|
}
|
|
}
|
|
echo 'End running on node_type ' + node_type
|
|
} else {
|
|
Utils.markStageSkippedForConditional('unittest: GPU')
|
|
}
|
|
}
|
|
|
|
|
|
|
|
def run_docs_GPU(node_type) {
|
|
echo 'Begin running on node_type ' + node_type
|
|
if (!skip_ci) {
|
|
node(node_type) {
|
|
ws("workspace/exec_${env.EXECUTOR_NUMBER}/tvm/docs-python-gpu") {
|
|
// NOTE: if exception happens, it will be caught outside
|
|
init_git()
|
|
docker_init(ci_gpu)
|
|
timeout(time: max_time, unit: 'MINUTES') {
|
|
withEnv([
|
|
'PLATFORM=gpu',
|
|
'TEST_STEP_NAME=docs: GPU',
|
|
"SKIP_SLOW_TESTS=${skip_slow_tests}"], {
|
|
sh(
|
|
script: "./${jenkins_scripts_root}/s3.py --action download --bucket ${s3_bucket} --prefix ${s3_prefix}/gpu",
|
|
label: 'Download artifacts from S3',
|
|
)
|
|
|
|
sh (
|
|
script: "${docker_run} ${ci_gpu} ./tests/scripts/task_python_docs.sh",
|
|
label: 'Build docs',
|
|
)
|
|
sh(
|
|
script: "./${jenkins_scripts_root}/s3.py --action upload --bucket ${s3_bucket} --prefix ${s3_prefix}/docs --items docs.tgz",
|
|
label: 'Upload artifacts to S3',
|
|
)
|
|
|
|
sh(
|
|
script: "aws s3 cp --no-progress _docs s3://${s3_bucket}/${s3_prefix}/docs --recursive",
|
|
label: 'Upload docs to S3',
|
|
)
|
|
})
|
|
}
|
|
}
|
|
}
|
|
echo 'End running on node_type ' + node_type
|
|
} else {
|
|
Utils.markStageSkippedForConditional('docs: GPU')
|
|
}
|
|
}
|
|
|
|
|
|
|
|
def test() {
|
|
stage('Test') {
|
|
environment {
|
|
SKIP_SLOW_TESTS = "${skip_slow_tests}"
|
|
}
|
|
parallel(
|
|
'unittest: GPU': {
|
|
try {
|
|
run_unittest_GPU('GPU-SPOT')
|
|
} catch (Throwable ex) {
|
|
echo 'Exception during SPOT run ' + ex.toString()
|
|
if (is_last_build()) {
|
|
// retry if at last build
|
|
// mark the current stage as success
|
|
// and try again via on demand node
|
|
echo 'Retry on-demand given it is last build'
|
|
currentBuild.result = 'SUCCESS'
|
|
run_unittest_GPU('GPU')
|
|
} else {
|
|
echo 'Exit since it is not last build'
|
|
throw ex
|
|
}
|
|
}
|
|
},
|
|
'docs: GPU': {
|
|
try {
|
|
run_docs_GPU('GPU-SPOT')
|
|
} catch (Throwable ex) {
|
|
echo 'Exception during SPOT run ' + ex.toString()
|
|
if (is_last_build()) {
|
|
// retry if at last build
|
|
// mark the current stage as success
|
|
// and try again via on demand node
|
|
echo 'Retry on-demand given it is last build'
|
|
currentBuild.result = 'SUCCESS'
|
|
run_docs_GPU('GPU')
|
|
} else {
|
|
echo 'Exit since it is not last build'
|
|
throw ex
|
|
}
|
|
}
|
|
},
|
|
)
|
|
}
|
|
}
|
|
test()
|
|
|
|
|
|
|
|
def deploy_docs() {
|
|
// Note: This code must stay in the Jenkinsfile to ensure that it runs
|
|
// from a trusted context only
|
|
sh(
|
|
script: '''
|
|
set -eux
|
|
rm -rf tvm-site
|
|
git clone -b $DOCS_DEPLOY_BRANCH --depth=1 https://github.com/apache/tvm-site
|
|
cd tvm-site
|
|
git status
|
|
git checkout -B $DOCS_DEPLOY_BRANCH
|
|
|
|
git ls-tree HEAD docs/ --name-only | grep -vP '^docs/v\\d' | xargs rm -rf
|
|
mkdir -p docs
|
|
tar xf ../docs.tgz -C docs
|
|
COMMIT=$(cat docs/commit_hash)
|
|
git add .
|
|
git config user.name tvm-bot
|
|
git config user.email 95660001+tvm-bot@users.noreply.github.com
|
|
git commit -m"deploying docs (apache/tvm@$COMMIT)"
|
|
git status
|
|
''',
|
|
label: 'Unpack docs and update tvm-site'
|
|
)
|
|
|
|
withCredentials([string(
|
|
credentialsId: 'docs-push-token',
|
|
variable: 'GITHUB_TOKEN',
|
|
)]) {
|
|
sh(
|
|
script: '''
|
|
cd tvm-site
|
|
git remote add deploy https://$GITHUB_TOKEN:x-oauth-basic@github.com/apache/tvm-site.git
|
|
git push deploy $DOCS_DEPLOY_BRANCH || true
|
|
''',
|
|
label: 'Upload docs to apache/tvm-site'
|
|
)
|
|
}
|
|
}
|
|
|
|
def deploy() {
|
|
stage('Deploy') {
|
|
if (env.BRANCH_NAME == 'main') {
|
|
parallel(
|
|
'Deploy Docs': {
|
|
if (env.DOCS_DEPLOY_ENABLED == 'yes') {
|
|
node('CPU') {
|
|
ws("workspace/exec_${env.EXECUTOR_NUMBER}/tvm/deploy-docs") {
|
|
timeout(time: max_time, unit: 'MINUTES') {
|
|
init_git()
|
|
sh(
|
|
script: "./${jenkins_scripts_root}/s3.py --action download --bucket ${s3_bucket} --prefix ${s3_prefix}/docs --items docs.tgz",
|
|
label: 'Download docs folder from S3',
|
|
)
|
|
deploy_docs()
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
Utils.markStageSkippedForConditional('Deploy Docs')
|
|
}
|
|
},
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
deploy()
|