diff --git a/.gitignore b/.gitignore index 08834735..b669894b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,11 @@ *.iws *.diff build -.gradle +#.gradle +.settings +.classpath +.project out atlassian-ide-plugin.xml +/bin diff --git a/build.gradle b/build.gradle index 9b86920c..b60a3fa7 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ repositories { } dependencies { - groovy 'org.codehaus.groovy:groovy-all:1.8.8' + compile 'org.codehaus.groovy:groovy-all:2.4.7' compile 'org.apache.ivy:ivy:2.2.0' compile 'commons-cli:commons-cli:1.2' // should be part of groovy, but not available when running for some reason testCompile 'junit:junit:4.10' @@ -24,7 +24,7 @@ task createSourceDirs(description : 'Create empty source directories for all def idea { project { - jdkName = '1.6' + jdkName = '1.8' } } @@ -33,14 +33,14 @@ task syncWithRepo(dependsOn: 'classes', type: JavaExec) { main = 'com.entagen.jenkins.Main' classpath = sourceSets.main.runtimeClasspath // pass through specified system properties to the call to main - ['help', 'jenkinsUrl', 'jenkinsUser', 'jenkinsPassword', 'gitUrl', 'templateJobPrefix', 'templateBranchName', 'branchNameRegex', 'nestedView', 'viewRegex', 'printConfig', 'dryRun', 'startOnCreate', 'noViews', 'noDelete'].each { + ['help', 'jenkinsUrl', 'jenkinsUser', 'jenkinsPassword', 'gitUrl', 'templateJobPrefix', 'templateBranchName', 'branchNameRegex', 'nestedView', 'viewRegex', 'printConfig', 'dryRun', 'startOnCreate', 'noViews', 'noDelete', 'enableJob', 'days', 'disableLastCommit'].each { if (System.getProperty(it)) systemProperty it, System.getProperty(it) } } task wrapper(type: Wrapper) { - gradleVersion = '1.0' + gradleVersion = '3.0' } diff --git a/get-branches.sh b/get-branches.sh new file mode 100644 index 00000000..7180239b --- /dev/null +++ b/get-branches.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +if [ ! -d $2 ]; then + git clone $1 || { echo >&2 "failed with $?"; exit 1; } +fi +cd $2 +git fetch -p +for branch in `git branch -r | grep -v HEAD`;do echo `git show --format="%ct" $branch | head -n 1` \\t$branch; done | sort -r \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 5397bfa3..89cf204a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Jun 20 11:41:01 CDT 2012 +#Sat Sep 10 12:51:28 EDT 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-1.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-3.0-all.zip \ No newline at end of file diff --git a/src/main/groovy/com/entagen/jenkins/GitApi.groovy b/src/main/groovy/com/entagen/jenkins/GitApi.groovy index affcedaf..2ef87f4f 100644 --- a/src/main/groovy/com/entagen/jenkins/GitApi.groovy +++ b/src/main/groovy/com/entagen/jenkins/GitApi.groovy @@ -5,28 +5,40 @@ import java.util.regex.Pattern class GitApi { String gitUrl Pattern branchNameFilter = null + Integer daysSinceLastCommit = 5; + Boolean disableLastCommit = false; public List getBranchNames() { - String command = "git ls-remote --heads ${gitUrl}" + String repo = gitUrl.substring(gitUrl.lastIndexOf('/') + 1, gitUrl.lastIndexOf('.git')) + String command = "sh get-branches.sh ${gitUrl} ${repo}" List branchNames = [] eachResultLine(command) { String line -> - String branchNameRegex = "^.*\trefs/heads/(.*)\$" + line = line.replace("\\t", "\t") + String branchNameRegex = "^.*\torigin/(.*)\$" String branchName = line.find(branchNameRegex) { full, branchName -> branchName } - Boolean selected = passesFilter(branchName) - println "\t" + (selected ? "* " : " ") + "$line" - // lines are in the format of: \trefs/heads/BRANCH_NAME - // ex: b9c209a2bf1c159168bf6bc2dfa9540da7e8c4a26\trefs/heads/master + Boolean selected = passesFilter(branchName) && (disableLastCommit || passesLastCommitDateFilter(line)) + + println "${(selected ? '* ' : '')} ${line}" + // lines are in the format of: lastCommitDate\torigin/BRANCH_NAME + // ex: 1471048873\torigin/master if (selected) branchNames << branchName } return branchNames } + public Boolean passesLastCommitDateFilter(String branch) { + Date lastCommitForBranch = new Date(branch.tokenize()[0].toLong() * 1000) + Date commitCutoff = new Date() - daysSinceLastCommit + return lastCommitForBranch.after(commitCutoff) + } + public Boolean passesFilter(String branchName) { if (!branchName) return false if (!branchNameFilter) return true - return branchName ==~ branchNameFilter + Boolean passed = branchName ==~ branchNameFilter + return passed } // assumes all commands are "safe", if we implement any destructive git commands, we'd want to separate those out for a dry-run @@ -37,18 +49,18 @@ class GitApi { def gitOutput = "" while(true) { - int readByte = inputStream.read() - if (readByte == -1) break // EOF - byte[] bytes = new byte[1] - bytes[0] = readByte - gitOutput = gitOutput.concat(new String(bytes)) + int readByte = inputStream.read() + if (readByte == -1) break // EOF + byte[] bytes = new byte[1] + bytes[0] = readByte + gitOutput = gitOutput.concat(new String(bytes)) } process.waitFor() if (process.exitValue() == 0) { gitOutput.eachLine { String line -> - closure(line) - } + closure(line) + } } else { String errorText = process.errorStream.text?.trim() println "error executing command: $command" @@ -57,4 +69,4 @@ class GitApi { } } -} +} \ No newline at end of file diff --git a/src/main/groovy/com/entagen/jenkins/JenkinsApi.groovy b/src/main/groovy/com/entagen/jenkins/JenkinsApi.groovy index 8d451fc5..ced8aeb0 100644 --- a/src/main/groovy/com/entagen/jenkins/JenkinsApi.groovy +++ b/src/main/groovy/com/entagen/jenkins/JenkinsApi.groovy @@ -66,6 +66,10 @@ class JenkinsApi { post('job/' + missingJob.jobName + '/enable') } } + + void enableJob(ConcreteJob job) { + post('job/' + job.jobName + '/enable') + } void startJob(ConcreteJob job) { println "Starting job ${job.jobName}." diff --git a/src/main/groovy/com/entagen/jenkins/JenkinsJobManager.groovy b/src/main/groovy/com/entagen/jenkins/JenkinsJobManager.groovy index b03bf45e..ceb313a7 100644 --- a/src/main/groovy/com/entagen/jenkins/JenkinsJobManager.groovy +++ b/src/main/groovy/com/entagen/jenkins/JenkinsJobManager.groovy @@ -17,6 +17,9 @@ class JenkinsJobManager { Boolean noViews = false Boolean noDelete = false Boolean startOnCreate = false + Boolean enableJob = false + String days + Boolean disableLastCommit JenkinsApi jenkinsApi GitApi gitApi @@ -63,7 +66,10 @@ class JenkinsJobManager { for(ConcreteJob missingJob in missingJobs) { println "Creating missing job: ${missingJob.jobName} from ${missingJob.templateJob.jobName}" jenkinsApi.cloneJobForBranch(missingJob, templateJobs) - if (startOnCreate) { + if(enableJob) { + jenkinsApi.enableJob(missingJob) + } + if (startOnCreate) { jenkinsApi.startJob(missingJob) } } @@ -90,7 +96,7 @@ class JenkinsJobManager { // don't want actual template jobs, just the jobs that were created from the templates return (allJobNames - templateJobNames).findAll { String jobName -> - templateBaseJobNames.find { String baseJobName -> jobName.startsWith(baseJobName)} + templateBaseJobNames.find { String baseJobName -> jobName.startsWith(baseJobName) && jobName.tokenize("-")[2] ==~ branchNameRegex.replace("/", "_")} } } @@ -161,7 +167,7 @@ class JenkinsJobManager { GitApi initGitApi() { if (!gitApi) { assert gitUrl != null - this.gitApi = new GitApi(gitUrl: gitUrl) + this.gitApi = new GitApi(gitUrl: gitUrl, daysSinceLastCommit: days.toInteger(), disableLastCommit: disableLastCommit) if (this.branchNameRegex){ this.gitApi.branchNameFilter = ~this.branchNameRegex } diff --git a/src/main/groovy/com/entagen/jenkins/Main.groovy b/src/main/groovy/com/entagen/jenkins/Main.groovy index 50a99a4f..20f0b31b 100644 --- a/src/main/groovy/com/entagen/jenkins/Main.groovy +++ b/src/main/groovy/com/entagen/jenkins/Main.groovy @@ -19,8 +19,11 @@ class Main { r: [longOpt: 'view-regex', required: false, args: 1, argName: 'viewRegex', description: "Supply a custom regex to be applied to any generated views, overriding the default template regex - gradle flag: -DviewRegex="], k: [longOpt: 'no-delete', required: false, args: 0, argName: 'noDelete', description: "Do not delete (keep) branches and views - gradle flag -DnoDelete=true"], f: [longOpt: 'filter-branch-names', required: false, args: 1, argName: 'branchNameRegex', description: "Only branches matching the regex will be accepted - gradle flag: -DbranchNameRegex="], - usr: [longOpt: 'jenkins-user', required: false, args: 1, argName: 'jenkinsUser', description: "Jenkins username - gradle flag -DjenkinsUser="], - pwd: [longOpt: 'jenkins-password', required: false, args: 1, argName: 'jenkinsPassword', description: "Jenkins password - gradle flag -DjenkinsPassword="] + e: [longOpt: 'enable-job', required: false, args: 1, argName: 'enableJob', description: "When creating a new job, enable it even if template job was disabled - gradle flag: -DenableJob=true"], + usr: [longOpt: 'jenkins-user', required: false, args: 1, argName: 'jenkinsUser', description: "Jenkins username - gradle flag -DjenkinsUser="], + pwd: [longOpt: 'jenkins-password', required: false, args: 1, argName: 'jenkinsPassword', description: "Jenkins password - gradle flag -DjenkinsPassword="], + days: [longOpt: 'days', required: false, args: 1, argName: 'days', description: "Creates jobs with commits within the specified number of days - gradle flag -Ddays=5"], + dlc: [longOpt: 'disable-last-commit', required: false, args: 1, argName: 'disableLastCommit', description: "Disables the creation of jobs based on last commit date - gradle flag = -DdisableLastCommit=true"] ] public static void main(String[] args) {