├── LICENSE.txt ├── README.md └── src └── main └── groovy ├── AddArtifactArchiver.groovy ├── AddArtifactoryRedeployPublisher.groovy ├── AddCopyPermission.groovy ├── AddGitSCMCredentials.groovy ├── AddScmTrigger.groovy ├── AddWebSVN2Browser.groovy ├── AddWorkspaceCleanUp.groovy ├── CleanupSlaveWorkspaces.groovy ├── CreateSonarJob.groovy ├── DisplayCronTiggersInViewDescription.groovy ├── IterateOverJobs.groovy ├── ListAllCronTriggers.groovy └── UpdateAntOpts.groovy /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2014 codecentric AG 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included 13 | in all copies or substantial portions of the Software. 14 | 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Jenkins Scripts 2 | ============== 3 | 4 | A collection of groovy scripts that can be used in the [Jenkins](http://jenkins-ci.org) 5 | console and have proven useful. 6 | -------------------------------------------------------------------------------- /src/main/groovy/AddArtifactArchiver.groovy: -------------------------------------------------------------------------------- 1 | import hudson.tasks.ArtifactArchiver 2 | 3 | /** 4 | * Adds an element archiver to the job, that archives results of the build. 5 | * It makes sense to use this in conjunction with a CopyPermission (see AddCopyPermission.groovy) 6 | * to allow other projects to copy the archived artifacts. 7 | */ 8 | def handleJob = { job -> 9 | archiver = new ArtifactArchiver( 10 | "target/jacoco.exec, target/*.jar, target/**/*.class, target/surefire-reports/*", // artifacts 11 | null, // excludes 12 | true, // latestOnly 13 | false, // allowEmptyArchive 14 | true // onlyIfSuccessful 15 | ) 16 | job.publishers.replace(archiver) 17 | } 18 | -------------------------------------------------------------------------------- /src/main/groovy/AddArtifactoryRedeployPublisher.groovy: -------------------------------------------------------------------------------- 1 | import org.jfrog.hudson.ArtifactoryRedeployPublisher 2 | import org.jfrog.hudson.ServerDetails 3 | 4 | /** 5 | * Adds a publisher that publishes build artifacts to artifactory. 6 | */ 7 | def handleJob = { job -> 8 | 9 | /* 10 | * easiest way to get the artifactoryName is to configure a ArtifactoryRedeployPublisher 11 | * manually and look it up in the xml config of the job 12 | */ 13 | server = new ServerDetails( 14 | "-1839878724@1400066745155", // String artifactoryName 15 | "http://localhost:8081/artifactory", // String artifactoryUrl 16 | "libs-release-local", // String repositoryKey 17 | "libs-snapshot-local", // String snapshotsRepositoryKey, 18 | null, // String downloadReleaseRepositoryKey 19 | null // String downloadSnapshotRepositoryKey 20 | ) 21 | 22 | artifactoryDeployer = new ArtifactoryRedeployPublisher( 23 | server, // ServerDetails details 24 | true, // boolean deployArtifacts 25 | null, // org.jfrog.hudson.util.IncludesExcludes artifactDeploymentPatterns 26 | null, // org.jfrog.hudson.util.Credentials overridingDeployerCredentials, 27 | false, // boolean includeEnvVars 28 | null, // org.jfrog.hudson.util.IncludesExcludes envVarsPatterns 29 | true, // boolean deployBuildInfo 30 | false, // boolean evenIfUnstable 31 | false, // boolean runChecks 32 | null, // String violationRecipients 33 | false, // boolean includePublishArtifacts 34 | null, // String scopes, 35 | false, // boolean disableLicenseAutoDiscovery 36 | false, // boolean discardOldBuilds 37 | false, // boolean passIdentifiedDownstream 38 | true, // boolean discardBuildArtifacts 39 | null, // String matrixParams 40 | false, // boolean enableIssueTrackerIntegration 41 | false, // boolean aggregateBuildIssues 42 | "Released", // String aggregationBuildStatus 43 | false, // boolean allowPromotionOfNonStagedBuilds 44 | false, // boolean blackDuckRunChecks 45 | null, // String blackDuckAppName 46 | null, // String blackDuckAppVersion 47 | null, // String blackDuckReportRecipients 48 | null, // String blackDuckScopes 49 | false, // boolean blackDuckIncludePublishedArtifacts 50 | true, // boolean autoCreateMissingComponentRequests, 51 | true, // boolean autoDiscardStaleComponentRequests, 52 | false // boolean filterExcludedArtifactsFromBuild 53 | ) 54 | 55 | job.publishers.replace(artifactoryDeployer) 56 | } 57 | -------------------------------------------------------------------------------- /src/main/groovy/AddCopyPermission.groovy: -------------------------------------------------------------------------------- 1 | import hudson.plugins.copyartifact.CopyArtifactPermissionProperty 2 | 3 | /** 4 | * Add a CopyArtifacts permission for all jobs that have the same name and a suffix 5 | * For example, if you have a Job called MyJob and a corresponding Maven Sonar Build 6 | * Job that's called MyJob-sonar, the sonar job will be allowed to copy artifacts. 7 | */ 8 | def handleJob = { job -> 9 | prop = new CopyArtifactPermissionProperty() 10 | prop.projectNameList.add(job.name + "*") 11 | job.addProperty(prop) 12 | } 13 | -------------------------------------------------------------------------------- /src/main/groovy/AddGitSCMCredentials.groovy: -------------------------------------------------------------------------------- 1 | import hudson.model.* 2 | import hudson.triggers.* 3 | 4 | for(item in Hudson.instance.items) { 5 | if(item.scm instanceof hudson.plugins.git.GitSCM ){ 6 | println("Project: " + item.name ) 7 | println("Credentials: " + item.scm.userRemoteConfigs[0].credentialsId) 8 | 9 | println("Set credentials") 10 | item.scm.userRemoteConfigs[0].credentialsId = "55b59e2c-8d2a-1285-85eb-d6d8b34d7399" 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /src/main/groovy/AddScmTrigger.groovy: -------------------------------------------------------------------------------- 1 | import hudson.triggers.* 2 | 3 | def handleJob = { job -> 4 | job.addTrigger(new SCMTrigger("H 23 * * 1-5")) 5 | job.save() 6 | } 7 | -------------------------------------------------------------------------------- /src/main/groovy/AddWebSVN2Browser.groovy: -------------------------------------------------------------------------------- 1 | import hudson.plugins.websvn2.* 2 | import hudson.scm.* 3 | 4 | // Add a new browser (WebSVN2 in this example) to an existing SCM-setting of a job. 5 | // For this a new SCM must be created as a copy of the old one, as the browser cannot 6 | // be set by it's own. 7 | def transform(job) { 8 | // handle branches and trunk differently: 9 | if (job.scm.locations[0].remote.contains("branches")) { 10 | matcher = (job.scm.locations[0].remote =~ /svn\/Project\/(.+)\/branches\/(.+)/) 11 | projectSvnName = matcher[0][1] 12 | branchName = matcher[0][2] 13 | url = "http://localhost/websvn/listing.php?repname=Project&path=/$projectSvnName/branches/$branchName" 14 | } else { 15 | matcher = (job.scm.locations[0].remote =~ /svn\/Project\/(.+)\/trunk/) 16 | projectSvnName = matcher[0][1] 17 | url = "http://localhost/websvn/listing.php?repname=Project&path=/$projectSvnName/trunk/" 18 | } 19 | 20 | oldScm = job.scm 21 | browser = new hudson.plugins.websvn2.WebSVN2RepositoryBrowser(new URL(url)) 22 | newScm = new SubversionSCM(Arrays.asList(oldScm.locations), oldScm.workspaceUpdater, 23 | browser, oldScm.excludedRegions, oldScm.excludedUsers, oldScm.excludedRevprop, oldScm.excludedCommitMessages, 24 | oldScm.includedRegions, oldScm.ignoreDirPropChanges, oldScm.filterChangelog, oldScm.additionalCredentials) 25 | job.scm = newScm 26 | job.save() 27 | } 28 | -------------------------------------------------------------------------------- /src/main/groovy/AddWorkspaceCleanUp.groovy: -------------------------------------------------------------------------------- 1 | import hudson.model.* 2 | import hudson.maven.* 3 | import hudson.tasks.* 4 | import hudson.plugins.ws_cleanup.* 5 | 6 | // Requires installed Workspace Cleanup Plugin 7 | // For each project 8 | for(item in Hudson.instance.items) { 9 | // For each FreeStyleProject 10 | if(item instanceof FreeStyleProject) { 11 | println("JOB : " + item.name); 12 | item.buildWrappersList.add(new PreBuildCleanup(null, false, "", "")) 13 | println(item.buildWrappers); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/groovy/CleanupSlaveWorkspaces.groovy: -------------------------------------------------------------------------------- 1 | import hudson.model.*; 2 | import hudson.util.*; 3 | import jenkins.model.*; 4 | import hudson.FilePath.FileCallable; 5 | import hudson.slaves.OfflineCause; 6 | import hudson.node_monitors.*; 7 | 8 | /** 9 | * This script can be used to cleanup the workspace directories on all connected Jenkins slaves. 10 | * All slaves with a disk usage below "thresholdInMB" will be tidied up. 11 | * Workspaces of running Jobs will be ignored. 12 | */ 13 | 14 | thresholdInMB = 1500 15 | 16 | for (node in Jenkins.instance.nodes) { 17 | 18 | computer = node.toComputer() 19 | if (computer.getChannel() == null) continue 20 | 21 | rootPath = node.getRootPath() 22 | size = DiskSpaceMonitor.DESCRIPTOR.get(computer).size 23 | slaveNodeSize = size / (1024 * 1024) as int 24 | 25 | println("slave: " + node.getDisplayName() + ", free space: " + slaveNodeSize + " MB") 26 | 27 | if (slaveNodeSize < thresholdInMB) { 28 | 29 | println("turning off slave temporarily") 30 | computer.setTemporarilyOffline(true, new hudson.slaves.OfflineCause.ByCLI("disk cleanup on slave")) 31 | 32 | for (item in Jenkins.instance.items) { 33 | jobName = item.getFullDisplayName() 34 | 35 | if (item.isBuilding()) { 36 | println(".. job " + jobName + " is currently running, skip") 37 | continue 38 | } 39 | 40 | println(".. wiping out workspace of job " + jobName) 41 | 42 | workspacePath = node.getWorkspaceFor(item) 43 | if (workspacePath == null) { 44 | println(".... could not get workspace path") 45 | continue 46 | } 47 | 48 | println(".... workspace = " + workspacePath) 49 | 50 | pathAsString = workspacePath.getRemote() 51 | if (workspacePath.exists()) { 52 | workspacePath.deleteRecursive() 53 | println(".... deleted from location " + pathAsString) 54 | } else { 55 | println(".... nothing to delete at " + pathAsString) 56 | } 57 | } 58 | 59 | println("bringing slave back online") 60 | computer.setTemporarilyOffline(false, null) 61 | 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/groovy/CreateSonarJob.groovy: -------------------------------------------------------------------------------- 1 | import jenkins.triggers.ReverseBuildTrigger 2 | import hudson.plugins.copyartifact.CopyArtifact 3 | import hudson.plugins.copyartifact.StatusBuildSelector 4 | import hudson.plugins.sonar.SonarPublisher 5 | 6 | /** 7 | * Use this after you have added the ArtifactArchiver to your build jobs. 8 | * This will create a new FreeStyleProject for the given job that execute sonar analysis. 9 | * It's good to have sonar running in it's own job, so that failures during analysis 10 | * won't mark the build as failed. This separation makes failure analysis easier. 11 | */ 12 | def handleJob = { job -> 13 | sonarJob = Jenkins.instance.createProject(FreeStyleProject.class, job.name + "-sonar") 14 | sonarJob.scm = job.scm 15 | sonarJob.addTrigger(new ReverseBuildTrigger(job.name, Result.SUCCESS)) 16 | 17 | copyArtifacts = new CopyArtifact( 18 | job.name, // String projectName 19 | null, // String parameters 20 | new StatusBuildSelector(false), // hudson.plugins.copyartifact.BuildSelector selector 21 | "target/jacoco.exec, target/**/*.class, target/surefire-reports/*", // String target - should agree with what has been archived by the ArtifactArchiver 22 | null, // String filter 23 | false, // boolean flatten 24 | false, // boolean optional 25 | false // boolean fingerprintArtifacts 26 | ) 27 | 28 | sonarJob.getBuildersList().replace(copyArtifacts) 29 | 30 | sonar = new SonarPublisher( 31 | null, // String installationName 32 | null, // String jobAdditionalProperties 33 | null // String mavenOpts 34 | ) 35 | 36 | sonarJob.addPublisher(sonar) 37 | } 38 | -------------------------------------------------------------------------------- /src/main/groovy/DisplayCronTiggersInViewDescription.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * This script gathers all cron triggers and displays them above a given view tab. 3 | * The result will look like the following. 4 | * 5 | * +------------------+----------------------+-----------------------+ 6 | * | Job Name | Next Run | Cron | 7 | * +------------------+----------------------+-----------------------+ 8 | * | Project A - CI | 07:15 - 21.8.2014 | 15 07 21 8 * | 9 | * | Project B - CI | 11:25 - 24.8.2014 | 25 11 24 8 * | 10 | * +------------------+----------------------+-----------------------+ 11 | */ 12 | 13 | import hudson.model.* 14 | import hudson.triggers.* 15 | 16 | def viewName = "Default" 17 | def viewTitle = "Build Triggers" 18 | 19 | for(view in Hudson.instance.views) { 20 | if( view.name == viewName ) { 21 | view.description = "

" + viewTitle + "

" 22 | view.description <<= "" 23 | 24 | for(item in Hudson.instance.items) { 25 | for(trigger in item.triggers.values()) { 26 | if(trigger instanceof TimerTrigger) { 27 | view.description <<= "" 28 | items = trigger.spec.split(' ') 29 | if( items.length == 5 ) { 30 | view.description <<= "" 31 | } else { 32 | view.description <<= "" 33 | } 34 | view.description <<= "" 35 | } 36 | } 37 | } 38 | 39 | view.description <<= "
Job NameNext RunCron
" + item.name + "" + items[1] +":"+ items[0] + " - " + items[2] + "." + items[3] + "." + (new Date().year + 1900) + "" + "" + trigger.spec + "
" 40 | } 41 | } -------------------------------------------------------------------------------- /src/main/groovy/IterateOverJobs.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Iterates over all items, identifing Folders and interating of the jobs inside 3 | * of the folders as well. Not that currently folder in folders are not supported 4 | */ 5 | import hudson.maven.MavenModuleSet 6 | import com.cloudbees.hudson.plugins.folder.Folder 7 | 8 | /** 9 | * All maven jobs ending with "-build" 10 | */ 11 | def relevantJobs = { job -> 12 | job instanceof MavenModuleSet && job.isBuildable() && job.name.endsWith("-build") 13 | } 14 | 15 | /** 16 | * Identify folders 17 | */ 18 | def folders = { item -> 19 | item instanceof Folder 20 | } 21 | 22 | def handleJob = { job -> 23 | // do something with the job... 24 | } 25 | 26 | Jenkins.instance.items.findAll(folders).each{ folder -> 27 | folder.items.findAll(relevantJobs).each(handleJob) 28 | } 29 | 30 | 31 | Jenkins.instance.items.findAll(relevantJobs).each(handleJob) 32 | -------------------------------------------------------------------------------- /src/main/groovy/ListAllCronTriggers.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * List all cron trigger times for all jobs 3 | */ 4 | import hudson.model.* 5 | import hudson.triggers.* 6 | 7 | for(item in Hudson.instance.items) { 8 | for(trigger in item.triggers.values()) { 9 | if(trigger instanceof TimerTrigger) { 10 | println("Trigger for Job: " + item.name) 11 | println(trigger.spec + '\n') 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/main/groovy/UpdateAntOpts.groovy: -------------------------------------------------------------------------------- 1 | import hudson.model.* 2 | import hudson.maven.* 3 | import hudson.tasks.* 4 | 5 | def newAntOptions="-Xmx1G -XX:MaxPermSize=512M" 6 | 7 | // For each project 8 | for(item in Hudson.instance.items) { 9 | // For each FreeStyleProject 10 | if(item instanceof FreeStyleProject) { 11 | println("JOB : " + item.name); 12 | // For each builder 13 | for (builder in item.builders){ 14 | println("-" + builder); 15 | if (builder instanceof Ant) { 16 | println("-- ANT BUILDER"); 17 | println("-- TARGETS: " + builder.targets); 18 | println("-- NAME: " + builder.antName); 19 | println("-- BUILDFILE: " + builder.buildFile); 20 | println("-- PROPERTIES: " + builder.@properties); 21 | println("-- ANTOPTS: " + builder.antOpts); 22 | def newBuilder = new Ant(builder.targets,builder.antName,newAntOptions,builder.buildFile,builder.@properties); 23 | item.buildersList.replace(newBuilder); 24 | } 25 | } 26 | } 27 | } 28 | --------------------------------------------------------------------------------