如何在 Jenkins 多分支管道中安排具有特定参数的作业
How to schedules jobs with specific parameters in a Jenkins multibranch pipeline
我们在 Jenkins 上有 2 个 FreeStyle 项目:
一个生成构建(每日构建+手动构建),另一个执行测试。
我们正在转向 jenkins 上的多分支管道,所以我的理解是每个存储库有一个项目,我们应该使用选项来实现不同的行为。
所以我可以创建参数,以指示我们是否要 运行 测试,如果我们要构建设置,那部分我可以接受。
我的问题是我需要默认情况下不执行测试(因为生成它们需要很多时间,而且我不希望开发人员错误地让 "Execute tests"选项已选中。
而且我需要在夜间执行每日构建时选中此选项。
所以 2 个问题:
- 如何安排?
- 如何提供用于此计划的参数值?
您可以创建一个单独的多分支作业,它将 运行 按计划触发您的主要作业,覆盖所有必要的参数。
它看起来像这样
pipeline {
agent any
triggers {
pollSCM('0 0 * * *')
}
stages {
stage('Triggering the main job') {
steps {
build job: "main/${BRANCH_NAME.replace('/', '%2F')}",
parameters: [string(name: 'RUN_TESTS', value: 'true')]
}
}
}
}
您应该将此文件与您的主 Jenkinsfile
放在存储库中,并配置一个单独的多分支管道作业来使用此文件。
要在同一份工作中保持这一点,需要一些 groovy 编码。由于您使用的是 MultiBranch 管道,因此这一切都可以存在于您的 Jenkinsfile
中
首先,按照 Vitalii 提到的那样设置您的 cron,这将按计划启动工作。
properties([
pipelineTriggers([cron('0 0 * * *')])
])
接下来,当这个作业被调度触发时,我们要调整它的参数运行。所以首先我们需要检查导致构建的原因。这可能需要安全脚本批准。
List causes = currentBuild.rawBuild.getCauses().collect { it.getClass().getCanonicalName().tokenize('.').last() }
如果其中包含 'TimerTriggerCause'
那么我们要更新参数。
if (causes.contains('TimerTriggerCause') {
setBooleanParam("EXECUTE_TESTS", true)
}
我们为此在共享库中编写了一个函数,如果您愿意,可以将其放在同一个 Jenkinsfile 中(在管道逻辑之外的底部):
/**
* Change boolean param value during build
*
* @param paramName new or existing param name
* @param paramValue param value
* @return nothing
*/
Void setBooleanParam(String paramName, Boolean paramValue) {
List<ParameterValue> newParams = new ArrayList<>();
newParams.add(new BooleanParameterValue(paramName, paramValue))
try {
$build().addOrReplaceAction($build().getAction(ParametersAction.class).createUpdated(newParams))
} catch (err) {
$build().addOrReplaceAction(new ParametersAction(newParams))
}
}
并让工作照常进行。当开始评估 params.EXECUTE_TESTS 时,这将是 true(而不是默认的 false)。
注意:可能需要为值导入模型
import hudson.model.BooleanParameterValue
将所有内容放在一起(只是将各个部分快速拼凑起来以获得整体图片),您的 jenkinsfile 最终会像这样
#!groovy
import hudson.model.BooleanParameterValue
List paramsList = [
choice(name: 'ACCOUNT_NAME', choices: ['account1', 'account2'].join('\n'), description: 'A choice param'),
string(name: 'PARAM', defaultValue: 'something', description: 'A string param'),
booleanParam(defaultValue: false, name: 'EXECUTE_TESTS', description: 'Checkbox'),
]
properties([
buildDiscarder(logRotator(numToKeepStr: '20')),
pipelineTriggers([cron('0 18 * * *')]), // 4am AEST/5am AEDT
disableConcurrentBuilds(),
parameters(paramList)
])
ansiColor {
timestamps {
node {
try {
causes = currentBuild.rawBuild.getCauses().collect { it.getClass().getCanonicalName().tokenize('.').last() }
if (causes.contains('TimerTriggerCause') {
setBooleanParam("EXECUTE_TESTS", true)
}
stage('Do the thing') {
// Normal do the things like build
}
stage('Execute tests if selected') {
if (params.EXECUTE_TESTS == true) {
// execute tests
} else {
echo('Tests not executed (Option was not selected/False)')
}
}
} catch (err) {
throw err
} finally {
deleteDir()
}
}
}
}
/**
* Change boolean param value during build
*
* @param paramName new or existing param name
* @param paramValue param value
* @return nothing
*/
Void setBooleanParam(String paramName, Boolean paramValue) {
List<ParameterValue> newParams = new ArrayList<>();
newParams.add(new BooleanParameterValue(paramName, paramValue))
try {
$build().addOrReplaceAction($build().getAction(ParametersAction.class).createUpdated(newParams))
} catch (err) {
$build().addOrReplaceAction(new ParametersAction(newParams))
}
}
请允许我提出一个更简单的方法。这是用于声明性管道。
我建议将测试(与应用程序代码一起视为第一个 class 代码)和应用程序源代码保存在同一个存储库中。
当 Jenkins 从您的 SCM 检出时,将它们放在一个存储库中将允许您在测试套件通过时应用标记(标签)。标签是您最好的朋友,应尽可能在成功时应用。不幸的是,在撰写本文时,多 SCM 结帐似乎不支持标签的应用。
我目前有一个由 5 名开发人员组成的团队,目前正在使用多分支管道来处理他们生成的所有功能分支。我们还有一个 'master' 和 'integration' 分支。 Master 用于干净的版本。集成是我的重点分支。
在声明式管道中进行调度非常简单:
triggers {
cron('0 22 * * *')
}
pollSCM 对于更复杂的 crontab 似乎不能可靠地工作。
您可能想考虑将条件性引入声明性管道的一种方法是通过 branchname。
success {
script {
if( "${env.BRANCH_NAME}" == "integration" ) {
//Create Package
//Upload to Artifactory
//Apply tag to Git
}
}
}
上例中的特性分支只是执行单元测试并向开发人员提供反馈。只有集成分支在成功时额外生成一个工件(用于以后的测试阶段)并标记存储库。
如果您不希望基于分支的分叉行为,我建议您在 Jenkins 中定义 2 个不同的作业(管道):一个到 运行 开发人员在白天的每次提交,一个是计划每晚 运行 执行您的长 运行ning 测试。
这就是我对单元测试和系统测试所做的。
单元测试作业是一个多分支管道,运行 用于企业 GitHub 存储库中的每个分支。每分钟轮询一次更改,仅 Integration 分支创建工件和标记。单元测试需要 10 分钟 运行.
系统测试作业是一个简单的管道,计划每晚 运行 执行,需要一个小时左右的时间来执行。
这不能很好地映射到多分支管道。我见过依赖于分支的阶段,但不是依赖于参数的阶段 - 它也会每天破坏阶段视图。
我建议编写两个单独的 Jenkins 文件,例如一个名为 Jenkinsfile
,第二个可能为 Jenkinsnightlyfile
。
然后你可以在同一个存储库上使用不同的 jenkinsfile 名称创建两个多分支管道项目。
将您的常规阶段放在第一个阶段,将所有测试放在另一个阶段(为了清楚起见,您也可以将此处的工作分成多个阶段),确保让另一个阶段使用适当的触发器,例如詹金斯管道:
properties([
pipelineTriggers([cron('0 0 * * *')])
])
或声明式管道:
triggers {
cron('0 0 * * *')
}
我们在 Jenkins 上有 2 个 FreeStyle 项目:
一个生成构建(每日构建+手动构建),另一个执行测试。
我们正在转向 jenkins 上的多分支管道,所以我的理解是每个存储库有一个项目,我们应该使用选项来实现不同的行为。
所以我可以创建参数,以指示我们是否要 运行 测试,如果我们要构建设置,那部分我可以接受。
我的问题是我需要默认情况下不执行测试(因为生成它们需要很多时间,而且我不希望开发人员错误地让 "Execute tests"选项已选中。
而且我需要在夜间执行每日构建时选中此选项。
所以 2 个问题:
- 如何安排?
- 如何提供用于此计划的参数值?
您可以创建一个单独的多分支作业,它将 运行 按计划触发您的主要作业,覆盖所有必要的参数。 它看起来像这样
pipeline {
agent any
triggers {
pollSCM('0 0 * * *')
}
stages {
stage('Triggering the main job') {
steps {
build job: "main/${BRANCH_NAME.replace('/', '%2F')}",
parameters: [string(name: 'RUN_TESTS', value: 'true')]
}
}
}
}
您应该将此文件与您的主 Jenkinsfile
放在存储库中,并配置一个单独的多分支管道作业来使用此文件。
要在同一份工作中保持这一点,需要一些 groovy 编码。由于您使用的是 MultiBranch 管道,因此这一切都可以存在于您的 Jenkinsfile
首先,按照 Vitalii 提到的那样设置您的 cron,这将按计划启动工作。
properties([
pipelineTriggers([cron('0 0 * * *')])
])
接下来,当这个作业被调度触发时,我们要调整它的参数运行。所以首先我们需要检查导致构建的原因。这可能需要安全脚本批准。
List causes = currentBuild.rawBuild.getCauses().collect { it.getClass().getCanonicalName().tokenize('.').last() }
如果其中包含 'TimerTriggerCause'
那么我们要更新参数。
if (causes.contains('TimerTriggerCause') {
setBooleanParam("EXECUTE_TESTS", true)
}
我们为此在共享库中编写了一个函数,如果您愿意,可以将其放在同一个 Jenkinsfile 中(在管道逻辑之外的底部):
/**
* Change boolean param value during build
*
* @param paramName new or existing param name
* @param paramValue param value
* @return nothing
*/
Void setBooleanParam(String paramName, Boolean paramValue) {
List<ParameterValue> newParams = new ArrayList<>();
newParams.add(new BooleanParameterValue(paramName, paramValue))
try {
$build().addOrReplaceAction($build().getAction(ParametersAction.class).createUpdated(newParams))
} catch (err) {
$build().addOrReplaceAction(new ParametersAction(newParams))
}
}
并让工作照常进行。当开始评估 params.EXECUTE_TESTS 时,这将是 true(而不是默认的 false)。
注意:可能需要为值导入模型
import hudson.model.BooleanParameterValue
将所有内容放在一起(只是将各个部分快速拼凑起来以获得整体图片),您的 jenkinsfile 最终会像这样
#!groovy
import hudson.model.BooleanParameterValue
List paramsList = [
choice(name: 'ACCOUNT_NAME', choices: ['account1', 'account2'].join('\n'), description: 'A choice param'),
string(name: 'PARAM', defaultValue: 'something', description: 'A string param'),
booleanParam(defaultValue: false, name: 'EXECUTE_TESTS', description: 'Checkbox'),
]
properties([
buildDiscarder(logRotator(numToKeepStr: '20')),
pipelineTriggers([cron('0 18 * * *')]), // 4am AEST/5am AEDT
disableConcurrentBuilds(),
parameters(paramList)
])
ansiColor {
timestamps {
node {
try {
causes = currentBuild.rawBuild.getCauses().collect { it.getClass().getCanonicalName().tokenize('.').last() }
if (causes.contains('TimerTriggerCause') {
setBooleanParam("EXECUTE_TESTS", true)
}
stage('Do the thing') {
// Normal do the things like build
}
stage('Execute tests if selected') {
if (params.EXECUTE_TESTS == true) {
// execute tests
} else {
echo('Tests not executed (Option was not selected/False)')
}
}
} catch (err) {
throw err
} finally {
deleteDir()
}
}
}
}
/**
* Change boolean param value during build
*
* @param paramName new or existing param name
* @param paramValue param value
* @return nothing
*/
Void setBooleanParam(String paramName, Boolean paramValue) {
List<ParameterValue> newParams = new ArrayList<>();
newParams.add(new BooleanParameterValue(paramName, paramValue))
try {
$build().addOrReplaceAction($build().getAction(ParametersAction.class).createUpdated(newParams))
} catch (err) {
$build().addOrReplaceAction(new ParametersAction(newParams))
}
}
请允许我提出一个更简单的方法。这是用于声明性管道。
我建议将测试(与应用程序代码一起视为第一个 class 代码)和应用程序源代码保存在同一个存储库中。
当 Jenkins 从您的 SCM 检出时,将它们放在一个存储库中将允许您在测试套件通过时应用标记(标签)。标签是您最好的朋友,应尽可能在成功时应用。不幸的是,在撰写本文时,多 SCM 结帐似乎不支持标签的应用。
我目前有一个由 5 名开发人员组成的团队,目前正在使用多分支管道来处理他们生成的所有功能分支。我们还有一个 'master' 和 'integration' 分支。 Master 用于干净的版本。集成是我的重点分支。
在声明式管道中进行调度非常简单:
triggers {
cron('0 22 * * *')
}
pollSCM 对于更复杂的 crontab 似乎不能可靠地工作。
您可能想考虑将条件性引入声明性管道的一种方法是通过 branchname。
success {
script {
if( "${env.BRANCH_NAME}" == "integration" ) {
//Create Package
//Upload to Artifactory
//Apply tag to Git
}
}
}
上例中的特性分支只是执行单元测试并向开发人员提供反馈。只有集成分支在成功时额外生成一个工件(用于以后的测试阶段)并标记存储库。
如果您不希望基于分支的分叉行为,我建议您在 Jenkins 中定义 2 个不同的作业(管道):一个到 运行 开发人员在白天的每次提交,一个是计划每晚 运行 执行您的长 运行ning 测试。
这就是我对单元测试和系统测试所做的。
单元测试作业是一个多分支管道,运行 用于企业 GitHub 存储库中的每个分支。每分钟轮询一次更改,仅 Integration 分支创建工件和标记。单元测试需要 10 分钟 运行.
系统测试作业是一个简单的管道,计划每晚 运行 执行,需要一个小时左右的时间来执行。
这不能很好地映射到多分支管道。我见过依赖于分支的阶段,但不是依赖于参数的阶段 - 它也会每天破坏阶段视图。
我建议编写两个单独的 Jenkins 文件,例如一个名为 Jenkinsfile
,第二个可能为 Jenkinsnightlyfile
。
然后你可以在同一个存储库上使用不同的 jenkinsfile 名称创建两个多分支管道项目。
将您的常规阶段放在第一个阶段,将所有测试放在另一个阶段(为了清楚起见,您也可以将此处的工作分成多个阶段),确保让另一个阶段使用适当的触发器,例如詹金斯管道:
properties([
pipelineTriggers([cron('0 0 * * *')])
])
或声明式管道:
triggers {
cron('0 0 * * *')
}