-
Notifications
You must be signed in to change notification settings - Fork 6.7k
Redesign Jenkinsfiles #12000
Redesign Jenkinsfiles #12000
Changes from all commits
52a2694
19f25f1
aff116a
6c39cd8
34d288d
b2bea2a
33d838f
fc4c2e8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,153 @@ | ||
| // -*- 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. | ||
|
|
||
| // initialize source codes | ||
| def init_git() { | ||
| deleteDir() | ||
| retry(5) { | ||
| try { | ||
| // Make sure wait long enough for api.github.com request quota. Important: Don't increase the amount of | ||
| // retries as this will increase the amount of requests and worsen the throttling | ||
| timeout(time: 15, unit: 'MINUTES') { | ||
| checkout scm | ||
| sh 'git submodule update --init --recursive' | ||
| sh 'git clean -xdff' | ||
| } | ||
| } catch (exc) { | ||
| deleteDir() | ||
| error "Failed to fetch source codes with ${exc}" | ||
| sleep 2 | ||
| } | ||
| } | ||
| } | ||
|
|
||
| def init_git_win() { | ||
| deleteDir() | ||
| retry(5) { | ||
| try { | ||
| // Make sure wait long enough for api.github.com request quota. Important: Don't increase the amount of | ||
| // retries as this will increase the amount of requests and worsen the throttling | ||
| timeout(time: 15, unit: 'MINUTES') { | ||
| checkout scm | ||
| bat 'git submodule update --init --recursive' | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this check if there's an error? I found that bat doesn't. powershell does to some degree. Why don't we use PS?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know. The scope of this PR is restructuring the Jenkinsfiles and not a refactor of what we do in there. |
||
| bat 'git clean -xdff' | ||
| } | ||
| } catch (exc) { | ||
| deleteDir() | ||
| error "Failed to fetch source codes with ${exc}" | ||
| sleep 2 | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // pack libraries for later use | ||
| def pack_lib(name, libs) { | ||
| sh """ | ||
| echo "Packing ${libs} into ${name}" | ||
| echo ${libs} | sed -e 's/,/ /g' | xargs md5sum | ||
| """ | ||
| stash includes: libs, name: name | ||
| } | ||
|
|
||
| // unpack libraries saved before | ||
| def unpack_lib(name, libs) { | ||
| unstash name | ||
| sh """ | ||
| echo "Unpacked ${libs} from ${name}" | ||
| echo ${libs} | sed -e 's/,/ /g' | xargs md5sum | ||
| """ | ||
| } | ||
|
|
||
| def publish_test_coverage() { | ||
| // Fall back to our own copy of the bash helper if it failed to download the public version | ||
| sh '(curl --retry 10 -s https://codecov.io/bash | bash -s -) || (curl --retry 10 -s https://s3-us-west-2.amazonaws.com/mxnet-ci-prod-slave-data/codecov-bash.txt | bash -s -)' | ||
| } | ||
|
|
||
| def collect_test_results_unix(original_file_name, new_file_name) { | ||
| if (fileExists(original_file_name)) { | ||
| // Rename file to make it distinguishable. Unfortunately, it's not possible to get STAGE_NAME in a parallel stage | ||
| // Thus, we have to pick a name manually and rename the files so that they can be stored separately. | ||
| sh 'cp ' + original_file_name + ' ' + new_file_name | ||
| archiveArtifacts artifacts: new_file_name | ||
| } | ||
| } | ||
|
|
||
| def collect_test_results_windows(original_file_name, new_file_name) { | ||
| // Rename file to make it distinguishable. Unfortunately, it's not possible to get STAGE_NAME in a parallel stage | ||
| // Thus, we have to pick a name manually and rename the files so that they can be stored separately. | ||
| if (fileExists(original_file_name)) { | ||
| bat 'xcopy ' + original_file_name + ' ' + new_file_name + '*' | ||
| archiveArtifacts artifacts: new_file_name | ||
| } | ||
| } | ||
|
|
||
|
|
||
| def docker_run(platform, function_name, use_nvidia, shared_mem = '500m') { | ||
| def command = "ci/build.py --docker-registry ${env.DOCKER_CACHE_REGISTRY} %USE_NVIDIA% --platform %PLATFORM% --docker-build-retries 3 --shm-size %SHARED_MEM% /work/runtime_functions.sh %FUNCTION_NAME%" | ||
| command = command.replaceAll('%USE_NVIDIA%', use_nvidia ? '--nvidiadocker' : '') | ||
| command = command.replaceAll('%PLATFORM%', platform) | ||
| command = command.replaceAll('%FUNCTION_NAME%', function_name) | ||
| command = command.replaceAll('%SHARED_MEM%', shared_mem) | ||
|
|
||
| sh command | ||
| } | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. whitespace |
||
|
|
||
|
|
||
| def assign_node_labels(args) { | ||
| NODE_LINUX_CPU = args.linux_cpu | ||
| NODE_LINUX_GPU = args.linux_gpu | ||
| NODE_LINUX_GPU_P3 = args.linux_gpu_p3 | ||
| NODE_WINDOWS_CPU = args.windows_cpu | ||
| NODE_WINDOWS_GPU = args.windows_gpu | ||
| } | ||
|
|
||
| def main_wrapper(args) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👀🤔 |
||
| // Main Jenkinsfile pipeline wrapper handler that allows to wrap core logic into a format | ||
| // that supports proper failure handling | ||
| // args: | ||
| // - core_logic: Jenkins pipeline containing core execution logic | ||
| // - failure_handler: Failure handler | ||
|
|
||
| // assign any caught errors here | ||
| err = null | ||
| try { | ||
| args['core_logic']() | ||
|
|
||
| // set build status to success at the end | ||
| currentBuild.result = "SUCCESS" | ||
| } catch (caughtError) { | ||
| node(NODE_LINUX_CPU) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we clarify this? It looks strange, why call bash to do echo? We can print from groovy right? Why match this particular node?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good question |
||
| sh "echo caught ${caughtError}" | ||
| err = caughtError | ||
| currentBuild.result = "FAILURE" | ||
| } | ||
| } finally { | ||
| node(NODE_LINUX_CPU) { | ||
| // Call failure handler | ||
| args['failure_handler']() | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure why this is in a finally. Why not call this from the catch? Then we wouldn't need the check in each failure_handler to see if it's result failed. We also wouldn't have to store the err and then re-throw it.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a good point. In the past, we had nested functions which were expected to continue although they had a failure and then exit at a later point in time. I don't think this applies anymore. Could we save this up for a refactor? I'm trying not to make any behavioural modifications here. |
||
|
|
||
| // Remember to rethrow so the build is marked as failing | ||
| if (err) { | ||
| throw err | ||
| } | ||
| } | ||
| } | ||
| } | ||
| return this | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is inconsistent with the constant labels style from the other files, why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, I missed replacing it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, it's explained below:
We can not use the constants at that point because the utility to load a constant has not been loaded at that point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need a node to define some constants? Could we have a separate file for them and load it before?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately yes. It's not possible to load other groovy scripts without being in a node context