Skip to content

Instantly share code, notes, and snippets.

@talenguyen
Last active February 13, 2020 04:34
Show Gist options
  • Save talenguyen/fd308b043632ead21faec9f34328274b to your computer and use it in GitHub Desktop.
Save talenguyen/fd308b043632ead21faec9f34328274b to your computer and use it in GitHub Desktop.
Jenkins cleanup
import com.cloudbees.hudson.plugins.folder.AbstractFolder
import hudson.model.AbstractItem
import groovy.transform.Field
def jobName = "Android-Verify" // jobName can be set to a Job or a Folder. If a folder, it will clean all jobs in that folder
//jobName should be full job name from root if mutliple levels down(for example "Folder1/Folder2/Job")
def resetBuildNumber = false // If this is true, the build number will be set back to 1
@Field def dryRun = false // If this is true, the job will run without deletion.
@Field def cleanedJobsTotal = 0
@Field def keepDays = 0 // Days to keep.
removeBuilds(Jenkins.instance.getItemByFullName(jobName), resetBuildNumber)
def removeBuilds(job, resetBuildNumber) {
println "removeBuilds => ${job}"
def count
def now = new Date()
if (job instanceof AbstractFolder) {
cleanedJobsLimit = 10 //Maximum number of jobs to clean in one run, useful for large systems or slow disks
for (subJob in job.getItems()) {
if(cleanedJobsTotal >= cleanedJobsLimit){
println "The cleaned jobs limit of " + cleanedJobsTotal + " has been reached. Exiting..."
return
}
else{
removeBuilds(subJob, resetBuildNumber)
}
}
} else if (job instanceof Job) {
count = 0
buildsDeleted = false
def builds
if (job.isBuildable()) { // If PR is merged or closed then it is not buildable. We can safety delete all of its builds, otherwise we keep the last build.
builds = job.getBuilds().drop(1)
} else {
builds = job.getBuilds()
}
builds.each {
println ":: Process " + it
def duration = groovy.time.TimeCategory.minus(
now,
it.getTimestamp().getTime()
)
println "Build " + duration.days
if(job.isBuildable() && duration.days < keepDays){
println "Ignore build that is scheduled within $keepDays days: " + it
}
else{
println "Delete out date build: " + it
if (dryRun) {
println "Dry run mode => delete ${it} will be not perform"
} else {
it.delete()
}
}
}
if (job.getBuilds().isEmpty()) {
println "Job " + job.name + " is empty and will be deleted"
try {
job.delete()
} catch (e) {
}
buildsDeleted = true
}
if(buildsDeleted){
println "Job " + job.name + " cleaned successfully.\n"
cleanedJobsTotal++
}
if (resetBuildNumber) {
job.nextBuildNumber = 1
job.save()
}
} else {
//Do nothing, next job
//throw new RuntimeException("Unsupported job type ${job.getClass().getName()}!")
}
}
// NOTES:
// dryRun: to only list the jobs which would be changed
// daysToKeep: If not -1, history is only kept up to this days.
// numToKeep: If not -1, only this number of build logs are kept.
// artifactDaysToKeep: If not -1 nor null, artifacts are only kept up to this days.
// artifactNumToKeep: If not -1 nor null, only this number of builds have their artifacts kept.
import jenkins.model.Jenkins
def dryRun = "true";
def daysToKeep = 7;
def numToKeep = 5;
def artifactDaysToKeep = -1;
def artifactNumToKeep = -1;
Jenkins.instanceOrNull.allItems(hudson.model.Job).each { job ->
if (job.isBuildable() && job.supportsLogRotator() && job.getProperty(jenkins.model.BuildDiscarderProperty) == null) {
println "Processing \"${job.fullDisplayName}\""
if (!"true".equals(dryRun)) {
// adding a property implicitly saves so no explicit one
try {
job.setBuildDiscarder(new hudson.tasks.LogRotator ( daysToKeep, numToKeep, artifactDaysToKeep, artifactNumToKeep))
println "${job.fullName} is updated"
} catch (Exception e) {
// Some implementation like for example the hudson.matrix.MatrixConfiguration supports a LogRotator but not setting it
println "[WARNING] Failed to update ${job.fullName} of type ${job.class} : ${e}"
}
}
}
}
return;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment