不要删除标记为“永久保留此构建”的Jenkins构建 - 用Groovy脚本删除Jenkins构建

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个构建,即 build#1到 build#15,您希望删除除 build#13 以外的所有构建,则此脚本将删除构建(build#1-12和14-15 - 即使您将任何构建标记为“永久保留此构建”),并仅保留 build#13。
现在,我想要的是:
  1. what should I change in this script to not delete a build - if a build is marked in Jenkins as "Keep this build forever". I tried the script and it deleted that keep forever build too.

  2. Lets say, if I'm using "Build name setter plugin" in Jenkins, which can give me build names as what name I want i.e. instead of getting just build as build#1 or #2, or #15, I will get build as build# 2.75.0.1, 2.75.0.2, 2.75.0.3, ..... , 2.75.0.15 (as I would have set the build name/description as use some variable which contains 2.75.0 (as a release version value) and suffixed it with the actual Jenkins job's build number i.e. the last 4th digit - ex: set the name as:

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

    In this case, I'll start getting Jenkins builds as 2.75.0.1 to 2.75.0.x (where x is the last build# of that release (2.75.0)). Similarly, when I'll change the property release version to next i.e. 2.75.1 or 2.76.0, then the same Jenkins job will start giving me builds as 2.75.1.0, 2.75.1.1, ...., 2.75.1.x or 2.76.0.1, 2.76.0.2, ...., 2.76.0.x and so on. During the release version change, let say, our build will start from 1 again (as I mentioned above for 2.75.1 and 2.76.0 release versions).

    In this case, if my Jenkins job's build history (shows all builds for 2.75.0.x, 2.75.1.x and 2.76.0.x), then what change should I make in this script to include a 3rd parameter/argument. This 3rd argument will take release /version value i.e. either 2.75.0 or 2.75.1 or 2.76.0 and then this script should delete build numbers on that release only (and should NOT delete other release's builds).

3个回答

1

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

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

我认为您应该能够在每次构建中使用getName()方法来检查是否应删除给定的构建。 API JavaDoc 可能相当晦涩,因此我经常浏览 GitHub 上的代码,寻找一个类似于我所需功能的 Jenkins 插件。公共 Scriptler 存储库 也可能很有用。

我从哪里获取这个“build”(在build.isKeepLog中),谢谢。 - AKS
build = jij.getLastBuild(); 如果构建未标记为永久保留,则无论如何都返回false。 - AKS
那听起来不太对劲;我有一些使用isKeepLog()来控制构建是否永久的脚本,它们运行得很好。你能在某个地方发布完整的脚本让我看看吗? - gareth_bowles
当然。我确实尝试过包含它,将构建设置为永久保留,但是当我println build.isKeepLog()时,它返回false。请查看我的最终答案脚本,该脚本可以从给定Jenkins作业的Jenkins和Artifactory构建工件中删除特定版本/发布的内容。如果您能使该脚本不删除“永久保留”构建,那将非常棒。 - AKS
在最终脚本中,在行it.delete()之前,您必须包含if (!build.isKeepLog())的逻辑。 - AKS

1

最终答案:这包括使用Artifactory的REST API调用从Artifactory中删除构建工件。该脚本将删除给定发布/版本的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 ""

0

好的 - 我的第二个问题的解决方案在这里:我仍在努力解决第一个问题。

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 ""

enter image description here

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

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


1
此脚本可以使用Jenkins "Scriptler"插件正常运行。请参见附加图像以获取输出结果。如果您想从Jenkins作业中运行此脚本,则在Build部分下,调用Scriptler脚本,提供位置/文件名,勾选jenkins作业将使用此scriptler脚本的参数(如上所示),就这样。此Jenkins作业需要3个参数字符串格式 - jobName、releaseVersion和buildNumber。 - AKS

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接