From 9b417890c8c6d5278da48352f7a5989432c72b81 Mon Sep 17 00:00:00 2001 From: "Minthorne, Josh" Date: Thu, 17 Sep 2015 09:15:09 -0400 Subject: [PATCH 1/8] sync with current state of AIG repo --- README.md | 7 ++++- build.gradle | 14 ++++++---- .../com/neoteric/jenkins/BranchView.groovy | 1 + .../groovy/com/neoteric/jenkins/GitApi.groovy | 1 + .../com/neoteric/jenkins/JenkinsApi.groovy | 28 +++++++++++++------ .../neoteric/jenkins/JenkinsJobManager.groovy | 10 +++++-- .../com/neoteric/jenkins/TemplateJob.groovy | 3 ++ 7 files changed, 45 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index e7bc451..c772eb3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ # Jenkins Build Per Git Flow Branch This script will allow you to keep your Jenkins jobs in sync with your Git repository (following Git Flow branching model). +**This repository was forked from https://github.com/neoteric-eu/jenkins-build-per-gitflow-branch** +*the build.gradle file was updated to contain the newest dependency versions along with the repository* + + ### Genesis This is a variation of a solution we found. Hence, the credit for the idea and initial implementation goes to Entagen and theirs [Jenkins Build Per Branch]. They explained it nicely, so it's advisable to take a look to their page. As stated, Entagen's version would suit better for a [GitHub flow] convention. Our need is to have three different templates for each of the Git Flow branches: features, releases, hotfixes and to sync them all in one 'scanning session' (single Jenkins sync job execution). I found it impossible using the original solution. So, we reused the concept of Entagen's script, but replaced the synchronization logic with what suited us better. @@ -47,7 +51,8 @@ The whole idea is to have a single Jenkins job which executes periodically, chec ##### 2. Add script parameters (provided in Switches box) - `-DjenkinsUrl` URL of the Jenkins.You should be able to append api/json to the URL to get JSON feed. - `-DjenkinsUser` Jenkins HTTP basic authorization user name. (optional) -- `-DjenkinsPasswrd` Jenkins HTTP basic authorization password. (optional) +- `-DjenkinsPassword` Jenkins HTTP basic authorization password. (optional) +*The original Usage has this variable as jenkinsPasswrd without the 'o'. This is why proofreading is so important" - `-DgitUrl` URL of the Git repository to make the synchronization against. - `-DdryRun` Pass this flag with any value and it won't make any changes to Jenkins (preview mode). It is recommended to use dry run until everything is set up correctly. (optional) - `-DtemplateJobPrefix` Prefix name of template jobs to use diff --git a/build.gradle b/build.gradle index 556eecc..9c1482e 100644 --- a/build.gradle +++ b/build.gradle @@ -2,17 +2,19 @@ apply plugin: 'groovy' apply plugin: 'eclipse' repositories { - mavenCentral() + maven { + url "http://dlccasdigdsu08:8081/nexus/content/groups/aig_public/" + } } dependencies { - compile 'org.codehaus.groovy:groovy-all:2.3.3' - compile 'org.apache.ivy:ivy:2.2.0' + compile 'org.codehaus.groovy:groovy-all:2.4.4' + compile 'org.apache.ivy:ivy:2.4.0' compile 'commons-cli:commons-cli:1.2' // should be part of groovy, but not available when running for some reason - compile 'org.jooq:joox:1.2.0' + compile 'org.jooq:joox:1.2.0' testCompile 'junit:junit:4.11' testCompile 'org.assertj:assertj-core:1.7.0' - testCompile 'com.github.stefanbirkner:system-rules:1.7.0' + testCompile 'com.github.stefanbirkner:system-rules:1.7.0' compile 'org.codehaus.groovy.modules.http-builder:http-builder:0.7.1' } @@ -36,5 +38,5 @@ task syncWithRepo(dependsOn: 'classes', type: JavaExec) { } task wrapper(type: Wrapper) { - gradleVersion = '1.12' + gradleVersion = '2.6' } \ No newline at end of file diff --git a/src/main/groovy/com/neoteric/jenkins/BranchView.groovy b/src/main/groovy/com/neoteric/jenkins/BranchView.groovy index 5582b13..5fb6ce6 100644 --- a/src/main/groovy/com/neoteric/jenkins/BranchView.groovy +++ b/src/main/groovy/com/neoteric/jenkins/BranchView.groovy @@ -9,6 +9,7 @@ class BranchView { } public String getSafeBranchName() { + println "---->geting the safe branch name -------->" return branchName.replaceAll('/', '_') } diff --git a/src/main/groovy/com/neoteric/jenkins/GitApi.groovy b/src/main/groovy/com/neoteric/jenkins/GitApi.groovy index eb7d42d..777cf7a 100644 --- a/src/main/groovy/com/neoteric/jenkins/GitApi.groovy +++ b/src/main/groovy/com/neoteric/jenkins/GitApi.groovy @@ -13,6 +13,7 @@ class GitApi { eachResultLine(command) { String line -> String branchNameRegex = "^.*\trefs/heads/(.*)\$" String branchName = line.find(branchNameRegex) { full, branchName -> branchName } + println "----- getBranchNames: branchName "+branchName Boolean selected = passesFilter(branchName) println "\t" + (selected ? "* " : " ") + "$line" // lines are in the format of: \trefs/heads/BRANCH_NAME diff --git a/src/main/groovy/com/neoteric/jenkins/JenkinsApi.groovy b/src/main/groovy/com/neoteric/jenkins/JenkinsApi.groovy index 0c60b6a..86b2ea8 100644 --- a/src/main/groovy/com/neoteric/jenkins/JenkinsApi.groovy +++ b/src/main/groovy/com/neoteric/jenkins/JenkinsApi.groovy @@ -42,7 +42,7 @@ class JenkinsApi { } List getJobNames(String prefix = null) { - println "getting project names from " + jenkinsServerUrl + "api/json" + def response = get(path: 'api/json') def jobNames = response.data.jobs.name if (prefix) return jobNames.findAll { it.startsWith(prefix) } @@ -50,14 +50,16 @@ class JenkinsApi { } String getJobConfig(String jobName) { + def response = get(path: "job/${jobName}/config.xml", contentType: TEXT, headers: [Accept: 'application/xml']) + response.data.text } void cloneJobForBranch(String jobPrefix, ConcreteJob missingJob, String createJobInView, String gitUrl) { String createJobInViewPath = resolveViewPath(createJobInView) - println "-----> createInView after" + createJobInView + println "-----> createInView after: " + createJobInView String missingJobConfig = configForMissingJob(missingJob, gitUrl) TemplateJob templateJob = missingJob.templateJob @@ -83,19 +85,23 @@ class JenkinsApi { } String configForMissingJob(ConcreteJob missingJob, String gitUrl) { + TemplateJob templateJob = missingJob.templateJob String config = getJobConfig(templateJob.jobName) + return processConfig(config, missingJob.branchName, gitUrl) } public String processConfig(String entryConfig, String branchName, String gitUrl) { + def root = new XmlParser().parseText(entryConfig) + // update branch name root.scm.branches."hudson.plugins.git.BranchSpec".name[0].value = "*/$branchName" - + // update GIT url root.scm.userRemoteConfigs."hudson.plugins.git.UserRemoteConfig".url[0].value = "$gitUrl" - + //update Sonar if (root.publishers."hudson.plugins.sonar.SonarPublisher".branch[0] != null) { root.publishers."hudson.plugins.sonar.SonarPublisher".branch[0].value = "$branchName" @@ -110,14 +116,18 @@ class JenkinsApi { //check if it was the only parameter - if so, remove the enclosing tag, so the project won't be seen as build with parameters def propertiesNode = root.properties - def parameterDefinitionsProperty = propertiesNode."hudson.model.ParametersDefinitionProperty".parameterDefinitions[0] + def parameterDefinitionsProperty + //the neoteric people hard coded property names and didn't do defensive coding. This causes an NPE. tisk tisk!! + if(propertiesNode."hudson.model.ParametersDefinitionProperty".parameterDefinitions[0] !=null){ + + parameterDefinitionsProperty = propertiesNode."hudson.model.ParametersDefinitionProperty".parameterDefinitions[0] - if(!parameterDefinitionsProperty.attributes() && !parameterDefinitionsProperty.children() && !parameterDefinitionsProperty.text()) { - root.remove(propertiesNode) - new Node(root, 'properties') + if(!parameterDefinitionsProperty.attributes() && !parameterDefinitionsProperty.children() && !parameterDefinitionsProperty.text()) { + root.remove(propertiesNode) + new Node(root, 'properties') + } } - def writer = new StringWriter() XmlNodePrinter xmlPrinter = new XmlNodePrinter(new PrintWriter(writer)) xmlPrinter.setPreserveWhitespace(true) diff --git a/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy b/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy index ebe3424..e13e7a3 100644 --- a/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy +++ b/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy @@ -16,15 +16,18 @@ class JenkinsJobManager { Boolean noDelete = false Boolean startOnCreate = false - String featureSuffix = "feature-" + String developmentSuffix = "development-" + String featureSuffix = "feature/" String hotfixSuffix = "hotfix-" String releaseSuffix = "release-" + String templateDevelopmentSuffix = "development" String templateFeatureSuffix = "feature" String templateHotfixSuffix = "hotfix" String templateReleaseSuffix = "release" - def branchSuffixMatch = [(templateFeatureSuffix): featureSuffix, + def branchSuffixMatch = [(templateDevelopmentSuffix) : developmentSuffix, + (templateFeatureSuffix) : featureSuffix, (templateHotfixSuffix) : hotfixSuffix, (templateReleaseSuffix): releaseSuffix] @@ -64,7 +67,7 @@ class JenkinsJobManager { } public List findRequiredTemplateJobs(List allJobNames) { - String regex = /^($templateJobPrefix)-(.*)-($templateFeatureSuffix|$templateReleaseSuffix|$templateHotfixSuffix)$/ + String regex = /^($templateJobPrefix)-(.*)-($templateDevelopmentSuffix|$templateFeatureSuffix|$templateReleaseSuffix|$templateHotfixSuffix)$/ List templateJobs = allJobNames.findResults { String jobName -> @@ -81,6 +84,7 @@ class JenkinsJobManager { public void syncJobs(List allBranchNames, List jobNames, List templateJobs) { + def templateJobsByBranch = templateJobs.groupBy({ template -> template.templateBranchName }) List missingJobs = []; diff --git a/src/main/groovy/com/neoteric/jenkins/TemplateJob.groovy b/src/main/groovy/com/neoteric/jenkins/TemplateJob.groovy index 902deea..a9a41c5 100644 --- a/src/main/groovy/com/neoteric/jenkins/TemplateJob.groovy +++ b/src/main/groovy/com/neoteric/jenkins/TemplateJob.groovy @@ -11,8 +11,11 @@ class TemplateJob { String templateBranchName String jobNameForBranch(String branchName) { + println "-----> no cranky jankins "+branchName // git branches often have a forward slash in them, but they make jenkins cranky, turn it into an underscore + println "-----> branch name is "+branchName String safeBranchName = branchName.replaceAll('/', '_') + println "-----? jenkins branch name is "+safeBranchName return "$baseJobName-$safeBranchName" } From 7d4768548b9ef17f86a90c3430570432421367fb Mon Sep 17 00:00:00 2001 From: dmalament Date: Thu, 17 Sep 2015 09:37:47 -0400 Subject: [PATCH 2/8] Fixing error trying to create job that already exists The check for gathering a list of missing jobs that need to be added was comparing differently formatted job names, so it never found any matches. --- .../groovy/com/neoteric/jenkins/JenkinsJobManager.groovy | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy b/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy index e13e7a3..70441f4 100644 --- a/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy +++ b/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy @@ -104,7 +104,7 @@ class JenkinsJobManager { } println "-------> Expected jobs:" expectedJobsPerBranch.each { println " $it" } - List jobNamesPerBranch = jobNames.findAll{ it.endsWith(branchToProcess) } + List jobNamesPerBranch = jobNames.findAll{ it.endsWith(templateJob.jobNameForBranch(branchToProcess)) } println "-------> Job Names per branch:" jobNamesPerBranch.each { println " $it" } List missingJobsPerBranch = expectedJobsPerBranch.findAll { expectedJob -> @@ -132,7 +132,7 @@ class JenkinsJobManager { jenkinsApi.startJob(missingJob) } } - + if (!noDelete && jobsToDelete) { println "Deleting deprecated jobs:\n\t${jobsToDelete.join('\n\t')}" jobsToDelete.each { String jobName -> @@ -140,7 +140,7 @@ class JenkinsJobManager { } } } - + JenkinsApi initJenkinsApi() { if (!jenkinsApi) { assert jenkinsUrl != null From 95ac325005057ec0e0d7014e5b6efb46c2cd5d6b Mon Sep 17 00:00:00 2001 From: dmalament Date: Thu, 17 Sep 2015 16:22:01 -0400 Subject: [PATCH 3/8] Fixing no property templateJob error --- .../com/neoteric/jenkins/JenkinsJobManager.groovy | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy b/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy index 70441f4..b04260b 100644 --- a/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy +++ b/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy @@ -104,11 +104,11 @@ class JenkinsJobManager { } println "-------> Expected jobs:" expectedJobsPerBranch.each { println " $it" } - List jobNamesPerBranch = jobNames.findAll{ it.endsWith(templateJob.jobNameForBranch(branchToProcess)) } + List jobNamesPerBranch = jobNames.findAll{ it.endsWith(jobNameForBranch(branchToProcess,jobPrefix)) } println "-------> Job Names per branch:" jobNamesPerBranch.each { println " $it" } List missingJobsPerBranch = expectedJobsPerBranch.findAll { expectedJob -> - !jobNamesPerBranch.any {it.contains(expectedJob.jobName) } + !jobNamesPerBranch.any {it.contains(expectedJob.jobNameForBranch()) } } println "-------> Missing jobs:" missingJobsPerBranch.each { println " $it" } @@ -165,4 +165,10 @@ class JenkinsJobManager { return this.gitApi } + + String jobNameForBranch(String branchName, String baseJobName) { + // git branches often have a forward slash in them, but they make jenkins cranky, turn it into an underscore + String safeBranchName = branchName.replaceAll('/', '_') + return "$baseJobName-$safeBranchName" + } } From a9c7a70202a96dae4b75c6857d9b0b2dbb669820 Mon Sep 17 00:00:00 2001 From: dmalament Date: Mon, 21 Sep 2015 16:59:32 -0400 Subject: [PATCH 4/8] Rewriting logic to create TemplatJobs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The regex wasn’t finding all the jobs it needed to, so not enough TemplateJob objects were being created. --- .../neoteric/jenkins/JenkinsJobManager.groovy | 47 +++++++++++++++---- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy b/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy index b04260b..5c460da 100644 --- a/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy +++ b/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy @@ -67,16 +67,45 @@ class JenkinsJobManager { } public List findRequiredTemplateJobs(List allJobNames) { - String regex = /^($templateJobPrefix)-(.*)-($templateDevelopmentSuffix|$templateFeatureSuffix|$templateReleaseSuffix|$templateHotfixSuffix)$/ - - List templateJobs = allJobNames.findResults { String jobName -> - - TemplateJob templateJob = null - jobName.find(regex) {full, templateName, baseJobName, branchName -> - templateJob = new TemplateJob(jobName: full, baseJobName: baseJobName, templateBranchName: branchName) + List templateJobs = new ArrayList(); + + for(String jobName:allJobNames){ + if(jobName.contains(jobPrefix)){ + String suffixToUse = ""; + if(jobName.contains(templateDevelopmentSuffix)){ + suffixToUse = templateDevelopmentSuffix; + } + else if(jobName.contains(templateFeatureSuffix)){ + suffixToUse = templateFeatureSuffix; + } + else if(jobName.contains(templateHotfixSuffix)) { + suffixToUse = templateHotfixSuffix; + } + else if(jobName.contains(templateReleaseSuffix)) { + suffixToUse = templateReleaseSuffix; + } + else { + continue; + } + int suffixStarts = jobName.indexOf(suffixToUse); + int branchNameStarts = jobName.indexOf("_"); + String branchName = ""; + String templateName = ""; + + if(branchNameStarts == -1){ + templateName = jobName.substring(suffixStarts,jobName.length()); + } + else { + templateName = jobName.substring(suffixStarts,branchNameStarts); + branchName = jobName.substring(branchNameStarts+1,jobName.length()); + } + + String baseName = jobName.substring(jobName.indexOf(jobPrefix)+jobPrefix.length()+1,suffixStarts-1); + + TemplateJob t = new TemplateJob(jobName,base,template); + templateJobs.add(t); + } } - return templateJob - } assert templateJobs?.size() > 0, "Unable to find any jobs matching template regex: $regex\nYou need at least one job to match the templateJobPrefix and templateBranchName (feature, hotfix, release) suffix arguments" return templateJobs From 8888f8e63bb1767d0769b288789339b15257e18a Mon Sep 17 00:00:00 2001 From: "Minthorne, Josh" Date: Tue, 22 Sep 2015 09:12:16 -0400 Subject: [PATCH 5/8] made changes to fix some runtime errors. Also added println to aid in debugging --- .../neoteric/jenkins/JenkinsJobManager.groovy | 114 +++++++++++------- .../com/neoteric/jenkins/TemplateJob.groovy | 36 +++--- 2 files changed, 91 insertions(+), 59 deletions(-) diff --git a/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy b/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy index 5c460da..26587ef 100644 --- a/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy +++ b/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy @@ -27,9 +27,9 @@ class JenkinsJobManager { String templateReleaseSuffix = "release" def branchSuffixMatch = [(templateDevelopmentSuffix) : developmentSuffix, - (templateFeatureSuffix) : featureSuffix, - (templateHotfixSuffix) : hotfixSuffix, - (templateReleaseSuffix): releaseSuffix] + (templateFeatureSuffix) : featureSuffix, + (templateHotfixSuffix) : hotfixSuffix, + (templateReleaseSuffix): releaseSuffix] JenkinsApi jenkinsApi GitApi gitApi @@ -67,50 +67,76 @@ class JenkinsJobManager { } public List findRequiredTemplateJobs(List allJobNames) { - List templateJobs = new ArrayList(); - - for(String jobName:allJobNames){ - if(jobName.contains(jobPrefix)){ - String suffixToUse = ""; - if(jobName.contains(templateDevelopmentSuffix)){ - suffixToUse = templateDevelopmentSuffix; - } - else if(jobName.contains(templateFeatureSuffix)){ - suffixToUse = templateFeatureSuffix; - } - else if(jobName.contains(templateHotfixSuffix)) { - suffixToUse = templateHotfixSuffix; - } - else if(jobName.contains(templateReleaseSuffix)) { - suffixToUse = templateReleaseSuffix; - } - else { - continue; - } - int suffixStarts = jobName.indexOf(suffixToUse); - int branchNameStarts = jobName.indexOf("_"); - String branchName = ""; - String templateName = ""; - - if(branchNameStarts == -1){ - templateName = jobName.substring(suffixStarts,jobName.length()); - } - else { - templateName = jobName.substring(suffixStarts,branchNameStarts); - branchName = jobName.substring(branchNameStarts+1,jobName.length()); - } - - String baseName = jobName.substring(jobName.indexOf(jobPrefix)+jobPrefix.length()+1,suffixStarts-1); - - TemplateJob t = new TemplateJob(jobName,base,template); - templateJobs.add(t); - } + List templateJobs = new ArrayList() + + List jobs = removeNonMatchingJobs(allJobNames) + + for(String jobName : allJobNames){ + + int suffixStarts + if(jobName.contains(templateDevelopmentSuffix)){ + suffixStarts = jobName.indexOf(templateDevelopmentSuffix) + println "\n\tdev "+suffixStarts + } + else if(jobName.contains(templateFeatureSuffix)){ + suffixStarts = jobName.indexOf(templateFeatureSuffix) + println "\n\tfeature "+suffixStarts + } + else if(jobName.contains(templateHotfixSuffix)) { + suffixStarts = jobName.indexOf(templateHotfixSuffix) + println "\n\thotfix "+suffixStarts + } + else if(jobName.contains(templateReleaseSuffix)) { + suffixStarts = jobName.indexOf(templateReleaseSuffix) + println "\n\trelease "+suffixStarts + } + else { + continue; } + int branchNameStarts = jobName.indexOf("_"); + String branchName = ""; + String templateName = ""; + + if(branchNameStarts == -1){ + templateName = jobName.substring(suffixStarts,jobName.length()); + } + else { + templateName = jobName.substring(suffixStarts,branchNameStarts); + branchName = jobName.substring(branchNameStarts+1,jobName.length()); + } + + println "\n\tjobName "+jobName + println "\n\t index of prefix "+jobName.indexOf(jobPrefix) + println "\n\tprefix length "+jobPrefix.length() + int where = jobPrefix.length()+1 + println "\n\tprefix length and some "+where + int begin = jobPrefix.length() + where + println "\tbegin "+begin + String baseName = jobName.substring(jobName.indexOf(jobPrefix)+jobPrefix.length()+1,suffixStarts-1); + + TemplateJob t = new TemplateJob(jobName,baseName,branchName); + println "\tadded "+jobName + templateJobs.add(t); + } + assert templateJobs?.size() > 0, "Unable to find any jobs matching template regex: $regex\nYou need at least one job to match the templateJobPrefix and templateBranchName (feature, hotfix, release) suffix arguments" return templateJobs } + private List removeNonMatchingJobs(List allJobs){ + println "\tjobprefix "+jobPrefix + Iterator iter = allJobs.iterator(); + + while(iter.hasNext()){ + String jobName = iter.next() + + if(!jobName.contains(jobPrefix)){ + iter.remove() + }//if + }//while + } + public void syncJobs(List allBranchNames, List jobNames, List templateJobs) { @@ -196,8 +222,8 @@ class JenkinsJobManager { } String jobNameForBranch(String branchName, String baseJobName) { - // git branches often have a forward slash in them, but they make jenkins cranky, turn it into an underscore - String safeBranchName = branchName.replaceAll('/', '_') - return "$baseJobName-$safeBranchName" + // git branches often have a forward slash in them, but they make jenkins cranky, turn it into an underscore + String safeBranchName = branchName.replaceAll('/', '_') + return "$baseJobName-$safeBranchName" } } diff --git a/src/main/groovy/com/neoteric/jenkins/TemplateJob.groovy b/src/main/groovy/com/neoteric/jenkins/TemplateJob.groovy index a9a41c5..e08a769 100644 --- a/src/main/groovy/com/neoteric/jenkins/TemplateJob.groovy +++ b/src/main/groovy/com/neoteric/jenkins/TemplateJob.groovy @@ -6,20 +6,26 @@ import groovy.transform.ToString; @ToString @EqualsAndHashCode class TemplateJob { - String jobName - String baseJobName - String templateBranchName + String jobName + String baseJobName + String templateBranchName - String jobNameForBranch(String branchName) { - println "-----> no cranky jankins "+branchName - // git branches often have a forward slash in them, but they make jenkins cranky, turn it into an underscore - println "-----> branch name is "+branchName - String safeBranchName = branchName.replaceAll('/', '_') - println "-----? jenkins branch name is "+safeBranchName - return "$baseJobName-$safeBranchName" - } - - ConcreteJob concreteJobForBranch(String jobPrefix, String branchName) { - ConcreteJob concreteJob = new ConcreteJob(templateJob: this, branchName: branchName, jobName: jobPrefix + '-' + jobNameForBranch(branchName) ) - } + TemplateJob () {} + + TemplateJob(String jobName, String baseJobName, String templateBranchName) { + this.jobName = jobName + this.baseJobName = baseJobName + this.templateBranchName = templateBranchName + } + + String jobNameForBranch(String branchName) { + // git branches often have a forward slash in them, but they make jenkins cranky, turn it into an underscore + String safeBranchName = branchName.replaceAll('/', '-') + println "-----? jenkins branch name is "+safeBranchName + return "$baseJobName-$safeBranchName" + } + + ConcreteJob concreteJobForBranch(String jobPrefix, String branchName) { + ConcreteJob concreteJob = new ConcreteJob(templateJob: this, branchName: branchName, jobName: jobPrefix + '-' + jobNameForBranch(branchName) ) + } } From 8ac7feed13978e9e9e8dd6e4eedbe58f2de4f709 Mon Sep 17 00:00:00 2001 From: dmalament Date: Tue, 22 Sep 2015 13:38:26 -0400 Subject: [PATCH 6/8] Removing check for underscore Simplifying code and moving the baseName to a parameter --- .../neoteric/jenkins/JenkinsJobManager.groovy | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy b/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy index 26587ef..3d48eb5 100644 --- a/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy +++ b/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy @@ -51,7 +51,7 @@ class JenkinsJobManager { println "-------------------------------------" println "All job names:" + allJobNames - List templateJobs = findRequiredTemplateJobs(allJobNames) + List templateJobs = findRequiredTemplateJobs(allJobNames,"build"); println "-------------------------------------" println "Template Jobs:" + templateJobs @@ -66,7 +66,7 @@ class JenkinsJobManager { } - public List findRequiredTemplateJobs(List allJobNames) { + public List findRequiredTemplateJobs(List allJobNames, String baseName) { List templateJobs = new ArrayList() List jobs = removeNonMatchingJobs(allJobNames) @@ -94,17 +94,7 @@ class JenkinsJobManager { continue; } - int branchNameStarts = jobName.indexOf("_"); - String branchName = ""; - String templateName = ""; - - if(branchNameStarts == -1){ - templateName = jobName.substring(suffixStarts,jobName.length()); - } - else { - templateName = jobName.substring(suffixStarts,branchNameStarts); - branchName = jobName.substring(branchNameStarts+1,jobName.length()); - } + String branchName = jobName.substring(suffixStarts,jobName.length()); println "\n\tjobName "+jobName println "\n\t index of prefix "+jobName.indexOf(jobPrefix) @@ -113,7 +103,6 @@ class JenkinsJobManager { println "\n\tprefix length and some "+where int begin = jobPrefix.length() + where println "\tbegin "+begin - String baseName = jobName.substring(jobName.indexOf(jobPrefix)+jobPrefix.length()+1,suffixStarts-1); TemplateJob t = new TemplateJob(jobName,baseName,branchName); println "\tadded "+jobName From b9954c9537566f6179823dac32bcdb8b3945776f Mon Sep 17 00:00:00 2001 From: "Minthorne, Josh" Date: Wed, 23 Sep 2015 09:55:17 -0400 Subject: [PATCH 7/8] made changes to fix some runtime errors. Also added println to aid in debugging --- .../neoteric/jenkins/JenkinsJobManager.groovy | 307 ++++++++++-------- .../com/neoteric/jenkins/TemplateJob.groovy | 2 +- 2 files changed, 180 insertions(+), 129 deletions(-) diff --git a/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy b/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy index 3d48eb5..de70e45 100644 --- a/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy +++ b/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy @@ -16,10 +16,10 @@ class JenkinsJobManager { Boolean noDelete = false Boolean startOnCreate = false - String developmentSuffix = "development-" + String developmentSuffix = "development" String featureSuffix = "feature/" - String hotfixSuffix = "hotfix-" - String releaseSuffix = "release-" + String hotfixSuffix = "hotfix/" + String releaseSuffix = "release" String templateDevelopmentSuffix = "development" String templateFeatureSuffix = "feature" @@ -38,181 +38,232 @@ class JenkinsJobManager { for (property in props) { this."${property.key}" = property.value } + initJenkinsApi() initGitApi() } void syncWithRepo() { List allBranchNames = gitApi.branchNames - println "-------------------------------------" - println "All branch names:" + allBranchNames + println "\n-------------------------------------" + println "All branch names:" + allBranchNames +"\t" List allJobNames = jenkinsApi.jobNames - println "-------------------------------------" - println "All job names:" + allJobNames + println "\n-------------------------------------" + println "All job names:" + allJobNames +"\t" - List templateJobs = findRequiredTemplateJobs(allJobNames,"build"); - println "-------------------------------------" - println "Template Jobs:" + templateJobs + List templateJobs = findRequiredTemplateJobs(allJobNames); + println "\n-------------------------------------" + println "Template Jobs:" + templateJobs +"\t" - List jobsWithJobPrefix = allJobNames.findAll { jobName -> + List jobsWithJobPrefix = allJobNames.findAll { + jobName -> jobName.startsWith(jobPrefix + '-') } - println "-------------------------------------" - println "Jobs with provided prefix:" + jobsWithJobPrefix + println "\n-------------------------------------" + println "Jobs with provided prefix:" + jobsWithJobPrefix +"\t" // create any missing template jobs and delete any jobs matching the template patterns that no longer have branches syncJobs(allBranchNames, jobsWithJobPrefix, templateJobs) } - public List findRequiredTemplateJobs(List allJobNames, String baseName) { - List templateJobs = new ArrayList() - List jobs = removeNonMatchingJobs(allJobNames) + public List findRequiredTemplateJobs(List allJobNames) { + String regex = /^($templateJobPrefix)-(.*)-($templateFeatureSuffix|$templateReleaseSuffix|$templateHotfixSuffix)$/ - for(String jobName : allJobNames){ + List templateJobs = allJobNames.findResults { + String jobName -> - int suffixStarts - if(jobName.contains(templateDevelopmentSuffix)){ - suffixStarts = jobName.indexOf(templateDevelopmentSuffix) - println "\n\tdev "+suffixStarts - } - else if(jobName.contains(templateFeatureSuffix)){ - suffixStarts = jobName.indexOf(templateFeatureSuffix) - println "\n\tfeature "+suffixStarts - } - else if(jobName.contains(templateHotfixSuffix)) { - suffixStarts = jobName.indexOf(templateHotfixSuffix) - println "\n\thotfix "+suffixStarts - } - else if(jobName.contains(templateReleaseSuffix)) { - suffixStarts = jobName.indexOf(templateReleaseSuffix) - println "\n\trelease "+suffixStarts + TemplateJob templateJob = null + jobName.find(regex) { + full, templateName, baseJobName, branchName -> + templateJob = new TemplateJob(jobName: full, baseJobName: baseJobName, templateBranchName: branchName) } - else { - continue; - } - - String branchName = jobName.substring(suffixStarts,jobName.length()); - - println "\n\tjobName "+jobName - println "\n\t index of prefix "+jobName.indexOf(jobPrefix) - println "\n\tprefix length "+jobPrefix.length() - int where = jobPrefix.length()+1 - println "\n\tprefix length and some "+where - int begin = jobPrefix.length() + where - println "\tbegin "+begin - - TemplateJob t = new TemplateJob(jobName,baseName,branchName); - println "\tadded "+jobName - templateJobs.add(t); + return templateJob } assert templateJobs?.size() > 0, "Unable to find any jobs matching template regex: $regex\nYou need at least one job to match the templateJobPrefix and templateBranchName (feature, hotfix, release) suffix arguments" return templateJobs } - private List removeNonMatchingJobs(List allJobs){ - println "\tjobprefix "+jobPrefix - Iterator iter = allJobs.iterator(); + /*public List findRequiredTemplateJobs(List allJobNames, String baseName) { + String regex = /^($templateJobPrefix)-(.*)-($templateFeatureSuffix|$templateReleaseSuffix|$templateHotfixSuffix)$/ + List templateJobs = new ArrayList() + List jobs = removeNonMatchingJobs(allJobNames) + for(String jobName : allJobNames){ + int suffixStarts + if(jobName.contains(templateDevelopmentSuffix)){ + suffixStarts = jobName.indexOf(templateDevelopmentSuffix) + //println "\n\tdev "+suffixStarts + } + else if(jobName.contains(templateFeatureSuffix)){ + suffixStarts = jobName.indexOf(templateFeatureSuffix) + //println "\n\tfeature "+suffixStarts + } + else if(jobName.contains(templateHotfixSuffix)) { + suffixStarts = jobName.indexOf(templateHotfixSuffix) + //println "\n\thotfix "+suffixStarts + } + else if(jobName.contains(templateReleaseSuffix)) { + suffixStarts = jobName.indexOf(templateReleaseSuffix) + //println "\n\trelease "+suffixStarts + } + else { + continue; + } + String branchName = jobName.substring(suffixStarts,jobName.length()); + // println "\n\tjobName "+jobName + //println "\n\t index of prefix "+jobName.indexOf(jobPrefix) + //println "\n\tprefix length "+jobPrefix.length() + //int where = jobPrefix.length()+1 + //println "\n\tprefix length and some "+where + //int begin = jobPrefix.length() + where + //println "\tbegin "+begin + TemplateJob t = new TemplateJob(jobName,baseName,branchName); + println "\tadded "+jobName + templateJobs.add(t); + } + assert templateJobs?.size() > 0, "Unable to find any jobs matching template regex: $regex\nYou need at least one job to match the templateJobPrefix and templateBranchName (development, feature, hotfix, release) suffix arguments" + return templateJobs + }*/ + + private List removeNonMatchingJobs(List allJobs){ + println "\tjobprefix "+jobPrefix + Iterator iter = allJobs.iterator(); + + while(iter.hasNext()){ + String jobName = iter.next() + + if(!jobName.contains(jobPrefix)){ + iter.remove() + }//if + }//while + } - while(iter.hasNext()){ - String jobName = iter.next() + public void syncJobs(List allBranchNames, List jobNames, List templateJobs) { + + println "tempjobs size is $templateJobs.size()" + println "all branches size is $allBranchNames.size()" + def templateJobsByBranch = templateJobs.groupBy({ + template -> template.templateBranchName + }) + println "size is $templateJobsByBranch" + + List missingJobs = []; + List jobsToDelete = []; + + templateJobsByBranch.keySet().each { + templateBranchToProcess -> + println "\tChecking $templateBranchToProcess branches" + List branchesWithCorrespondingTemplate = allBranchNames.findAll { + branchName -> + println "\t\tbranch name is $branchName\n" + branchName.startsWith(branchSuffixMatch[templateBranchToProcess]) + } - if(!jobName.contains(jobPrefix)){ - iter.remove() - }//if - }//while - } + println "\tFound corresponding branches: $branchesWithCorrespondingTemplate" + branchesWithCorrespondingTemplate.each { + branchToProcess -> - public void syncJobs(List allBranchNames, List jobNames, List templateJobs) { + println "\t\tProcessing branch: $branchToProcess" + List expectedJobsPerBranch = templateJobsByBranch[templateBranchToProcess].collect { + TemplateJob templateJob -> + templateJob.concreteJobForBranch(jobPrefix, branchToProcess) + } - def templateJobsByBranch = templateJobs.groupBy({ template -> template.templateBranchName }) + println "\t\t\tExpected jobs for : "+jobNameForBranch(branchToProcess,jobPrefix) - List missingJobs = []; - List jobsToDelete = []; + expectedJobsPerBranch.each { + println "\t\t\t$it" + } + List jobNamesPerBranch = jobNames.findAll{ + it.contains(jobNameForBranch(branchToProcess,jobPrefix)) + } - templateJobsByBranch.keySet().each { templateBranchToProcess -> - println "-> Checking $templateBranchToProcess branches" - List branchesWithCorrespondingTemplate = allBranchNames.findAll { branchName -> - branchName.startsWith(branchSuffixMatch[templateBranchToProcess]) - } + println "\t\tJob Names per branch:" - println "---> Founded corresponding branches: $branchesWithCorrespondingTemplate" - branchesWithCorrespondingTemplate.each { branchToProcess -> - println "-----> Processing branch: $branchToProcess" - List expectedJobsPerBranch = templateJobsByBranch[templateBranchToProcess].collect { TemplateJob templateJob -> - templateJob.concreteJobForBranch(jobPrefix, branchToProcess) + jobNamesPerBranch.each { + println " $it" + } + List missingJobsPerBranch = expectedJobsPerBranch.findAll { + expectedJob -> + !jobNamesPerBranch.any { + it.contains(expectedJob.jobNameForBranch()) + } + } + + println "\n\t\tMissing jobs:" + + missingJobsPerBranch.each { + println "\t\t\t$it" + } + missingJobs.addAll(missingJobsPerBranch) } - println "-------> Expected jobs:" - expectedJobsPerBranch.each { println " $it" } - List jobNamesPerBranch = jobNames.findAll{ it.endsWith(jobNameForBranch(branchToProcess,jobPrefix)) } - println "-------> Job Names per branch:" - jobNamesPerBranch.each { println " $it" } - List missingJobsPerBranch = expectedJobsPerBranch.findAll { expectedJob -> - !jobNamesPerBranch.any {it.contains(expectedJob.jobNameForBranch()) } + + List deleteCandidates = jobNames.findAll { + it.contains(branchSuffixMatch[templateBranchToProcess]) + } + List jobsToDeletePerBranch = deleteCandidates.findAll { + candidate -> + !branchesWithCorrespondingTemplate.any { + candidate.endsWith(it) + } } - println "-------> Missing jobs:" - missingJobsPerBranch.each { println " $it" } - missingJobs.addAll(missingJobsPerBranch) - } - List deleteCandidates = jobNames.findAll { it.contains(branchSuffixMatch[templateBranchToProcess]) } - List jobsToDeletePerBranch = deleteCandidates.findAll { candidate -> - !branchesWithCorrespondingTemplate.any { candidate.endsWith(it) } + println "\n\tJobs to delete:" + jobsToDeletePerBranch.each { + println " $it" + } + jobsToDelete.addAll(jobsToDeletePerBranch) } - - println "-----> Jobs to delete:" - jobsToDeletePerBranch.each { println " $it" } - jobsToDelete.addAll(jobsToDeletePerBranch) - } - println "\nSummary:\n---------------" - if (missingJobs) { - for(ConcreteJob missingJob in missingJobs) { - println "Creating missing job: ${missingJob.jobName} from ${missingJob.templateJob.jobName}" - jenkinsApi.cloneJobForBranch(jobPrefix, missingJob, createJobInView, gitUrl) - jenkinsApi.startJob(missingJob) + println "\nSummary:\n---------------" + if (missingJobs) { + for(ConcreteJob missingJob in missingJobs) { + println "Creating missing job: ${missingJob.jobName} from ${missingJob.templateJob.jobName}" + jenkinsApi.cloneJobForBranch(jobPrefix, missingJob, createJobInView, gitUrl) + jenkinsApi.startJob(missingJob) + } } - } - if (!noDelete && jobsToDelete) { - println "Deleting deprecated jobs:\n\t${jobsToDelete.join('\n\t')}" - jobsToDelete.each { String jobName -> - jenkinsApi.deleteJob(jobName) + if (!noDelete && jobsToDelete) { + println "Deleting deprecated jobs:\n\t${jobsToDelete.join('\n\t')}" + jobsToDelete.each { + String jobName -> + jenkinsApi.deleteJob(jobName) + } } } - } - JenkinsApi initJenkinsApi() { - if (!jenkinsApi) { - assert jenkinsUrl != null - if (dryRun) { - println "DRY RUN! Not executing any POST commands to Jenkins, only GET commands" - this.jenkinsApi = new JenkinsApiReadOnly(jenkinsServerUrl: jenkinsUrl) - } else { - this.jenkinsApi = new JenkinsApi(jenkinsServerUrl: jenkinsUrl) + JenkinsApi initJenkinsApi() { + if (!jenkinsApi) { + assert jenkinsUrl != null + if (dryRun) { + println "DRY RUN! Not executing any POST commands to Jenkins, only GET commands" + this.jenkinsApi = new JenkinsApiReadOnly(jenkinsServerUrl: jenkinsUrl) + } else { + this.jenkinsApi = new JenkinsApi(jenkinsServerUrl: jenkinsUrl) + } + + if (jenkinsUser || jenkinsPassword) this.jenkinsApi.addBasicAuth(jenkinsUser, jenkinsPassword) } - if (jenkinsUser || jenkinsPassword) this.jenkinsApi.addBasicAuth(jenkinsUser, jenkinsPassword) + return this.jenkinsApi } - return this.jenkinsApi - } + GitApi initGitApi() { + if (!gitApi) { + assert gitUrl != null + this.gitApi = new GitApi(gitUrl: gitUrl) + } - GitApi initGitApi() { - if (!gitApi) { - assert gitUrl != null - this.gitApi = new GitApi(gitUrl: gitUrl) + return this.gitApi } - return this.gitApi - } - - String jobNameForBranch(String branchName, String baseJobName) { - // git branches often have a forward slash in them, but they make jenkins cranky, turn it into an underscore - String safeBranchName = branchName.replaceAll('/', '_') - return "$baseJobName-$safeBranchName" + String jobNameForBranch(String branchName, String baseJobName) { + // git branches often have a forward slash in them, but they make jenkins cranky, turn it into an underscore + String safeBranchName = branchName.replaceAll('/', '-') + return "$baseJobName-$safeBranchName" + } } -} diff --git a/src/main/groovy/com/neoteric/jenkins/TemplateJob.groovy b/src/main/groovy/com/neoteric/jenkins/TemplateJob.groovy index e08a769..3498cd2 100644 --- a/src/main/groovy/com/neoteric/jenkins/TemplateJob.groovy +++ b/src/main/groovy/com/neoteric/jenkins/TemplateJob.groovy @@ -21,7 +21,7 @@ class TemplateJob { String jobNameForBranch(String branchName) { // git branches often have a forward slash in them, but they make jenkins cranky, turn it into an underscore String safeBranchName = branchName.replaceAll('/', '-') - println "-----? jenkins branch name is "+safeBranchName + println "\t\t\t\t jenkins branch name is "+safeBranchName return "$baseJobName-$safeBranchName" } From 2332ef400a5eee4d73bfbe905208491ad4f70625 Mon Sep 17 00:00:00 2001 From: dmalament Date: Fri, 2 Oct 2015 16:24:03 -0400 Subject: [PATCH 8/8] Rewrite to remove TemplateJob and ConcreteJob objects Using the TemplateJob and ConcreteJob objects added needless complexity to the code. This version relies on strings of job names and branch names. --- .../com/neoteric/jenkins/JenkinsApi.groovy | 52 ++-- .../neoteric/jenkins/JenkinsJobManager.groovy | 236 +++++------------- 2 files changed, 86 insertions(+), 202 deletions(-) diff --git a/src/main/groovy/com/neoteric/jenkins/JenkinsApi.groovy b/src/main/groovy/com/neoteric/jenkins/JenkinsApi.groovy index 86b2ea8..a45be49 100644 --- a/src/main/groovy/com/neoteric/jenkins/JenkinsApi.groovy +++ b/src/main/groovy/com/neoteric/jenkins/JenkinsApi.groovy @@ -13,8 +13,8 @@ import org.apache.http.protocol.HttpContext import org.apache.http.HttpRequest class JenkinsApi { - - + + final String SHOULD_START_PARAM_NAME = "startOnCreate" String jenkinsServerUrl RESTClient restClient @@ -57,21 +57,20 @@ class JenkinsApi { response.data.text } - void cloneJobForBranch(String jobPrefix, ConcreteJob missingJob, String createJobInView, String gitUrl) { + void cloneJobForBranch(String templateJob, String missingJob, String branchName, String createJobInView, String gitUrl) { String createJobInViewPath = resolveViewPath(createJobInView) println "-----> createInView after: " + createJobInView - String missingJobConfig = configForMissingJob(missingJob, gitUrl) - TemplateJob templateJob = missingJob.templateJob + String missingJobConfig = configForMissingJob(templateJob, branchName, gitUrl) //Copy job with jenkins copy job api, this will make sure jenkins plugins get the call to make a copy if needed (promoted builds plugin needs this) - post(createJobInViewPath + 'createItem', missingJobConfig, [name: missingJob.jobName, mode: 'copy', from: templateJob.jobName], ContentType.XML) + post(createJobInViewPath + 'createItem', missingJobConfig, [name: missingJob, mode: 'copy', from: templateJob], ContentType.XML) - post('job/' + missingJob.jobName + "/config.xml", missingJobConfig, [:], ContentType.XML) + post('job/' + missingJob + "/config.xml", missingJobConfig, [:], ContentType.XML) //Forced disable enable to work around Jenkins' automatic disabling of clones jobs //But only if the original job was enabled - post('job/' + missingJob.jobName + '/disable') + post('job/' + missingJob + '/disable') if (!missingJobConfig.contains("true")) { - post('job/' + missingJob.jobName + '/enable') + post('job/' + missingJob+ '/enable') } } @@ -84,12 +83,9 @@ class JenkinsApi { elements.join(); } - String configForMissingJob(ConcreteJob missingJob, String gitUrl) { - - TemplateJob templateJob = missingJob.templateJob - String config = getJobConfig(templateJob.jobName) - - return processConfig(config, missingJob.branchName, gitUrl) + String configForMissingJob(String templateJob, String branchName, String gitUrl) { + String config = getJobConfig(templateJob) + return processConfig(config, branchName, gitUrl) } public String processConfig(String entryConfig, String branchName, String gitUrl) { @@ -106,43 +102,43 @@ class JenkinsApi { if (root.publishers."hudson.plugins.sonar.SonarPublisher".branch[0] != null) { root.publishers."hudson.plugins.sonar.SonarPublisher".branch[0].value = "$branchName" } - - + + //remove template build variable Node startOnCreateParam = findStartOnCreateParameter(root) if (startOnCreateParam) { startOnCreateParam.parent().remove(startOnCreateParam) } - + //check if it was the only parameter - if so, remove the enclosing tag, so the project won't be seen as build with parameters def propertiesNode = root.properties def parameterDefinitionsProperty //the neoteric people hard coded property names and didn't do defensive coding. This causes an NPE. tisk tisk!! if(propertiesNode."hudson.model.ParametersDefinitionProperty".parameterDefinitions[0] !=null){ - + parameterDefinitionsProperty = propertiesNode."hudson.model.ParametersDefinitionProperty".parameterDefinitions[0] - + if(!parameterDefinitionsProperty.attributes() && !parameterDefinitionsProperty.children() && !parameterDefinitionsProperty.text()) { root.remove(propertiesNode) new Node(root, 'properties') } } - + def writer = new StringWriter() XmlNodePrinter xmlPrinter = new XmlNodePrinter(new PrintWriter(writer)) xmlPrinter.setPreserveWhitespace(true) xmlPrinter.print(root) return writer.toString() } - - void startJob(ConcreteJob job) { - String templateConfig = getJobConfig(job.templateJob.jobName) + + void startJob(String templateJob, String jobName) { + String templateConfig = getJobConfig(templateJob) if (shouldStartJob(templateConfig)) { - println "Starting job ${job.jobName}." - post('job/' + job.jobName + '/build') + println "Starting job ${jobName}." + post('job/' + jobName + '/build') } } - + public boolean shouldStartJob(String config) { Node root = new XmlParser().parseText(config) Node startOnCreateParam = findStartOnCreateParameter(root) @@ -151,7 +147,7 @@ class JenkinsApi { } return startOnCreateParam.defaultValue[0]?.text().toBoolean() } - + Node findStartOnCreateParameter(Node root) { return root.properties."hudson.model.ParametersDefinitionProperty".parameterDefinitions."hudson.model.BooleanParameterDefinition".find { it.name[0].text() == SHOULD_START_PARAM_NAME diff --git a/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy b/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy index de70e45..750e6a2 100644 --- a/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy +++ b/src/main/groovy/com/neoteric/jenkins/JenkinsJobManager.groovy @@ -16,20 +16,13 @@ class JenkinsJobManager { Boolean noDelete = false Boolean startOnCreate = false - String developmentSuffix = "development" - String featureSuffix = "feature/" - String hotfixSuffix = "hotfix/" - String releaseSuffix = "release" - String templateDevelopmentSuffix = "development" String templateFeatureSuffix = "feature" String templateHotfixSuffix = "hotfix" String templateReleaseSuffix = "release" - - def branchSuffixMatch = [(templateDevelopmentSuffix) : developmentSuffix, - (templateFeatureSuffix) : featureSuffix, - (templateHotfixSuffix) : hotfixSuffix, - (templateReleaseSuffix): releaseSuffix] + List missingJobs + List jobsToDelete + def jobNameToBranchName JenkinsApi jenkinsApi GitApi gitApi @@ -52,189 +45,84 @@ class JenkinsJobManager { println "\n-------------------------------------" println "All job names:" + allJobNames +"\t" - List templateJobs = findRequiredTemplateJobs(allJobNames); - println "\n-------------------------------------" - println "Template Jobs:" + templateJobs +"\t" + missingJobs = []; + jobsToDelete = []; + jobNameToBranchName = [:] + // create any missing template jobs and delete any jobs matching the template patterns that no longer have branches + syncJobs(allBranchNames, allJobNames) + addMissingJobs() + deleteJobs() + } + void syncJobs(List allBranchNames, List allJobNames){ + //first check for missing jobs List jobsWithJobPrefix = allJobNames.findAll { jobName -> jobName.startsWith(jobPrefix + '-') } println "\n-------------------------------------" println "Jobs with provided prefix:" + jobsWithJobPrefix +"\t" - - // create any missing template jobs and delete any jobs matching the template patterns that no longer have branches - syncJobs(allBranchNames, jobsWithJobPrefix, templateJobs) - - } - - - public List findRequiredTemplateJobs(List allJobNames) { - String regex = /^($templateJobPrefix)-(.*)-($templateFeatureSuffix|$templateReleaseSuffix|$templateHotfixSuffix)$/ - - List templateJobs = allJobNames.findResults { - String jobName -> - - TemplateJob templateJob = null - jobName.find(regex) { - full, templateName, baseJobName, branchName -> - templateJob = new TemplateJob(jobName: full, baseJobName: baseJobName, templateBranchName: branchName) + List jenkinsBranchNames = new ArrayList() + + //first check for branches that don't have jobs yet and add them + for(String branch:allBranchNames){ + String trueName = jobNameForBranch(branch,jobPrefix+"-"+templateJobPrefix); + jenkinsBranchNames.add(trueName) + if(!allJobNames.contains(trueName)){ + //add job + missingJobs.add(trueName) + jobNameToBranchName[trueName] = branch } - return templateJob } - assert templateJobs?.size() > 0, "Unable to find any jobs matching template regex: $regex\nYou need at least one job to match the templateJobPrefix and templateBranchName (feature, hotfix, release) suffix arguments" - return templateJobs - } - - /*public List findRequiredTemplateJobs(List allJobNames, String baseName) { - String regex = /^($templateJobPrefix)-(.*)-($templateFeatureSuffix|$templateReleaseSuffix|$templateHotfixSuffix)$/ - List templateJobs = new ArrayList() - List jobs = removeNonMatchingJobs(allJobNames) - for(String jobName : allJobNames){ - int suffixStarts - if(jobName.contains(templateDevelopmentSuffix)){ - suffixStarts = jobName.indexOf(templateDevelopmentSuffix) - //println "\n\tdev "+suffixStarts - } - else if(jobName.contains(templateFeatureSuffix)){ - suffixStarts = jobName.indexOf(templateFeatureSuffix) - //println "\n\tfeature "+suffixStarts - } - else if(jobName.contains(templateHotfixSuffix)) { - suffixStarts = jobName.indexOf(templateHotfixSuffix) - //println "\n\thotfix "+suffixStarts - } - else if(jobName.contains(templateReleaseSuffix)) { - suffixStarts = jobName.indexOf(templateReleaseSuffix) - //println "\n\trelease "+suffixStarts - } - else { - continue; - } - String branchName = jobName.substring(suffixStarts,jobName.length()); - // println "\n\tjobName "+jobName - //println "\n\t index of prefix "+jobName.indexOf(jobPrefix) - //println "\n\tprefix length "+jobPrefix.length() - //int where = jobPrefix.length()+1 - //println "\n\tprefix length and some "+where - //int begin = jobPrefix.length() + where - //println "\tbegin "+begin - TemplateJob t = new TemplateJob(jobName,baseName,branchName); - println "\tadded "+jobName - templateJobs.add(t); - } - assert templateJobs?.size() > 0, "Unable to find any jobs matching template regex: $regex\nYou need at least one job to match the templateJobPrefix and templateBranchName (development, feature, hotfix, release) suffix arguments" - return templateJobs - }*/ - - private List removeNonMatchingJobs(List allJobs){ - println "\tjobprefix "+jobPrefix - Iterator iter = allJobs.iterator(); - - while(iter.hasNext()){ - String jobName = iter.next() - - if(!jobName.contains(jobPrefix)){ - iter.remove() - }//if - }//while + //then check for jobs that don't have branches anymore and need to be deleted + for(String job:allJobNames){ + if(!jenkinsBranchNames.contains(job)){ + //delete job + jobsToDelete.add(job) + } } + } - public void syncJobs(List allBranchNames, List jobNames, List templateJobs) { - - println "tempjobs size is $templateJobs.size()" - println "all branches size is $allBranchNames.size()" - def templateJobsByBranch = templateJobs.groupBy({ - template -> template.templateBranchName - }) - println "size is $templateJobsByBranch" - - List missingJobs = []; - List jobsToDelete = []; - - templateJobsByBranch.keySet().each { - templateBranchToProcess -> - println "\tChecking $templateBranchToProcess branches" - List branchesWithCorrespondingTemplate = allBranchNames.findAll { - branchName -> - println "\t\tbranch name is $branchName\n" - branchName.startsWith(branchSuffixMatch[templateBranchToProcess]) - } - - println "\tFound corresponding branches: $branchesWithCorrespondingTemplate" - branchesWithCorrespondingTemplate.each { - branchToProcess -> - - println "\t\tProcessing branch: $branchToProcess" - - List expectedJobsPerBranch = templateJobsByBranch[templateBranchToProcess].collect { - TemplateJob templateJob -> - templateJob.concreteJobForBranch(jobPrefix, branchToProcess) - } - - println "\t\t\tExpected jobs for : "+jobNameForBranch(branchToProcess,jobPrefix) - - expectedJobsPerBranch.each { - println "\t\t\t$it" - } - List jobNamesPerBranch = jobNames.findAll{ - it.contains(jobNameForBranch(branchToProcess,jobPrefix)) - } - - println "\t\tJob Names per branch:" - - jobNamesPerBranch.each { - println " $it" - } - List missingJobsPerBranch = expectedJobsPerBranch.findAll { - expectedJob -> - !jobNamesPerBranch.any { - it.contains(expectedJob.jobNameForBranch()) - } - } + void addMissingJobs(){ + for(String job:missingJobs){ + String templateJobName = jobPrefix+"-"+templateJobPrefix - println "\n\t\tMissing jobs:" + if(job.contains(templateJobName+"-"+templateDevelopmentSuffix)){ + templateJobName = templateJobName + "-" + templateDevelopmentSuffix + } + else if(job.contains(templateJobName+"-"+templateFeatureSuffix)){ + templateJobName = templateJobName + "-" + templateFeatureSuffix + } + else if(job.contains(templateJobName+"-"+templateHotfixSuffix)){ + templateJobName = templateJobName + "-" + templateHotfixSuffix + } + else if(job.contains(templateJobName+"-"+templateReleaseSuffix)){ + templateJobName = templateJobName + "-" + templateReleaseSuffix + } + else { + //throw an error because a template job for this branch doesn't exist + } - missingJobsPerBranch.each { - println "\t\t\t$it" - } - missingJobs.addAll(missingJobsPerBranch) - } + String branchName = jobNameToBranchName[job] - List deleteCandidates = jobNames.findAll { - it.contains(branchSuffixMatch[templateBranchToProcess]) - } - List jobsToDeletePerBranch = deleteCandidates.findAll { - candidate -> - !branchesWithCorrespondingTemplate.any { - candidate.endsWith(it) - } - } + println "Creating missing job: ${job} from ${templateJobName}" - println "\n\tJobs to delete:" - jobsToDeletePerBranch.each { - println " $it" - } - jobsToDelete.addAll(jobsToDeletePerBranch) - } - println "\nSummary:\n---------------" - if (missingJobs) { - for(ConcreteJob missingJob in missingJobs) { - println "Creating missing job: ${missingJob.jobName} from ${missingJob.templateJob.jobName}" - jenkinsApi.cloneJobForBranch(jobPrefix, missingJob, createJobInView, gitUrl) - jenkinsApi.startJob(missingJob) - } - } + jenkinsApi.cloneJobForBranch(templateJobName, missingJob, branchName, createJobInView, gitUrl) + jenkinsApi.startJob(templateJobName, missingJob) + } + } - if (!noDelete && jobsToDelete) { - println "Deleting deprecated jobs:\n\t${jobsToDelete.join('\n\t')}" - jobsToDelete.each { - String jobName -> - jenkinsApi.deleteJob(jobName) - } + void deleteJobs(){ + if (!noDelete && jobsToDelete) { + println "Deleting deprecated jobs:\n\t${jobsToDelete.join('\n\t')}" + jobsToDelete.each { + String jobName -> + jenkinsApi.deleteJob(jobName) } } + } + JenkinsApi initJenkinsApi() { if (!jenkinsApi) {