Jenkins管道里程碑没有取消之前正在进行的构建

时间:2017-09-04 17:07:52

标签: jenkins jenkins-pipeline

我正在试验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'
            }
        }
    } 
}

两次触发此管道不会取消第一个作业

6 个答案:

答案 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来实现。