我正在试验Jenkins管道和里程碑,并且无法弄清楚为什么Jenkins在新版本越过里程碑时没有取消之前的版本。
示例Jenkinsfile
pipeline {
agent any
parameters {
booleanParam(defaultValue: true, description: '', name: 'userFlag')
}
stages {
stage("foo") {
steps {
milestone(ordinal: 1, label: "BUILD_START_MILESTONE")
sh 'sleep 1000'
}
}
}
}
两次触发此管道不会取消第一个作业
答案 0 :(得分:7)
试试这个:
/* This method should be added to your Jenkinsfile and called at the very beginning of the build*/
@NonCPS
def cancelPreviousBuilds() {
def jobName = env.JOB_NAME
def buildNumber = env.BUILD_NUMBER.toInteger()
/* Get job name */
def currentJob = Jenkins.instance.getItemByFullName(jobName)
/* Iterating over the builds for specific job */
for (def build : currentJob.builds) {
/* If there is a build that is currently running and it's not current build */
if (build.isBuilding() && build.number.toInteger() != buildNumber) {
/* Than stopping it */
build.doStop()
}
}
}
答案 1 :(得分:5)
我不认为这种行为是“如果我是一个越过这个里程碑的新版本,那么所有越过这个里程碑的旧版本将被取消”
里程碑步骤的实际行为是,当最近的管道首先穿过它时,它会阻止旧管道越过该里程碑。
答案 2 :(得分:4)
根据milestone plugin,我对document有一个简单的解决方法:
- 构建按顺序传递里程碑(将内部版本号作为分类字段)。
- 如果较新的版本已通过里程碑,则较旧的版本将不会继续(它们将中止)。
- 当某个版本通过某个里程碑时,任何通过先前里程碑但未通过该里程碑的较早版本都将中止。
- 一旦构建通过里程碑,它将永远不会被尚未通过里程碑的较新构建中止。
您可以尝试以下操作:
pipeline {
agent any
stages {
stage('Stop Old Build') {
steps {
milestone label: '', ordinal: Integer.parseInt(env.BUILD_ID) - 1
milestone label: '', ordinal: Integer.parseInt(env.BUILD_ID)
}
}
}
}
您可以将其放在任何管道的开头。
假设您刚刚开始一个新的构建,即#5。第一个里程碑将用于传递#4的第二个里程碑,第二个里程碑(第5个里程碑)将终止#4的进程(如果当前正在运行)。
答案 3 :(得分:0)
根据https://jenkins.io/blog/2016/10/16/stage-lock-milestone/,一段'里程碑()'对我来说可以杀死以前的工作,而管道开始时间很短,
stage('Build') {
// The first milestone step starts tracking concurrent build order
milestone()
node {
echo "Building"
}}
// The Deploy stage does not limit concurrency but requires manual input
// from a user. Several builds might reach this step waiting for input.
// When a user promotes a specific build all preceding builds are aborted,
// ensuring that the latest code is always deployed.
stage('Deploy') {
timeout(time: 60, unit: 'SECONDS') {input "Deploy?"}
milestone()
node {
echo "Deploying"
}
}
最后一个里程碑有助于杀死以前的版本,如果达到,请点击上面的案例中的部署按钮。或者针对以下情况发布的锁定资源
// This locked resource contains both Test stages as a single concurrency Unit.
// Only 1 concurrent build is allowed to utilize the test resources at a time.
// Newer builds are pulled off the queue first. When a build reaches the
// milestone at the end of the lock, all jobs started prior to the current
// build that are still waiting for the lock will be aborted
lock(resource: 'myResource', inversePrecedence: true){
node('test') {
stage('Unit Tests') {
echo "Unit Tests"
}
stage('System Tests') {
echo "System Tests"
}
}
milestone()
}
答案 4 :(得分:0)
以@ D.W。的答案为基础,我发现了一个有效的简单模式。它似乎适合D.W.的项目符号3(这是官方文档):When a build passes a milestone, Jenkins aborts older builds that passed the previous milestone but not this one.
添加一个较早的里程碑,使所有事物都可以通过,然后再等待将要发生的事情,就可以按照您认为的那样工作。就我而言:
steps {
milestone 1
input 'ok'
milestone 2
}
以此创建两个活动的内部版本,仅批准第二个。您会看到第一个自动取消,因为内部版本2首先通过了milestone 2
。
尝试取出milestone 1
,当构建2通过milestone 2
时,您会看到构建1不会不被取消。
添加早期里程碑即可满足要求。似乎某个版本必须通过任何里程碑,然后新版本通过的将来里程碑将导致该取消。
答案 5 :(得分:-2)
我认为这是正常行为。 如果您想要只运行作业,可以添加
pipeline {
agent { label 'xxx' }
options {
disableConcurrentBuilds()
}
如果要杀死当前作业并触发新作业,可以在构建中添加一些groovy来实现。