3

我有以下 Groovy 脚本,它删除给定 Jenkins 作业的所有构建,除了用户提供的一个构建号(即想要保留)。

/*** BEGIN META {
  "name" : "Bulk Delete Builds except the given build number",
  "comment" : "For a given job and a given build number, delete all build except the user provided one.",
  "parameters" : [ 'jobName', 'buildNumber' ],
  "core": "1.409",
  "authors" : [
     { name : "Arun Sangal" }
  ]
} END META **/


// NOTE: Uncomment parameters below if not using Scriptler >= 2.0, or if you're just pasting the script in manually.
// ----- Logic in this script takes 5000 as the infinite number, decrease / increase this value from your own experience.
// The name of the job.
//def jobName = "some-job"

// The range of build numbers to delete.
//def buildNumber = "5"

def lastBuildNumber = buildNumber.toInteger() - 1;
def nextBuildNumber = buildNumber.toInteger() + 1;


import jenkins.model.*;
import hudson.model.Fingerprint.RangeSet;

def jij = jenkins.model.Jenkins.instance.getItem(jobName);

println("Keeping Job_Name: ${jobName} and build Number: ${buildNumber}");
println ""

def setBuildRange = "1-${lastBuildNumber}"
def range = RangeSet.fromString(setBuildRange, true);
jij.getBuilds(range).each { it.delete() }
println("Builds have been deleted - Range: " + setBuildRange)

setBuildRange = "${nextBuildNumber}-5000"
range = RangeSet.fromString(setBuildRange, true);
jij.getBuilds(range).each { it.delete() }
println("Builds have been deleted - Range: " + setBuildRange)

这适用于任何 Jenkins 工作。例如:如果您的 Jenkins 作业名称是“TestJob”并且您有 15 个构建,即构建#1 在 Jenkins 中构建 15,并且您想要删除所有构建但保留构建#13,那么此脚本将删除构建(构建#1 -12 和 14-15 - 即使您将任何构建标记为“永远保留此构建”)并且只保留构建#13。


现在,我想要的是:

  1. 我应该在此脚本中更改什么以不删除构建 - 如果构建在 Jenkins 中标记为“永久保留此构建”。我尝试了脚本,它也删除了保持永远构建的内容。

  2. 可以说,如果我在 Jenkins 中使用“构建名称设置器插件”,它可以给我构建名称作为我想要的名称,而不是仅仅构建为 build#1 或 #2 或 #15,我将得到 build作为 build# 2.75.0.1, 2.75.0.2, 2.75.0.3, ..... , 2.75.0.15 (因为我会将构建名称/描述设置为使用一些包含 2.75.0 的变量(作为发布版本值) 并以实际 Jenkins 作业的内部版本号作为后缀,即最后 4 位数字 - 例如:将名称设置为:

    ${ENV,var="somepropertyvariable"}.${BUILD_NUMBER}
    

    在这种情况下,我将开始将 Jenkins 构建为 2.75.0.1 到 2.75.0.x(其中 x 是该版本 (2.75.0) 的最后一个构建#)。同样,当我将属性发布版本更改为下一个版本,即 2.75.1 或 2.76.0 时,相同的 Jenkins 工作将开始为我提供 2.75.1.0、2.75.1.1、......、2.75.1 的构建版本。 x 或 2.76.0.1、2.76.0.2、.....、2.76.0.x 等等。在发布版本更改期间,假设我们的构建将再次从 1 开始(正如我在上面提到的 2.75.1 和 2.76.0 发布版本)。

    在这种情况下,如果我的 Jenkins 作业的构建历史记录(显示 2.75.0.x、2.75.1.x 和 2.76.0.x 的所有构建),那么我应该在此脚本中进行哪些更改以包含第三个参数/参数. 这第三个参数将采用版本/版本值,即 2.75.0 或 2.75.1 或 2.76.0,然后此脚本应仅删除该版本上的构建号(并且不应删除其他版本的构建)。

4

3 回答 3

1

如果要测试构建是否已标记为永久,请使用

if (!build.isKeepLog()) {
    // Build can be deleted
} else {
    // Build is marked permanent
}

我认为您应该能够在每个构建上使用getName() 方法来检查是否应该删除给定的构建。API JavaDoc 可能相当晦涩难懂,所以我经常在GitHub 上查看 Jenkins 插件的代码,该插件的功能与我需要的类似。公共 Scriptler 存储库也很有用。

于 2013-09-23T22:13:24.590 回答
1

最终答案:这包括从 Artifactory 中删除构建工件以及使用 Artifactor 的 REST API 调用。此脚本将删除给定版本/版本的 Jenkins/Artifactory 构建/工件(有时随着时间的推移 - 给定的 Jenkins 作业可以创建多个版本/版本构建,例如:2.75.0.1、2.75.0.2、2.75.0.3、。 ...,2.75.0.54, 2.76.0.1, 2.76.0.2, ..., 2.76.0.16, 2.76.1.1, 2.76.1.2, ...., 2.76.1.5)。在这种情况下,对于该作业的每个新版本,我们都会从 1 开始构建#。如果您必须删除除一个/甚至全部之外的所有构建(根据您自己的需要稍微更改脚本)并且不要更改较旧/其他版本的构建,请使用以下脚本。

Scriptler 目录链接http ://scriptlerweb.appspot.com/script/show/103001

享受!

/*** BEGIN META {
  "name" : "Bulk Delete Builds except the given build number",
  "comment" : "For a given job and a given build numnber, delete all builds of a given release version (M.m.interim) only and except the user provided one. Sometimes a Jenkins job use Build Name setter plugin and same job generates 2.75.0.1 and 2.76.0.43",
  "parameters" : [ 'jobName', 'releaseVersion', 'buildNumber' ],
  "core": "1.409",
  "authors" : [
     { name : "Arun Sangal - Maddys Version" }
  ]
} END META **/

import groovy.json.*
import jenkins.model.*;
import hudson.model.Fingerprint.RangeSet;
import hudson.model.Job;
import hudson.model.Fingerprint;

//these should be passed in as arguments to the script
if(!artifactoryURL) throw new Exception("artifactoryURL not provided")
if(!artifactoryUser) throw new Exception("artifactoryUser not provided")
if(!artifactoryPassword) throw new Exception("artifactoryPassword not provided")
def authString = "${artifactoryUser}:${artifactoryPassword}".getBytes().encodeBase64().toString()
def artifactorySettings = [artifactoryURL: artifactoryURL, authString: authString]

if(!jobName) throw new Exception("jobName not provided")
if(!buildNumber) throw new Exception("buildNumber not provided")

def lastBuildNumber = buildNumber.toInteger() - 1;
def nextBuildNumber = buildNumber.toInteger() + 1;

def jij = jenkins.model.Jenkins.instance.getItem(jobName);

def promotedBuildRange = new Fingerprint.RangeSet()
promotedBuildRange.add(buildNumber.toInteger())
def promoteBuildsList = jij.getBuilds(promotedBuildRange)
assert promoteBuildsList.size() == 1
def promotedBuild = promoteBuildsList[0]
// The release / version of a Jenkins job - i.e. in case you use "Build name" setter plugin in Jenkins for getting builds like 2.75.0.1, 2.75.0.2, .. , 2.75.0.15 etc.
// and over the time, change the release/version value (2.75.0) to a newer value i.e. 2.75.1 or 2.76.0 and start builds of this new release/version from #1 onwards.
def releaseVersion = promotedBuild.getDisplayName().split("\\.")[0..2].join(".")

println ""
println("- Jenkins Job_Name: ${jobName} -- Version: ${releaseVersion} -- Keep Build Number: ${buildNumber}");
println ""

/** delete the indicated build and its artifacts from artifactory */
def deleteBuildFromArtifactory(String jobName, int deleteBuildNumber, Map<String, String> artifactorySettings){
    println "     ## Deleting >>>>>>>>>: - ${jobName}:${deleteBuildNumber} from artifactory"
                                def artifactSearchUri = "api/build/${jobName}?buildNumbers=${deleteBuildNumber}&artifacts=1"
                                def conn = "${artifactorySettings['artifactoryURL']}/${artifactSearchUri}".toURL().openConnection()
                                conn.setRequestProperty("Authorization", "Basic " + artifactorySettings['authString']);
                                conn.setRequestMethod("DELETE")
    if( conn.responseCode != 200 ) {
        println "Failed to delete the build artifacts from artifactory for ${jobName}/${deleteBuildNumber}: ${conn.responseCode} - ${conn.responseMessage}"
    }
}

/** delete all builds in the indicated range that match the releaseVersion */
def deleteBuildsInRange(String buildRange, String releaseVersion, Job theJob, Map<String, String> artifactorySettings){
    def range = RangeSet.fromString(buildRange, true);
    theJob.getBuilds(range).each {
        if ( it.getDisplayName().find(/${releaseVersion}.*/)) {
            println "     ## Deleting >>>>>>>>>: " + it.getDisplayName();
            deleteBuildFromArtifactory(theJob.name, it.number, artifactorySettings)
            it.delete();
        }
    }
}

//delete all the matching builds before the promoted build number
deleteBuildsInRange("1-${lastBuildNumber}", releaseVersion, jij, artifactorySettings)

//delete all the matching builds after the promoted build number
deleteBuildsInRange("${nextBuildNumber}-${jij.nextBuildNumber}", releaseVersion, jij, artifactorySettings)

println ""
println("- Builds have been successfully deleted for the above mentioned release: ${releaseVersion}")
println ""
于 2013-09-24T21:36:46.037 回答
0

好的 - 我的问题 2 的解决方案在这里:我仍在努力解决问题 1。

http://scriptlerweb.appspot.com/script/show/102001

bulkDeleteJenkinsBuildsExceptOne_OfAGivenRelease.groovy

/*** BEGIN META {
  "name" : "Bulk Delete Builds except the given build number",
  "comment" : "For a given job and a given build numnber, delete all builds of a given release version (M.m.interim) only and except the user provided one. Sometimes a Jenkins job use Build Name setter plugin and same job generates 2.75.0.1 and 2.76.0.43",
  "parameters" : [ 'jobName', 'releaseVersion', 'buildNumber' ],
  "core": "1.409",
  "authors" : [
     { name : "Arun Sangal" }
  ]
} END META **/


// NOTE: Uncomment parameters below if not using Scriptler >= 2.0, or if you're just pasting the script in manually.
// ----- Logic in this script takes 5000 as the infinite number, decrease / increase this value from your own experience.
// The name of the job.
//def jobName = "some-job"

// The release / version of a Jenkins job - i.e. in case you use "Build name" setter plugin in Jenkins for getting builds like 2.75.0.1, 2.75.0.2, .. , 2.75.0.15 etc.
// and over the time, change the release/version value (2.75.0) to a newer value i.e. 2.75.1 or 2.76.0 and start builds of this new release/version from #1 onwards.
//def releaseVersion = "2.75.0"

// The range of build numbers to delete.
//def buildNumber = "5"

def lastBuildNumber = buildNumber.toInteger() - 1;
def nextBuildNumber = buildNumber.toInteger() + 1;


import jenkins.model.*;
import hudson.model.Fingerprint.RangeSet;

def jij = jenkins.model.Jenkins.instance.getItem(jobName);
//def build = jij.getLastBuild();

println ""
println("- Jenkins Job_Name: ${jobName} -- Version: ${releaseVersion} -- Keep Build Number: ${buildNumber}");
println ""
println "  -- Range before given build number: ${buildNumber}"
println ""

def setBuildRange = "1-${lastBuildNumber}"
def range = RangeSet.fromString(setBuildRange, true);
jij.getBuilds(range).each {
  if ( it.getDisplayName().find(/${releaseVersion}.*/)) {
     println "     ## Deleting >>>>>>>>>: " + it.getDisplayName();

     // Trying to find - how to NOT delete a build in Jenkins if it's marked as "keep this build forever". If someone has an idea, please update this script with a newer version in GitHub.
     //if ( !build.isKeepLog()) {
          it.delete();
     //} else {
     //   println "build -- can't be deleted as :" + build.getWhyKeepLog();
     //}
  }
}



println ""
println "  -- Range after  given build number: ${buildNumber}"
println ""
setBuildRange = "${nextBuildNumber}-5000"
range = RangeSet.fromString(setBuildRange, true);
jij.getBuilds(range).each {
  if ( it.getDisplayName().find(/${releaseVersion}.*/)) {
     println "     ## Deleting >>>>>>>>>: " + it.getDisplayName();
     it.delete();
  }
}

println ""
println("- Builds have been successfully deleted for the above mentioned release: ${releaseVersion}")
println ""

在此处输入图像描述

也可以通过 Jenkins 作业调用此脚本(需要 3 个参数,如 scriptler 脚本中所述) - 或者也可以从浏览器调用它:使用以下链接:

http://YourJenkinsServerName:PORT/job/Some_Jenkins_Job_That_You_Will_Create/buildWithParameters?jobName=Test_AppSvc&releaseVersion=2.75.0&buildNumber=15

于 2013-09-24T04:14:03.527 回答