diff --git a/README.md b/README.md index 3600fe7..c38db69 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,9 @@ To work with Jenkins, you MUST install the following jenkins plugins first. 1. [Jenkins GIT plugin](https://wiki.jenkins-ci.org/display/JENKINS/Git+Plugin) 2. [Post build task](https://wiki.jenkins-ci.org/display/JENKINS/Post+build+task) 3. [Mailer Plugin](https://wiki.jenkins-ci.org/display/JENKINS/Mailer) (optional, if you want email notifications) +4. In order to have PR verify builds, your jenkins nodes must be able to create a merge commit, meaning your jenkins users should have a ~/.gitconfig file with a user/email set. The commits are thrown away so the value doesn't matter. -If either of these are missing, things won't work. +If any of these are missing, things won't work. # USER GUIDE @@ -22,7 +23,7 @@ requests are created. ## INITIAL CONFIG After installing stashbot, you will need to do the following as a system -administrator: +administrator in stash: * Create a jenkins server configuration (one for each jenkins server you connect to) by clicking on "Stashbot Jenkins Admin" under the administration page * You will need to give stashbot a username/password to access jenkins which has permission to create jobs @@ -169,6 +170,8 @@ Not every released version will necessarily be put on the Atlassian Marketplace, ## KNOWN BUGS +* Calls to user(null) in RepositoryCloneLinksRequest.Builder() may be broken in Stash 3.11+ + * Removed them for SSH but haven't tested if they need to be removed for HTTP URLs also yet... * JenkinsManager.updateAllJobs() and createMissingJobs() are untested. ## PLANNED FEATURES diff --git a/bin/install-plugin-sdk-linux.sh b/bin/install-plugin-sdk-linux.sh index 54b96c7..420769b 100755 --- a/bin/install-plugin-sdk-linux.sh +++ b/bin/install-plugin-sdk-linux.sh @@ -1,7 +1,7 @@ #!/bin/bash -# Version 4.2.20 -DOWNLOAD_URL="https://marketplace.atlassian.com/download/plugins/atlassian-plugin-sdk-tgz/version/42230" +# Version 5.0.13 +DOWNLOAD_URL="https://marketplace.atlassian.com/download/plugins/atlassian-plugin-sdk-tgz/version/42260" # To find new URLs, see: https://marketplace.atlassian.com/plugins/atlassian-plugin-sdk-tgz/versions INSTALL_BIN=`pwd`/.sdk.tar.gz diff --git a/libs/com/offbytwo/jenkins/jenkins-client/0.3.0.p1/jenkins-client-0.3.0.p1.jar b/libs/com/offbytwo/jenkins/jenkins-client/0.3.0.p1/jenkins-client-0.3.0.p1.jar new file mode 100644 index 0000000..ed2758b Binary files /dev/null and b/libs/com/offbytwo/jenkins/jenkins-client/0.3.0.p1/jenkins-client-0.3.0.p1.jar differ diff --git a/libs/com/offbytwo/jenkins/jenkins-client/0.3.0.p1/jenkins-client-0.3.0.p1.jar.md5 b/libs/com/offbytwo/jenkins/jenkins-client/0.3.0.p1/jenkins-client-0.3.0.p1.jar.md5 new file mode 100644 index 0000000..29a248d --- /dev/null +++ b/libs/com/offbytwo/jenkins/jenkins-client/0.3.0.p1/jenkins-client-0.3.0.p1.jar.md5 @@ -0,0 +1 @@ +b4e796a2623b09ade8aeb83b8687ed0c \ No newline at end of file diff --git a/libs/com/offbytwo/jenkins/jenkins-client/0.3.0.p1/jenkins-client-0.3.0.p1.jar.sha1 b/libs/com/offbytwo/jenkins/jenkins-client/0.3.0.p1/jenkins-client-0.3.0.p1.jar.sha1 new file mode 100644 index 0000000..09b1a7e --- /dev/null +++ b/libs/com/offbytwo/jenkins/jenkins-client/0.3.0.p1/jenkins-client-0.3.0.p1.jar.sha1 @@ -0,0 +1 @@ +f5d68197a3c910db6738dcf6ff2c48f84e6da157 \ No newline at end of file diff --git a/libs/com/offbytwo/jenkins/jenkins-client/0.3.0.p1/jenkins-client-0.3.0.p1.pom b/libs/com/offbytwo/jenkins/jenkins-client/0.3.0.p1/jenkins-client-0.3.0.p1.pom new file mode 100644 index 0000000..f73b5b0 --- /dev/null +++ b/libs/com/offbytwo/jenkins/jenkins-client/0.3.0.p1/jenkins-client-0.3.0.p1.pom @@ -0,0 +1,64 @@ + + + 4.0.0 + com.offbytwo.jenkins + jenkins-client + 0.3.0.p1 + + + com.fasterxml.jackson.core + jackson-annotations + 2.3.4 + runtime + + + com.fasterxml.jackson.core + jackson-core + 2.3.4 + runtime + + + com.fasterxml.jackson.core + jackson-databind + 2.3.4 + runtime + + + dom4j + dom4j + 1.6.1 + runtime + + + org.jvnet.hudson + xstream + 1.4.7-jenkins-1 + runtime + + + com.google.guava + guava + 17.0 + runtime + + + commons-lang + commons-lang + 2.6 + runtime + + + commons-io + commons-io + 2.4 + runtime + + + org.apache.httpcomponents + httpclient + 4.2.2 + runtime + + + diff --git a/libs/com/offbytwo/jenkins/jenkins-client/0.3.0.p1/jenkins-client-0.3.0.p1.pom.md5 b/libs/com/offbytwo/jenkins/jenkins-client/0.3.0.p1/jenkins-client-0.3.0.p1.pom.md5 new file mode 100644 index 0000000..bb19120 --- /dev/null +++ b/libs/com/offbytwo/jenkins/jenkins-client/0.3.0.p1/jenkins-client-0.3.0.p1.pom.md5 @@ -0,0 +1 @@ +d016f9109a907f19105ef34f4f5b2929 \ No newline at end of file diff --git a/libs/com/offbytwo/jenkins/jenkins-client/0.3.0.p1/jenkins-client-0.3.0.p1.pom.sha1 b/libs/com/offbytwo/jenkins/jenkins-client/0.3.0.p1/jenkins-client-0.3.0.p1.pom.sha1 new file mode 100644 index 0000000..0497aa2 --- /dev/null +++ b/libs/com/offbytwo/jenkins/jenkins-client/0.3.0.p1/jenkins-client-0.3.0.p1.pom.sha1 @@ -0,0 +1 @@ +1ec73efa618ade099c6d865595adc2917adfd8e2 \ No newline at end of file diff --git a/libs/com/offbytwo/jenkins/jenkins-client/maven-metadata.xml b/libs/com/offbytwo/jenkins/jenkins-client/maven-metadata.xml new file mode 100644 index 0000000..d2acddc --- /dev/null +++ b/libs/com/offbytwo/jenkins/jenkins-client/maven-metadata.xml @@ -0,0 +1,13 @@ + + + com.offbytwo.jenkins + jenkins-client + + 0.3.0.p1 + 0.3.0.p1 + + 0.3.0.p1 + + 20151016050210 + + diff --git a/pom.xml b/pom.xml index 902068e..b1b2d83 100644 --- a/pom.xml +++ b/pom.xml @@ -12,6 +12,13 @@ stashbot Stashbot is a plugin for Atlassian Stash that makes continuous integration via jenkins easy and self-servicable for end-users. atlassian-plugin + + + stashbot-internal + stashbot-internal + file://${project.basedir}/libs + + @@ -127,7 +134,7 @@ com.offbytwo.jenkins jenkins-client - 0.1.5 + 0.3.0.p1 @@ -212,9 +219,9 @@ - 3.6.0 - 3.6.0 - tomcat7x + 3.11.4 + 3.11.4 + tomcat8x com.atlassian.auiplugin:ajs + com.atlassian.auiplugin:aui-experimental-expander + com.atlassian.auiplugin:aui-experimental-iconfont + com.atlassian.auiplugin:aui-experimental-tooltips + com.atlassian.auiplugin:aui-form-notification + com.atlassian.auiplugin:aui-form-validation + com.atlassian.auiplugin:dialog2 diff --git a/src/main/resources/css/stashbot.css b/src/main/resources/css/stashbot.css index b6c4a4f..a10d230 100644 --- a/src/main/resources/css/stashbot.css +++ b/src/main/resources/css/stashbot.css @@ -3,3 +3,6 @@ input.palantir-stashbot-disabled, span.palantir-stashbot-disabled { color:#999999; } +dt { + font-family: monospaced; +} diff --git a/src/main/resources/jenkins-publish-job.vm b/src/main/resources/jenkins-publish-job.vm index a4a5574..6e5257b 100644 --- a/src/main/resources/jenkins-publish-job.vm +++ b/src/main/resources/jenkins-publish-job.vm @@ -25,6 +25,12 @@ This is the default publish job created automatically by stashbot, and cannot be changed in Jenkins. Stash Project Link: <a href="$esc.xml($cleanRepositoryUrl)">$esc.xml($cleanRepositoryUrl)</a> + + $publishBuildExpiryDays + $publishBuildExpiryNumber + -1 + -1 + false @@ -87,7 +93,7 @@ #if ( $isPinned ) - $label + $esc.xml($label) false #else true @@ -98,6 +104,9 @@ true + + $esc.xml($globalPrebuildCommand) + (git reset --hard HEAD && git clean -fdx) || (echo "SETUP exited with status $? ; FAILURE1" ; /bin/false) @@ -137,6 +146,17 @@ false + + + + Build timed out \(after $buildTimeout minutes\) + AND + + + false + false + + #if ($isJunit) @@ -186,5 +206,12 @@ #end - + + + + $buildTimeout + + + + diff --git a/src/main/resources/jenkins-verify-job.vm b/src/main/resources/jenkins-verify-job.vm index fe579f4..e0b1d64 100644 --- a/src/main/resources/jenkins-verify-job.vm +++ b/src/main/resources/jenkins-verify-job.vm @@ -23,6 +23,12 @@ This is the default verify job created automatically by stashbot, and cannot be changed in Jenkins. Stash Project Link: <a href="$esc.xml($cleanRepositoryUrl)">$esc.xml($cleanRepositoryUrl)</a> + + $verifyBuildExpiryDays + $verifyBuildExpiryNumber + -1 + -1 + false @@ -85,7 +91,7 @@ #if ( $isPinned ) - $label + $esc.xml($label) false #else true @@ -96,6 +102,9 @@ true + + $esc.xml($globalPrebuildCommand) + (git reset --hard HEAD && git clean -fdx) || (echo "SETUP exited with status $? ; FAILURE1" ; /bin/false) @@ -135,6 +144,17 @@ false + + + + Build timed out \(after $buildTimeout minutes\) + AND + + + false + false + + #if ($isJunit) @@ -184,5 +204,12 @@ #end - + + + + $buildTimeout + + + + diff --git a/src/main/resources/jenkins-verify-pull-request-job.vm b/src/main/resources/jenkins-verify-pull-request-job.vm index da1ac8e..a52d4b3 100644 --- a/src/main/resources/jenkins-verify-pull-request-job.vm +++ b/src/main/resources/jenkins-verify-pull-request-job.vm @@ -31,6 +31,12 @@ This is the default verify job created automatically by stashbot, and cannot be changed in Jenkins. Stash Project Link: <a href="$esc.xml($cleanRepositoryUrl)">$esc.xml($cleanRepositoryUrl)</a> + + $verifyBuildExpiryDays + $verifyBuildExpiryNumber + -1 + -1 + false @@ -108,7 +114,7 @@ #if ( $isPinned ) - $label + $esc.xml($label) false #else true @@ -119,6 +125,9 @@ true + + $esc.xml($globalPrebuildCommand) + (git reset --hard HEAD && git clean -fdx) || (echo "SETUP exited with status $? ; FAILURE1" ; /bin/false) @@ -132,7 +141,7 @@ set +x -git fetch $mergeRefUrl $mergeRef && git merge --no-ff $mergeHead || /bin/false || (echo "BUILD FAILURE$?" && /bin/false) +git merge --no-ff $mergeHead || /bin/false || (echo "BUILD FAILURE$?" && /bin/false) set -x @@ -164,6 +173,17 @@ set -x false + + + + Build timed out \(after $buildTimeout minutes\) + AND + + + false + false + + #if ($isJunit) @@ -213,5 +233,12 @@ set -x #end - + + + + $buildTimeout + + + + diff --git a/src/main/resources/js/stashbot.js b/src/main/resources/js/stashbot.js index 6d35830..e75d5aa 100644 --- a/src/main/resources/js/stashbot.js +++ b/src/main/resources/js/stashbot.js @@ -1,7 +1,23 @@ +require(['aui/form-notification']); +require(['aui/form-validation']); require(['jquery'], function($) { console.debug("Injecting JS to disable dropdown") $(window).load(function() { + + // Activate tooltip on any item with this class + AJS.$(".tooltip-stashbot-class").tooltip(); + + AJS.$("#stashbot-howto-button").click(function(e) { + e.preventDefault(); + AJS.dialog2("#stashbot-howto-dialog").show(); + }); + + AJS.$("#stashbot-howto-dialog-close-button").click(function(e) { + e.preventDefault(); + AJS.dialog2("#stashbot-howto-dialog").hide() + }); + console.debug("Detecting if jenkins server config is locked or not") locked = $("#isJenkinsServerLocked") if (locked.text() == "locked") { diff --git a/src/main/resources/static/jenkins-configuration-panel.soy b/src/main/resources/static/jenkins-configuration-panel.soy index b1602e3..ee95fd4 100644 --- a/src/main/resources/static/jenkins-configuration-panel.soy +++ b/src/main/resources/static/jenkins-configuration-panel.soy @@ -6,6 +6,7 @@ * @param error * @param notice * @param authenticationModeData + * @param defaultJenkinsConfig * Xparam authenticationModeDataSelected **/ {template .jenkinsConfigurationPanel} @@ -16,203 +17,394 @@ {if $error} -
ERROR: {$error}
+ {call widget.aui.message.error} + {param title: 'ERROR' /} + {param content} + {$error} + {/param} + {/call} {/if} {if $notice} -
NOTICE: {$notice}
+ {call widget.aui.message.warning} + {param title: 'NOTICE' /} + {param content} + {$notice} + {/param} + {/call} {/if} {call aui.group.group} {param content} {call aui.group.item} {param content} -

Stashbot Administrative Tasks

-
    -
  • Create any plans that don't already exist HERE
  • -
  • Update/Create all plans HERE
  • -
+

{{stash_i18n('stash.web.repository.stashbot.heading', 'Stashbot Jenkins Settings')}}

{/param} {/call} {/param} {/call} {call aui.group.group} {param content} - {call aui.group.item} - {param content} -

{{stash_i18n('stash.web.repository.stashbot.heading', 'Stashbot Jenkins Settings')}}

- {/param} - {/call} +
+ + {foreach $jenkinsConfig in $jenkinsConfigs} +
+ {call aui.form.form} + {param action: $relUrl /} + {param content} + {call aui.group.group} + {param content} + {call aui.form.textField} + {param id: 'name' /} + {param labelContent: stash_i18n('stash.web.stash.jenkins.name.label', 'Jenkins Server Name') /} + {param value: $jenkinsConfig.name /} + {param descriptionText: stash_i18n('stash.web.stash.jenkins.name.description', 'This name will be used by users setting up Stashbot to pick a Jenkins server.') /} + {/call} + {call aui.form.checkboxField} + {param legendContent: stash_i18n('stash.web.stash.locked.button.description', 'Force as Default Server') /} + {param descriptionText: 'Locking this Jenkins server forces repository owners to use this Jenkins server configuration by default. For a repo to use a different server, a System Admin needs to change it for them.' /} + {param fields: [[ + 'id': 'locked', + 'labelText': stash_i18n('stash.web.stash.locked.button.label', 'Locked'), + 'isChecked': $jenkinsConfig.locked + ]] /} + {/call} + {/param} + {/call} + + {call aui.group.group} + {param content} +

Jenkins Settings

+ {call aui.form.textField} + {param id: 'url' /} + {param labelContent: stash_i18n('stash.web.stash.jenkins.url.label', 'Server URL') /} + {param value: $jenkinsConfig.url /} + {param descriptionText: stash_i18n('stash.web.stash.jenkins.url.description', 'Jenkins URL (e.g. http://jenkins.example.com:1234/)') /} + {/call} + {call aui.form.textField} + {param id: 'username' /} + {param labelContent: stash_i18n('stash.web.stash.jenkins.username.label', 'Username') /} + {param value: $jenkinsConfig.username /} + {/call} + {call aui.form.passwordField} + {param id: 'password' /} + {param labelContent: stash_i18n('stash.web.stash.jenkins.password.label', 'Password') /} + {param value: $jenkinsConfig.password /} + {/call} + {call aui.form.textField} + {param id: 'prefixTemplate' /} + {param labelContent: stash_i18n('stash.web.stash.prefixTemplate.label', 'Job Folder') /} + {param value: $jenkinsConfig.prefixTemplate /} + {param descriptionText: stash_i18n('stash.web.stash.prefixTemplate.description', 'The folder Stashbot will place jobs in Jenkins. If you are not using the Jenkins Folders plugin, or do not want to use subfolders, just use /. The folder can be specified using the template variables $project and $repo') /} + {/call} + {call aui.form.textField} + {param id: 'jobTemplate' /} + {param labelContent: stash_i18n('stash.web.stash.jobTemplate.label', 'Job Name Template') /} + {param value: $jenkinsConfig.jobTemplate /} + {param descriptionText: stash_i18n('stash.web.stash.jobTemplate.description', 'The name of the jobs created. It supports template variables $project and $repo. The job type will be appended at the end.') /} + {/call} + {/param} + {/call} + + {call aui.group.group} + {param content} +

Stash Settings

+ {call aui.form.selectField} + {param id: 'authenticationMode' /} + {param labelContent: stash_i18n('stash.web.stash.authenticationMode.label', 'Authentication Mode') /} + {param options: $authenticationModeData[$jenkinsConfig.name] /} + {param value: $jenkinsConfig.authenticationModeStr /} + {param descriptionText: 'The authentication mode to use for jenkins to talk back to stash. If you select Manual Credentials, create it in jenkins first then add the UUID of the credential in the password field, while using a valid username for stash in the username field (which is still used for comments on pull requests, etc.)' /} + {/call} + {call aui.form.textField} + {param id: 'stashUsername' /} + {param labelContent: stash_i18n('stash.web.stash.jenkins.stashusername.label', 'Username') /} + {param value: $jenkinsConfig.stashUsername /} + {param descriptionText: stash_i18n('stash.web.stash.jenkins.stashusername.description', 'Stash user that can clone the appropriate repos. This user will also comment on PRs. If the user does not exist, Stashbot will create it with the password below.') /} + {/call} + {call aui.form.passwordField} + {param id: 'stashPassword' /} + {param labelContent: stash_i18n('stash.web.stash.jenkins.stashpassword.label', 'Password or Jenkins Cred ID') /} + {param value: $jenkinsConfig.stashPassword /} + {param descriptionText: stash_i18n('stash.web.stash.jenkins.stashpassword.description', 'Password for the username. In Credential UUID mode, it is a Jenkins Credential ID. Supports $password and $repo replacement in Credential UUID mode.') /} + {/call} + {/param} + {/call} + + {call aui.group.group} + {param content} +

Job Settings

+ {call aui.form.textField} + {param id: 'maxVerifyChain' /} + {param labelContent: stash_i18n('stash.web.stash.maxVerifyChain.label', 'Maximum Commit Verifications') /} + {param value: ($jenkinsConfig.maxVerifyChain == 0 ? '0' : $jenkinsConfig.maxVerifyChain) /} + {param descriptionText: stash_i18n('stash.web.stash.maxVerifyChain.description', 'The maximum number of builds to trigger for a single push. Individual repositories also have this setting, but they are limited by the setting of the jenkins server as well. Set to 0 for "no limit". You probably want to set this to between 50% and 200% of the number of executors your jenkins instance has, depending on how long your build takes, your expected latency, and load.') /} + {/call} + {call aui.form.textField} + {param id: 'defaultTimeout' /} + {param labelContent: stash_i18n('stash.web.stash.defaultTimeout.label', 'Default Build Timeout') /} + {param value: $jenkinsConfig.defaultTimeout /} + {param descriptionText: stash_i18n('stash.web.stash.defaultTimeout.description', 'The default timeout value (in minutes from 5 to 10080) for a Jenkins job created by Stashbot. This can be overriden on the repo level.') /} + {/call} + {call aui.form.textField} + {param id: 'globalLabel' /} + {param labelContent: 'Global Job Label' /} + {param value: $jenkinsConfig.globalLabel /} + {param descriptionText: 'The default label all Stashbot jobs should have on this Jenkins server. This is useful for Jenkins servers with multiple pools of nodes. For no default label, leave blank.' /} + {/call} + {call aui.form.textareaField} + {param id: 'globalPrebuild' /} + {param labelContent: stash_i18n('stash.web.stash.globalPrebuild.label', 'Global Pre-build Commands') /} + {param value: $jenkinsConfig.globalPrebuildCommand /} + {param descriptionText: stash_i18n('stash.web.stash.globalPrebuild.description', 'Command or commands to run before all builds. Useful for cleanup and global prep.') /} + {/call} + {/param} + {/call} + + {call aui.group.group} + {param content} + {call aui.form.buttons} + {param content} + {call aui.form.submit} + {param id: 'submit' /} + {param text: 'Save' /} + {param type: 'submit' /} + {/call} + {call stash.buttons.button} + {param id: 'delete' /} + {param buttonText: 'Delete Entry ' + $jenkinsConfig.name /} + {param href: $relUrl + '/delete/' + $jenkinsConfig.name /} + {/call} + {/param} + {/call} + {/param} + {/call} + + + {/param} + {/call} +
+ {/foreach} + +
+ {call aui.form.form} + {param action: $relUrl /} + {param content} + + {call aui.group.group} + {param content} + {call aui.form.textField} + {param id: 'name' /} + {param labelContent: stash_i18n('stash.web.stash.jenkins.name.label', 'Jenkins Server Name') /} + {param placeholderText: 'enter name here [a-zA-Z0-9]+' /} + {param descriptionText: stash_i18n('stash.web.stash.jenkins.name.description', 'This name will be used by users setting up Stashbot to pick a Jenkins server.') /} + {/call} + {call aui.form.checkboxField} + {param legendContent: stash_i18n('stash.web.stash.locked.button.description', 'Force as Default Server') /} + {param descriptionText: 'Locking this Jenkins server forces repository owners to use this Jenkins server configuration by default. For a repo to use a different server, a System Admin needs to change it for them.' /} + {param fields: [[ + 'id': 'locked', + 'labelText': stash_i18n('stash.web.stash.locked.button.label', 'Locked'), + ]] /} + {/call} + {/param} + {/call} + + {call aui.group.group} + {param content} +

Jenkins Settings

+ {call aui.form.textField} + {param id: 'url' /} + {param labelContent: stash_i18n('stash.web.stash.jenkins.url.label', 'Server URL') /} + {param placeholderText: 'http://jenkins.example.com:8080/' /} + {param descriptionText: stash_i18n('stash.web.stash.jenkins.url.description', 'Jenkins URL (e.g. http://jenkins.example.com:1234/)') /} + {/call} + {call aui.form.textField} + {param id: 'username' /} + {param labelContent: stash_i18n('stash.web.stash.jenkins.username.label', 'Username') /} + {param value: 'jenkins_user' /} + {/call} + {call aui.form.passwordField} + {param id: 'password' /} + {param labelContent: stash_i18n('stash.web.stash.jenkins.password.label', 'Password') /} + {param value: 'jenkins_password' /} + {/call} + {call aui.form.textField} + {param id: 'prefixTemplate' /} + {param labelContent: stash_i18n('stash.web.stash.prefixTemplate.label', 'Job Folder') /} + {param value: '/' /} + {param descriptionText: stash_i18n('stash.web.stash.prefixTemplate.description', 'The folder Stashbot will place jobs in Jenkins. If you are not using the Jenkins Folders plugin, or do not want to use subfolders, just use /. The folder can be specified using the template variables $project and $repo') /} + {/call} + {call aui.form.textField} + {param id: 'jobTemplate' /} + {param labelContent: stash_i18n('stash.web.stash.jobTemplate.label', 'Job Name Template') /} + {param value: '$project_$repo' /} + {param descriptionText: stash_i18n('stash.web.stash.jobTemplate.description', 'The name of the jobs created. It supports template variables $project and $repo. The job type will be appended at the end.') /} + {/call} + {/param} + {/call} + + {call aui.group.group} + {param content} +

Stash Settings

+ {call aui.form.selectField} + {param id: 'authenticationMode' /} + {param labelContent: stash_i18n('stash.web.stash.authenticationMode.label', 'Authentication Mode') /} + {param options: $authenticationModeData['default'] /} + {param descriptionText: 'The authentication mode to use for jenkins to talk back to stash. If you select Manual Credentials, create it in jenkins first then add the UUID of the credential in the password field, while using a valid username for stash in the username field (which is still used for comments on pull requests, etc.)' /} + {/call} + {call aui.form.textField} + {param id: 'stashUsername' /} + {param labelContent: stash_i18n('stash.web.stash.jenkins.stashusername.label', 'Username') /} + {param value: 'stash_user' /} + {param descriptionText: stash_i18n('stash.web.stash.jenkins.stashusername.description', 'Stash user that can clone the appropriate repos. This user will also comment on PRs. If the user does not exist, Stashbot will create it with the password below.') /} + {/call} + {call aui.form.passwordField} + {param id: 'stashPassword' /} + {param labelContent: stash_i18n('stash.web.stash.jenkins.stashpassword.label', 'Password or Jenkins Cred ID') /} + {param value: 'stash_password' /} + {param descriptionText: stash_i18n('stash.web.stash.jenkins.stashpassword.description', 'Password for the username. In Credential UUID mode, it is a Jenkins Credential ID. Supports $password and $repo replacement in Credential UUID mode.') /} + {/call} + {/param} + {/call} + + + {call aui.group.group} + {param content} +

Job Settings

+ {call aui.form.textField} + {param id: 'maxVerifyChain' /} + {param labelContent: stash_i18n('stash.web.stash.maxVerifyChain.label', 'Maximum Commit Verifications') /} + {param value: '10' /} + {param descriptionText: stash_i18n('stash.web.stash.maxVerifyChain.description', 'The maximum number of builds to trigger for a single push. Individual repositories also have this setting, but they are limited by the setting of the jenkins server as well. Set to 0 for "no limit". You probably want to set this to between 50% and 200% of the number of executors your jenkins instance has, depending on how long your build takes, your expected latency, and load.') /} + {/call} + {call aui.form.textField} + {param id: 'defaultTimeout' /} + {param labelContent: stash_i18n('stash.web.stash.defaultTimeout.label', 'Default Build Timeout') /} + {param value: '240' /} + {param descriptionText: stash_i18n('stash.web.stash.defaultTimeout.description', 'The default timeout value (in minutes from 5 to 10080) for a Jenkins job created by Stashbot. This can be overriden on the repo level.') /} + {/call} + {call aui.form.textField} + {param id: 'globalLabel' /} + {param labelContent: 'Global Job Label' /} + {param value: '' /} + {param descriptionText: 'The default label all Stashbot jobs should have on this Jenkins server. This is useful for Jenkins servers with multiple pools of nodes. For no default label, leave blank.' /} + {/call} + {call aui.form.textareaField} + {param id: 'globalPrebuild' /} + {param labelContent: stash_i18n('stash.web.stash.globalPrebuild.label', 'Global Pre-build Commands') /} + {param value: '/bin/true' /} + {param descriptionText: stash_i18n('stash.web.stash.globalPrebuild.description', 'Command or commands to run before all builds. Useful for cleanup and global prep.') /} + {/call} + {/param} + {/call} + + + {call aui.form.buttons} + {param content} + {call aui.form.submit} + {param id: 'submit' /} + {param text: 'Save' /} + {param type: 'submit' /} + {/call} + {/param} + {/call} + + {/param} + {/call} +
+ +
+ {/param} {/call} + +

 

+ {call aui.group.group} {param content} - {foreach $jenkinsConfig in $jenkinsConfigs} -

{$jenkinsConfig.name}

- {call aui.form.form} - {param action: $relUrl /} - {param content} - {call aui.form.textField} - {param id: 'name' /} - {param labelContent: stash_i18n('stash.web.stash.jenkins.name.label', 'Jenkins Server Name') /} - {param value: $jenkinsConfig.name /} - {param descriptionText: stash_i18n('stash.web.stash.jenkins.name.description', 'Jenkins Server Name (referred to in the repository configuration)') /} - {/call} - {call aui.form.textField} - {param id: 'url' /} - {param labelContent: stash_i18n('stash.web.stash.jenkins.url.label', 'Jenkins URL') /} - {param value: $jenkinsConfig.url /} - {param descriptionText: stash_i18n('stash.web.stash.jenkins.url.description', 'Jenkins URL (e.g. http://jenkins.example.com:1234/)') /} - {/call} - {call aui.form.selectField} - {param id: 'authenticationMode' /} - {param labelContent: stash_i18n('stash.web.stash.authenticationMode.label', 'Stash Authentication Mode') /} - {param options: $authenticationModeData[$jenkinsConfig.name] /} - {param value: $jenkinsConfig.authenticationModeStr /} - {param descriptionText: stash_i18n('stash.web.stash.authenticationMode.description', 'Stash Authentication Mode') /} - {/call} - {call aui.form.textField} - {param id: 'username' /} - {param labelContent: stash_i18n('stash.web.stash.jenkins.username.label', 'Jenkins Username') /} - {param value: $jenkinsConfig.username /} - {param descriptionText: stash_i18n('stash.web.stash.jenkins.description', 'Jenkins Username') /} - {/call} - {call aui.form.passwordField} - {param id: 'password' /} - {param labelContent: stash_i18n('stash.web.stash.jenkins.password.label', 'Jenkins Password') /} - {param value: $jenkinsConfig.password /} - {param descriptionText: stash_i18n('stash.web.stash.jenkins.description', 'Jenkins Password') /} - {/call} - {call aui.form.textField} - {param id: 'stashUsername' /} - {param labelContent: stash_i18n('stash.web.stash.jenkins.stashusername.label', 'Stash Username') /} - {param value: $jenkinsConfig.stashUsername /} - {param descriptionText: stash_i18n('stash.web.stash.jenkins.stashusername.description', 'Stash Username') /} - {/call} - {call aui.form.passwordField} - {param id: 'stashPassword' /} - {param labelContent: stash_i18n('stash.web.stash.jenkins.stashpassword.label', 'Stash Password') /} - {param value: $jenkinsConfig.stashPassword /} - {param descriptionText: stash_i18n('stash.web.stash.jenkins.stashpassword.description', 'Stash Password') /} - {/call} - {call aui.form.textField} - {param id: 'maxVerifyChain' /} - {param labelContent: stash_i18n('stash.web.stash.maxVerifyChain.label', 'Maximum number of commits to verify on a single push') /} - {param value: ($jenkinsConfig.maxVerifyChain == 0 ? '0' : $jenkinsConfig.maxVerifyChain) /} - {param descriptionText: stash_i18n('stash.web.stash.maxVerifyChain.description', 'Maximum number of commits to verify on a single push') /} - {/call} - {call aui.form.checkboxField} - {param legendContent: stash_i18n('stash.web.stash.locked.button.description', 'Lock projects into this configuration') /} - {param fields: [[ - 'id': 'locked', - 'labelText': stash_i18n('stash.web.stash.locked.button.label', 'Locked'), - 'isChecked': $jenkinsConfig.locked - ]] /} - {/call} - {call aui.form.buttons} - {param content} - {call aui.form.submit} - {param id: 'submit' /} - {param text: 'Save' /} - {param type: 'submit' /} - {/call} - {/param} - {/call} - {call stash.buttons.button} - {param id: 'delete' /} - {param buttonText: 'Delete Entry ' + $jenkinsConfig.name /} - {param href: $relUrl + '/delete/' + $jenkinsConfig.name /} - {/call} - {/param} - {/call} - {/foreach} -

New Jenkins Server

- {call aui.form.form} - {param action: $relUrl /} - {param content} - {call aui.form.textField} - {param id: 'name' /} - {param labelContent: stash_i18n('stash.web.stash.jenkins.name.label', 'Jenkins Server Name') /} - {param value: 'enter name here [a-zA-Z0-9]+' /} - {param descriptionText: stash_i18n('stash.web.stash.jenkins.name.description', 'Jenkins Server Name (referred to in the repository configuration)') /} - {/call} - {call aui.form.textField} - {param id: 'url' /} - {param labelContent: stash_i18n('stash.web.stash.jenkins.url.label', 'Jenkins URL') /} - {param value: 'http://jenkins.example.com:8080/' /} - {param descriptionText: stash_i18n('stash.web.stash.jenkins.url.description', 'Jenkins URL (e.g. http://jenkins.example.com:1234/)') /} - {/call} - {call aui.form.selectField} - {param id: 'authenticationMode' /} - {param labelContent: stash_i18n('stash.web.stash.authenticationMode.label', 'Stash Authentication Mode') /} - {param options: $authenticationModeData['default'] /} - {param descriptionText: stash_i18n('stash.web.stash.authenticationMode.description', 'Stash Authentication Mode') /} - {/call} - {call aui.form.textField} - {param id: 'username' /} - {param labelContent: stash_i18n('stash.web.stash.jenkins.username.label', 'Jenkins Username') /} - {param value: 'jenkins_user' /} - {param descriptionText: stash_i18n('stash.web.stash.jenkins.description', 'Jenkins Username') /} - {/call} - {call aui.form.passwordField} - {param id: 'password' /} - {param labelContent: stash_i18n('stash.web.stash.jenkins.password.label', 'Jenkins Password') /} - {param value: 'jenkins_password' /} - {param descriptionText: stash_i18n('stash.web.stash.jenkins.description', 'Jenkins Password') /} - {/call} - {call aui.form.textField} - {param id: 'stashUsername' /} - {param labelContent: stash_i18n('stash.web.stash.jenkins.stashusername.label', 'Stash Username') /} - {param value: 'stash_user' /} - {param descriptionText: stash_i18n('stash.web.stash.jenkins.stashusername.description', 'Stash Username') /} - {/call} - {call aui.form.passwordField} - {param id: 'stashPassword' /} - {param labelContent: stash_i18n('stash.web.stash.jenkins.stashpassword.label', 'Stash Password') /} - {param value: 'stash_password' /} - {param descriptionText: stash_i18n('stash.web.stash.jenkins.stashpassword.description', 'Stash Password') /} - {/call} - {call aui.form.textField} - {param id: 'maxVerifyChain' /} - {param labelContent: stash_i18n('stash.web.stash.maxVerifyChain.label', 'Maximum number of commits to verify on a single push') /} - {param value: '10' /} - {param descriptionText: stash_i18n('stash.web.stash.maxVerifyChain.description', 'Maximum number of commits to verify on a single push') /} - {/call} - {call aui.form.checkboxField} - {param legendContent: stash_i18n('stash.web.stash.locked.button.description', 'Lock projects into this configuration') /} - {param fields: [[ - 'id': 'locked', - 'labelText': stash_i18n('stash.web.stash.locked.button.label', 'Locked'), - ]] /} - {/call} - {call aui.form.buttons} - {param content} - {call aui.form.submit} - {param id: 'submit' /} - {param text: 'Save' /} - {param type: 'submit' /} - {/call} - {/param} - {/call} - {/param} +

Stashbot Administrative Tasks

+ {call aui.group.group} + {param content} + {call aui.group.group} + {param content} +

Create and Update

+ + {call stash.buttons.button} + {param id: 'button-create-missing-plans' /} + {param buttonText: 'Create Missing Plans' /} + {param href: $relUrl + '/create-new/.' /} + {/call} + + {call stash.buttons.button} + {param id: 'button-update-all-plans' /} + {param buttonText: 'Update/Create Plans' /} + {param href: $relUrl + '/reload-all/.' /} + {/call} + {/param} + {/call} + + {call aui.group.group} + {param content} +

Cleaning

+ Clean up Jenkins Jobs that haven't been run in a certain amount of days. + {call aui.form.form} + {param action: $relUrl + '/clean-jobs/' /} + {param method: 'get' /} + {param content} + + {call aui.form.textField} + {param id: 'age' /} + {param labelContent: stash_i18n('stash.web.stash.ageToClean.label', 'Age to Delete') /} + {param value: '90' /} + {/call} + + {call aui.form.checkboxField} + {param legendContent: stash_i18n('stash.web.stash.cleanjobsdryrun.button.legend', 'Dry Run') /} + {param fields: [[ + 'id': 'dry_run', + 'labelText': stash_i18n('stash.web.stash.cleanjobsdryrun.button.label', 'Enabled'), + 'isChecked': true + ]] /} + {/call} + + {call aui.form.checkboxField} + {param legendContent: stash_i18n('stash.web.stash.cleanjobsdeleteunused.button.legend', 'Include Unused Jobs') /} + {param descriptionText: 'Including unused builds means that any builds that have never run are deleted.' /} + {param fields: [[ + 'id': 'delete_unused', + 'labelText': stash_i18n('stash.web.stash.cleanjobsdeketeunused.button.label', 'Enabled'), + 'isChecked': false + ]] /} + {/call} + + {call aui.form.buttons} + {param content} + {call aui.form.submit} + {param id: 'submit' /} + {param text: 'Clean Jobs' /} + {param type: 'submit' /} + {/call} + {/param} + {/call} + + {/param} + {/call} + {/param} + {/call} + {/param} {/call} {/param} {/call} -
-

Configuring Jenkins:

-

-Jenkins configurations include the following fields: -

    -
  • name: The name users will see when they select this jenkins server
  • -
  • url: The URL for the jenkins instance. (e.g. https://jenkins.example.com:8080/)
  • -
  • Authentication Mode: The authentication mode to use for jenkins to talk back to stash. If you select Manual Credentials, create it in jenkins first then add the UUID of the credential in the password field, while using a valid username for stash in the username field (which is still used for comments on pull requests, etc.)
  • -
  • username: The username to use to log into jenkins (value is ignored if authentication is not enabled). -
  • password: The password to use to log into jenkins (value is ignored if authentication is not enabled). -
  • stashUsername: The username to use to log into stash from jenkins (for cloning repos and reporting build results). This account is automatically created if it does not exist already. It is recommended you generate a reasonable username/password pair. If you prefer for auditing purposes, you may use an account from crowd/LDAP by using the existing credentials in this field.
  • -
  • stashPassword: The password to use to log into stash from jenkins (same comment applies as for the username).
  • -
  • maxVerifyChain: The maximum number of builds to trigger for a single push. Individual repositories also have this setting, but they are limited by the setting of the jenkins server as well. Set to 0 for "no limit". You probably want to set this to between 50% and 200% of the number of executors your jenkins instance has, depending on how long your build takes, your expected latency, and load.
  • -
-

-
+ {/template} diff --git a/src/main/resources/static/repository-configuration-panel.soy b/src/main/resources/static/repository-configuration-panel.soy index 6924b56..82f0f91 100644 --- a/src/main/resources/static/repository-configuration-panel.soy +++ b/src/main/resources/static/repository-configuration-panel.soy @@ -1,6 +1,7 @@ {namespace plugin.page.stashbot} /** + * @param error * @param repository * @param ciEnabled * @param publishBranchRegex @@ -31,6 +32,15 @@ * @param verificationEnabled * @param verifyPREnabled * @param publishEnabled + * @param buildTimeout + * @param buildTimeoutMin + * @param buildTimeoutMax + * @param verifyBuildExpiryDays + * @param verifyBuildExpiryNumber + * @param publishBuildExpiryDays + * @param publishBuildExpiryNumber + * @param buildExpiryMaxDays + * @param buildExpiryMaxNumber * **/ {template .repositoryConfigurationPanel} @@ -40,7 +50,7 @@ - {{stash_i18n('stash.web.repository.git-ops.title', 'Stashbot settings for {0} / {1}', $repository.project.name, $repository.name)}} + {{stash_i18n('stash.web.repository.git-ops.title', 'Stashbot settings')}} {call aui.group.group} @@ -52,288 +62,593 @@ {/call} {/param} {/call} -{call aui.group.group} - {param content} - {call aui.form.form} - {param action: '' /} +{if $error} + {call widget.aui.message.error} + {param title: 'An error occured in saving config.' /} {param content} -

Local Settings

-

These are settings modify if the repo builds, where it builds, and when it builds.

- {call aui.form.checkboxField} - {param legendContent: stash_i18n('stash.web.stash.enable-ci-radio.button.description', 'Stashbot Repository Enable
(to enable stashbot for this repository, check this and at least one build type below)') /} - {param fields: [[ - 'id': 'ciEnabled', - 'labelText': stash_i18n('stash.web.stash.enable-ci-radio.button.label', 'Enabled'), - 'isChecked': $ciEnabled - ]] /} - {/call} - - {call aui.form.checkboxField} - {param legendContent: stash_i18n('stash.web.stash.enable-verification.button.description', 'Commit Verifies') /} - {param fields: [[ - 'id': 'verificationEnabled', - 'labelText': stash_i18n('stash.web.stash.enable-verification.button.label', 'Enabled'), - 'isChecked': $verificationEnabled - ]] /} - {/call} - {call aui.form.checkboxField} - {param legendContent: stash_i18n('stash.web.stash.enable-verify-pr.button.description', 'Pull Request Verifies') /} - {param fields: [[ - 'id': 'verifyPREnabled', - 'labelText': stash_i18n('stash.web.stash.enable-verify-pr.button.label', 'Enabled'), - 'isChecked': $verifyPREnabled - ]] /} - {/call} - {call aui.form.checkboxField} - {param legendContent: stash_i18n('stash.web.stash.enable-publish.button.description', 'Publishes') /} - {param fields: [[ - 'id': 'publishEnabled', - 'labelText': stash_i18n('stash.web.stash.enable-verification.button.label', 'Enabled'), - 'isChecked': $publishEnabled - ]] /} - {/call} - - {call aui.form.selectField} - {param id: 'jenkinsServerName' /} - {param labelContent: stash_i18n('stash.web.stash.jenkinsServerName.label', 'Jenkins Server') /} - {param options: $jenkinsServersData /} - {param value: $jenkinsServerName /} - {/call} - {call aui.form.textField} - {param id: 'publishBranchRegex' /} - {param labelContent: stash_i18n('stash.web.stash.publishBranchRegex.label', 'Regex for branches to publish') /} - {param value: $publishBranchRegex /} - {param descriptionText: stash_i18n('stash.web.stash.publishBranchRegex.description', '(anchored regular expression) Branches matching this regular expression will have the publish build command run on them by jenkins (e.g. "refs/heads/master" or "refs/heads/.*")') /} - {/call} - {call aui.form.textField} - {param id: 'verifyBranchRegex' /} - {param labelContent: stash_i18n('stash.web.stash.verifyBranchRegex.label', 'Regex for branches to verify') /} - {param value: $verifyBranchRegex /} - {param descriptionText: stash_i18n('stash.web.stash.verifyBranchRegex.description', '(anchored regular expression) Branches matching this regular expression will have the verify build command run on them by jenkins (e.g. "refs/heads/develop" or "refs/heads/.*")') /} - {/call} - {call aui.form.textField} - {param id: 'maxVerifyChain' /} - {param labelContent: stash_i18n('stash.web.stash.maxVerifyChain.label', 'Maximum number of commits to verify on a single push') /} - {param value: $maxVerifyChain /} - {/call} - {call aui.form.checkboxField} - {param legendContent: stash_i18n('stash.web.stash.rebuild-on-update-radio.button.description', 'Rebuild merge verifies when target branch updates') /} - {param fields: [[ - 'id': 'rebuildOnUpdate', - 'labelText': stash_i18n('stash.web.stash.enable-ci-radio.button.label', 'Enabled'), - 'isChecked': $rebuildOnUpdate - ]] /} - {/call} - {call aui.form.checkboxField} - {param legendContent: stash_i18n('stash.web.stash.strict-verify-mode.button.description', 'Enable Strict Verify Mode') /} - {param fields: [[ - 'id': 'isStrictVerifyMode', - 'labelText': stash_i18n('stash.web.stash.strict-verify-mode.button.label', 'Enabled'), - 'isChecked': $isStrictVerifyMode - ]] /} - {/call} - - -

Jenkins Settings

-

Modify what commands get run for builds, if there are tests, who gets notified, etc.

- - {call aui.form.textField} - {param id: 'prebuildCommand' /} - {param labelContent: stash_i18n('stash.web.stash.prebuildCommand.label', 'Command to run before all builds (and for PR verifies, before the merge)') /} - {param value: $prebuildCommand /} - {/call} - -

 

- - {call aui.form.textField} - {param id: 'publishBuildCommand' /} - {param labelContent: stash_i18n('stash.web.stash.publishBuildCommand.label', 'Command to run for a publish build') /} - {param value: $publishBuildCommand /} - {/call} - {call aui.form.checkboxField} - {param legendContent: stash_i18n('stash.web.stash.publish-pinned-checkbox.button.description', 'Pin publish builds to a label') /} - {param fields: [[ - 'id': 'isPublishPinned', - 'labelText': stash_i18n('stash.web.stash.enable-ci-radio.button.label', 'Pinned'), - 'isChecked': $isPublishPinned - ]] /} - {/call} - {call aui.form.textField} - {param id: 'publishLabel' /} - {param labelContent: stash_i18n('stash.web.stash.verifyLabel.label', 'Label to pin publish builds to') /} - {param value: $publishLabel /} - {param descriptionText: stash_i18n('stash.web.stash.verifyBranchRegex.description', 'Build node label to pin publish builds to') /} - {/call} - -

 

- - {call aui.form.textField} - {param id: 'verifyBuildCommand' /} - {param labelContent: stash_i18n('stash.web.stash.verifyBuildCommand.label', 'Command to run for a verify build') /} - {param value: $verifyBuildCommand /} - {/call} - {call aui.form.checkboxField} - {param legendContent: stash_i18n('stash.web.stash.verify-pinned-checkbox.button.description', 'Pin verify builds to a label') /} - {param fields: [[ - 'id': 'isVerifyPinned', - 'labelText': stash_i18n('stash.web.stash.enable-ci-radio.button.label', 'Pinned'), - 'isChecked': $isVerifyPinned - ]] /} - {/call} - {call aui.form.textField} - {param id: 'verifyLabel' /} - {param labelContent: stash_i18n('stash.web.stash.verifyLabel.label', 'Label to pin verify builds to') /} - {param value: $verifyLabel /} - {param descriptionText: stash_i18n('stash.web.stash.verifyBranchRegex.description', 'Build node label to pin verify builds to') /} - {/call} - -

 

- - {call aui.form.checkboxField} - {param legendContent: stash_i18n('stash.web.stash.junit-enabled.button.description', 'Junit Test Results') /} - {param fields: [[ - 'id': 'isJunit', - 'labelText': stash_i18n('stash.web.stash.enable-ci-radio.button.label', 'Enabled'), - 'isChecked': $isJunit - ]] /} - {/call} - {call aui.form.textField} - {param id: 'junitPath' /} - {param labelContent: stash_i18n('stash.web.stash.junitPath.label', 'Result Location') /} - {param value: $junitPath /} - {param descriptionText: stash_i18n('stash.web.stash.junitPath.description', 'Path to use for junit results (e.g. build/test-results/*.xml)') /} - {/call} - - {call aui.form.checkboxField} - {param legendContent: stash_i18n('stash.web.stash.artifacts-enabled.button.description', 'Artifact Archival') /} - {param fields: [[ - 'id': 'artifactsEnabled', - 'labelText': stash_i18n('stash.web.stash.enable-ci-radio.button.label', 'Enabled'), - 'isChecked': $artifactsEnabled - ]] /} - {/call} - {call aui.form.textField} - {param id: 'artifactsPath' /} - {param labelContent: stash_i18n('stash.web.stash.artifactsPath.label', 'Artifact Location') /} - {param value: $artifactsPath /} - {param descriptionText: stash_i18n('stash.web.stash.artifactsPath.description', 'Path to use for artifacts (e.g. **/*.log)') /} - {/call} - - -

 

- - {call aui.form.checkboxField} - {param legendContent: stash_i18n('stash.web.stash.email-enabled.button.description', 'E-mail notifications') /} - {param fields: [[ - 'id': 'isEmailNotificationsEnabled', - 'labelText': stash_i18n('stash.web.stash.enable-ci-radio.button.label', 'Enabled'), - 'isChecked': $isEmailNotificationsEnabled - ]] /} - {/call} - {call aui.form.textField} - {param id: 'emailRecipients' /} - {param labelContent: stash_i18n('stash.web.stash.emailRecipients.label', 'E-mail Recipients') /} - {param value: $emailRecipients /} - {/call} - {call aui.form.checkboxField} - {param legendContent: stash_i18n('stash.web.stash.emailForEveryUnstableBuild.button.description', 'E-mail Options') /} - {param fields: [[ - 'id': 'isEmailForEveryUnstableBuild', - 'labelText': stash_i18n('stash.web.stash.enable-ci-radio.button.label', 'Send e-mail for every unstable build'), - 'isChecked': $isEmailForEveryUnstableBuild - ]] /} - {/call} - {call aui.form.checkboxField} - {param legendContent: stash_i18n('stash.web.stash.emailSendToIndividuals.button.description', '') /} - {param fields: [[ - 'id': 'isEmailSendToIndividuals', - 'labelText': stash_i18n('stash.web.stash.enable-ci-radio.button.label', 'Send separate e-mails to individuals who broke the build'), - 'isChecked': $isEmailSendToIndividuals - ]] /} - {/call} - {call aui.form.checkboxField} - {param legendContent: stash_i18n('stash.web.stash.emailPerModuleEmail.button.description', '') /} - {param fields: [[ - 'id': 'isEmailPerModuleEmail', - 'labelText': stash_i18n('stash.web.stash.enable-ci-radio.button.label', 'Send e-mail for each failed module'), - 'isChecked': $isEmailPerModuleEmail - ]] /} - {/call} - -

 

- - {call aui.form.checkboxField} - {param legendContent: stash_i18n('stash.web.stash.preserveJenkinsJobConfig.label', 'Preserve Jenkins Job Config') /} - {param descriptionText: stash_i18n('stash.web.stash.preserveJenkinsJobConfig.description', 'See below for details.') /} - {param fields: [[ - 'id': 'isPreserveJenkinsJobConfig', - 'labelText': stash_i18n('stash.web.stash.preserveJenkinsJobConfig.button.label', 'Enabled'), - 'isChecked': $isPreserveJenkinsJobConfig - ]] /} - {/call} - -

 

- - {call aui.form.buttons} + {$error} + {/param} + {/call} +{/if} + +{call aui.form.form} + {param action: '' /} + {param content} + + {call aui.group.group} {param content} - {call aui.form.submit} - {param id: 'submit' /} - {param text: stash_i18n('stash.web.stash.ci-prefs.submit', 'Save') /} - {param type: 'submit' /} - {/call} + {call aui.form.checkboxField} + {param legendContent: stash_i18n('stash.web.stash.enable-ci-radio.button.description', 'Stashbot') /} + {param fields: [[ + 'id': 'ciEnabled', + 'labelText': stash_i18n('stash.web.stash.enable-ci-radio.button.label', 'Enabled'), + 'isChecked': $ciEnabled + ]] /} + {/call} + + What is Stashbot? + {/param} - {/call} + {/call} /* Top group end */ -

-
+

Publishing

+ {call aui.group.group} + {param content} + {call aui.form.checkboxField} + {param legendContent: stash_i18n('stash.web.stash.enable-publish.button.description', 'Publishes') /} + {param fields: [[ + 'id': 'publishEnabled', + 'labelText': stash_i18n('stash.web.stash.enable-verification.button.label', 'Enabled'), + 'isChecked': $publishEnabled + ]] /} + {/call} + {call aui.form.textField} + {param id: 'publishBranchRegex' /} + {param labelContent: stash_i18n('stash.web.stash.publishBranchRegex.label', 'Trigger Regex') /} + {param value: $publishBranchRegex /} + {param fieldWidth: 'long' /} + {param validationArguments: [ 'minlength' : 1, 'maxlength' : 255 ] /} + {param descriptionContent} + Branches that match this regex will have a publish build run on Jenkins. Be aware that this is + the full git ref - + e.g. "refs/heads/master" or "refs/heads/.*", not just "master". + {/param} + {param infoMessage: 'Examples:
  • refs/heads/master
  • refs/heads/.*
  • refs/tags/.*
  • refs/heads/(master|develop)
' /} + {/call} + {call aui.form.textField} + {param id: 'publishBuildCommand' /} + {param labelContent: stash_i18n('stash.web.stash.publishBuildCommand.label', 'Command') /} + {param descriptionText: stash_i18n('stash.web.stash.publishBuildCommand.description', 'The command that will be run during a publish build. This should be a script that runs a publishing command like ./gradlew publish') /} + {param infoMessage: 'Examples:
  • ./scripts/publish.sh
  • ENVVAR=1 ENVVAR=2 ./scripts/publish.sh
  • ./stashbot/publish.sh
' /} + {param value: $publishBuildCommand /} + {param fieldWidth: 'long' /} + {param validationArguments: [ 'minlength' : 1, 'maxlength' : 255 ] /} + {/call} + {call aui.expander.trigger} + {param id: 'advanced-expand-publish'/} + {param contentId: 'advanced-expand-publish-content'/} + {param tag: 'a'/} + {param content: 'Advanced Publishing'/} + {param replaceText: 'Hide Advanced'/} + {/call} + {call aui.expander.content} + {param id: 'advanced-expand-publish-content'/} + {param content} + {call aui.group.group} + {param content} + {call aui.group.item} + {param content} + {call aui.form.checkboxField} + {param legendContent: stash_i18n('stash.web.stash.publish-pinned-checkbox.button.description', 'Restrict Jenkins Nodes') /} + {param fields: [[ + 'id': 'isPublishPinned', + 'labelText': stash_i18n('stash.web.stash.enable-ci-radio.button.label', 'Enabled'), + 'isChecked': $isPublishPinned + ]] /} + {/call} + {call aui.form.textField} + {param id: 'publishLabel' /} + {param labelContent: stash_i18n('stash.web.stash.verifyLabel.label', 'Jenkins Node Label') /} + {param value: $publishLabel /} + {param descriptionText: stash_i18n('stash.web.stash.verifyBranchRegex.description', 'Jenkins node label to restrict publish builds to') /} + {/call} + {/param} + {/call} + {call aui.group.item} + {param content} +

Result Expiration

+
Build results meeting either of these conditions will be deleted. + {call aui.form.textField} + {param id: 'publishBuildExpiryDays' /} + {param labelContent: 'Days to keep' /} + {param descriptionText: 'The number of days to keep build results.' /} + {param value: $publishBuildExpiryDays /} + {param fieldWidth: 'short' /} + {param validationArguments: [ 'min' : 1, 'max' : $buildExpiryMaxDays ] /} + {/call} + {call aui.form.textField} + {param id: 'publishBuildExpiryNumber' /} + {param labelContent: 'Builds to keep' /} + {param descriptionText: 'The maximum number of build results to keep.' /} + {param value: $publishBuildExpiryNumber /} + {param fieldWidth: 'short' /} + {param validationArguments: [ 'min' : 1, 'max' : $buildExpiryMaxNumber ] /} + {/call} + {/param} + {/call} + {/param} + {/call} + {/param} + {/call} + {/param} + {/call} /* Publishing group End */ + + +

Verifications

+ {call aui.group.group} + {param content} + {call aui.form.checkboxField} + {param legendContent: stash_i18n('stash.web.stash.enable-verification.button.description', 'Commit Verifies') /} + {param fields: [[ + 'id': 'verificationEnabled', + 'labelText': stash_i18n('stash.web.stash.enable-verification.button.label', 'Enabled'), + 'isChecked': $verificationEnabled + ]] /} + {/call} + {call aui.form.checkboxField} + {param legendContent: stash_i18n('stash.web.stash.enable-verify-pr.button.description', 'PR Verifies') /} + {param fields: [[ + 'id': 'verifyPREnabled', + 'labelText': stash_i18n('stash.web.stash.enable-verify-pr.button.label', 'Enabled'), + 'isChecked': $verifyPREnabled + ]] /} + {/call} + {call aui.form.textField} + {param id: 'verifyBranchRegex' /} + {param labelContent: stash_i18n('stash.web.stash.verifyBranchRegex.label', 'Trigger Regex') /} + {param value: $verifyBranchRegex /} + {param fieldWidth: 'long' /} + {param validationArguments: [ 'minlength' : 1, 'maxlength' : 255 ] /} + {param descriptionContent} + Branches that match this regex will have a verify build run on Jenkins. Be aware that this is + the full git ref - + e.g. "refs/heads/master" or "refs/heads/.*", not just "master". + {/param} + {param infoMessage: 'Examples:
  • refs/heads/master
  • refs/heads/.*
  • refs/heads/(master|develop)
  • refs/heads/feature/.*
' /} + {/call} + {call aui.form.textField} + {param id: 'verifyBuildCommand' /} + {param labelContent: stash_i18n('stash.web.stash.verifyBuildCommand.label', 'Command') /} + {param descriptionText: stash_i18n('stash.web.stash.verifyBuildCommand.description', 'The command that will be run during a verification.') /} + {param infoMessage: 'Examples:
  • ./scripts/verify.sh
  • ENVVAR=1 ENVVAR=2 ./scripts/verifytest.sh
  • ./stashbot/check.sh
' /} + {param validationArguments: [ 'minlength' : 1, 'maxlength' : 255 ] /} + {param value: $verifyBuildCommand /} + {param fieldWidth: 'long' /} + {/call} + {call aui.expander.trigger} + {param id: 'advanced-expand-verify'/} + {param contentId: 'advanced-expand-verify-content'/} + {param tag: 'a'/} + {param content: 'Advanced Verification'/} + {param replaceText: 'Hide Advanced'/} + {/call} + {call aui.expander.content} + {param id: 'advanced-expand-verify-content'/} + {param content} + {call aui.group.group} + {param content} + {call aui.group.item} + {param content} + {call aui.form.checkboxField} + {param legendContent: stash_i18n('stash.web.stash.verify-pinned-checkbox.button.description', 'Restrict Jenkins Nodes') /} + {param fields: [[ + 'id': 'isVerifyPinned', + 'labelText': stash_i18n('stash.web.stash.enable-ci-radio.button.label', 'Enabled'), + 'isChecked': $isVerifyPinned + ]] /} + {/call} + {call aui.form.textField} + {param id: 'verifyLabel' /} + {param labelContent: stash_i18n('stash.web.stash.verifyLabel.label', 'Jenkins Node Label') /} + {param value: $verifyLabel /} + {param descriptionText: stash_i18n('stash.web.stash.verifyBranchRegex.description', 'Jenkins node label to restrict publish builds to') /} + {param validationArguments: [ 'minlength' : 1, 'maxlength' : 255 ] /} + {/call} + {call aui.form.textField} + {param id: 'maxVerifyChain' /} + {param labelContent: stash_i18n('stash.web.stash.maxVerifyChain.label', 'Maximum number of commits to verify on a single push') /} + {param value: $maxVerifyChain /} + {param validationArguments: [ 'minlength' : 1, 'maxlength' : 255 ] /} + {/call} + {call aui.form.checkboxField} + {param legendContent: stash_i18n('stash.web.stash.rebuild-on-update-radio.button.description', 'Rebuild PR on target change') /} + {param fields: [[ + 'id': 'rebuildOnUpdate', + 'labelText': stash_i18n('stash.web.stash.enable-ci-radio.button.label', 'Enabled'), + 'isChecked': $rebuildOnUpdate + ]] /} + {/call} + {call aui.form.checkboxField} + {param legendContent: stash_i18n('stash.web.stash.strict-verify-mode.button.description', 'Strict Verify Mode') /} + {param fields: [[ + 'id': 'isStrictVerifyMode', + 'labelText': stash_i18n('stash.web.stash.strict-verify-mode.button.label', 'Enabled'), + 'isChecked': $isStrictVerifyMode + ]] /} + {/call} + {/param} + {/call} + {call aui.group.item} + {param content} +

Result Expiration

+ {call aui.form.textField} + {param id: 'verifyBuildExpiryDays' /} + {param labelContent: 'Days to keep' /} + {param descriptionText: 'The number of days to keep build results.' /} + {param value: $verifyBuildExpiryDays /} + {param fieldWidth: 'short' /} + {param validationArguments: [ 'min' : 1, 'max' : $buildExpiryMaxDays ] /} + {/call} + {call aui.form.textField} + {param id: 'verifyBuildExpiryNumber' /} + {param labelContent: 'Builds to keep' /} + {param descriptionText: 'The number of build results to keep.' /} + {param value: $verifyBuildExpiryNumber /} + {param fieldWidth: 'short' /} + {param validationArguments: [ 'min' : 1, 'max' : $buildExpiryMaxNumber ] /} + {/call} + {/param} + {/call} + {/param} + {/call} + {/param} + {/call} /* Expanded Group End */ + {/param} + {/call} /* Verification Group End */ + +

Artifacts

+ {call aui.group.group} + {param content} + + {call aui.group.item} + {param content} + {call aui.form.checkboxField} + {param legendContent: stash_i18n('stash.web.stash.junit-enabled.button.description', 'Junit Test Results') /} + {param fields: [[ + 'id': 'isJunit', + 'labelText': stash_i18n('stash.web.stash.enable-ci-radio.button.label', 'Enabled'), + 'isChecked': $isJunit + ]] /} + {/call} + {call aui.form.textField} + {param id: 'junitPath' /} + {param labelContent: stash_i18n('stash.web.stash.junitPath.label', 'Result Location') /} + {param value: $junitPath /} + {param descriptionContent} + Location of JUnit xml files after a build completes. This is an ant-style glob. + For example, Gradle by default will put results at **/build/test-results/TEST-*.xml. If no xml files are found, the build will fail. This applies + to verify and publish builds. + {/param} + {param validationArguments: [ 'minlength' : 1, 'maxlength' : 255 ] /} + {param infoMessage: 'Examples:
  • **/build/test-results/TEST-*.xml
  • **/build/test-results/TEST-*.xml,testserver/tests/*.xml
' /} + {/call} + {/param} + {/call} /* JUnit Item End */ + + {call aui.group.item} + {param content} + {call aui.form.checkboxField} + {param legendContent: stash_i18n('stash.web.stash.artifacts-enabled.button.description', 'Save Artifacts') /} + {param fields: [[ + 'id': 'artifactsEnabled', + 'labelText': stash_i18n('stash.web.stash.enable-ci-radio.button.label', 'Enabled'), + 'isChecked': $artifactsEnabled + ]] /} + {/call} + {call aui.form.textField} + {param id: 'artifactsPath' /} + {param labelContent: stash_i18n('stash.web.stash.artifactsPath.label', 'Artifact Pattern') /} + {param value: $artifactsPath /} + {param descriptionContent} + Comma-delimited ant-style globs you wish + Jenkins to save after a build (of any type) completes. This is useful for picking up logs, coverage reports, etc. + {/param} + {param validationArguments: [ 'minlength' : 1, 'maxlength' : 255 ] /} + {param infoMessage: 'Examples:
  • **/logs/*.log
  • **/testserver/logs/*.log,npm-debug.log,build/**/*.log
' /} + {/call} + {/param} + {/call} /* Artifacting Item End */ + {/param} + {/call} + + +

Advanced

+ {call aui.expander.trigger} + {param id: 'advanced-expand-jenkins'/} + {param contentId: 'advanced-expand-jenkins-content'/} + {param tag: 'a'/} + {param content: 'Show Advanced'/} + {param replaceText: 'Hide Advanced'/} + {/call} + {call aui.expander.content} + {param id: 'advanced-expand-jenkins-content'/} + {param content} + + {call aui.group.group} + {param content} + {call aui.group.item} + {param content} + {call aui.form.selectField} + {param id: 'jenkinsServerName' /} + {param labelContent: stash_i18n('stash.web.stash.jenkinsServerName.label', 'Jenkins Server') /} + {param options: $jenkinsServersData /} + {param value: $jenkinsServerName /} + {/call} + {/param} + {/call} + + {call aui.group.item} + {param content} + {call aui.form.textField} + {param id: 'buildTimeout' /} + {param labelContent: stash_i18n('stash.web.stash.buildTimeout.label', 'Build Timeout (minutes)') /} + {param descriptionText: stash_i18n('stash.web.stash.buildTimeout.description', 'Timeout (in minutes) for all builds. A value of -1 uses Jenkins-wide default. Minimum value of ' + $buildTimeoutMin + ' and maximum value of ' + $buildTimeoutMax + '.') /} + {param value: $buildTimeout /} + {param fieldWidth: 'short' /} + {param validationArguments: [ 'minlength' : 1, 'maxlength' : 255 ] /} + {/call} + {/param} + {/call} + {/param} + {/call} /* Group End */ + + {call aui.group.group} + {param content} +

 

+ {/param} + {/call} + + {call aui.group.group} + {param content} + + {call aui.group.item} + {param content} + {call aui.form.textField} + {param id: 'prebuildCommand' /} + {param descriptionText: stash_i18n('stash.web.stash.prebuildCommand.description', 'Command to run before all builds (and for PR verifies, before the merge). This happens after any Global Preamble the admin may have set.') /} + {param labelContent: stash_i18n('stash.web.stash.prebuildCommand.label', 'Pre Build Command') /} + {param value: $prebuildCommand /} + {param validationArguments: [ 'minlength' : 1, 'maxlength' : 255 ] /} + {/call} + {/param} + {/call} + + {call aui.group.item} + {param content} + {call aui.form.checkboxField} + {param legendContent: stash_i18n('stash.web.stash.preserveJenkinsJobConfig.label', 'Preserve Jenkins Job Config') /} + {param descriptionText: stash_i18n('stash.web.stash.preserveJenkinsJobConfig.description', 'Enabling this option stops Stashbot from setting any command, artifact, testing, etc. options for your build.') /} + {param fields: [[ + 'id': 'isPreserveJenkinsJobConfig', + 'labelText': stash_i18n('stash.web.stash.preserveJenkinsJobConfig.button.label', 'Enabled'), + 'isChecked': $isPreserveJenkinsJobConfig + ]] /} + {/call} + {/param} + {/call} + {/param} + {/call} /* Group End */ + + {call aui.group.group} + {param content} +

 

+ {/param} + {/call} + + {call aui.group.group} + {param content} + {call aui.form.checkboxField} + {param legendContent: stash_i18n('stash.web.stash.email-enabled.button.description', 'E-mail notifications') /} + {param fields: [[ + 'id': 'isEmailNotificationsEnabled', + 'labelText': stash_i18n('stash.web.stash.enable-ci-radio.button.label', 'Enabled'), + 'isChecked': $isEmailNotificationsEnabled + ]] /} + {/call} + {call aui.form.textField} + {param id: 'emailRecipients' /} + {param labelContent: stash_i18n('stash.web.stash.emailRecipients.label', 'E-mail Recipients') /} + {param value: $emailRecipients /} + {param validationArguments: [ 'minlength' : 1, 'maxlength' : 255 ] /} + {/call} + {call aui.form.checkboxField} + {param legendContent: stash_i18n('stash.web.stash.emailForEveryUnstableBuild.button.description', 'E-mail Options') /} + {param fields: [[ + 'id': 'isEmailForEveryUnstableBuild', + 'labelText': stash_i18n('stash.web.stash.enable-ci-radio.button.label', 'Send e-mail for every unstable build'), + 'isChecked': $isEmailForEveryUnstableBuild + ]] /} + {/call} + {call aui.form.checkboxField} + {param legendContent: stash_i18n('stash.web.stash.emailSendToIndividuals.button.description', '') /} + {param fields: [[ + 'id': 'isEmailSendToIndividuals', + 'labelText': stash_i18n('stash.web.stash.enable-ci-radio.button.label', 'Send separate e-mails to individuals who broke the build'), + 'isChecked': $isEmailSendToIndividuals + ]] /} + {/call} + {call aui.form.checkboxField} + {param legendContent: stash_i18n('stash.web.stash.emailPerModuleEmail.button.description', '') /} + {param fields: [[ + 'id': 'isEmailPerModuleEmail', + 'labelText': stash_i18n('stash.web.stash.enable-ci-radio.button.label', 'Send e-mail for each failed module'), + 'isChecked': $isEmailPerModuleEmail + ]] /} + {/call} + {/param} + {/call} /* Group End */ + {/param} + {/call} + + +

 

+ {call aui.form.buttons} + {param content} + {call aui.form.submit} + {param id: 'submitstashbotsettings' /} + {param text: stash_i18n('stash.web.stash.ci-prefs.submit', 'Save') /} + {param type: 'submit' /} + {/call} + {/param} + {/call} - {/param} - {/call} {/param} {/call} -
-

Regular Expressions:

-

-Regular expressions are simple Java style regular expressions. Extra escaping is not required, and the regular expressions are anchored by default so you must add a trailing ".*" if you want prefix matching. -
-Examples: -

refs/heads/master
-
refs/heads/.*
-
refs/heads/features/.*-verify
-

-

Verify Versus Publish:

-

-When a new change is added to a reference which matches both publish and verify regular expressions, the publish build is triggered first. A verify build is never done on a sha1 which has already triggered a publish build. Also, publish builds are always only triggered on the most recent change to a ref, so if a chain of commits are pushed, only the latest is published (though depending on other settings, multiple verify builds could be triggered, see next section). -

-

Build Pinning

-

-If your jenkins instance has applied labels to build nodes, you can have verifiy or publish builds pinned to a specific build node label by checking these checkboxes, and entering the desired label. -

-

Max Verify Chain:

-

-The max verify chain setting specifies the number of verify builds to trigger due to a single ref update, at most. For example, if the setting is set to 5, and a reference is updated from pointing to commit A, to pointing to commit B, and commit B has commit A as it's parent's parent's parent's parent, that is a chain of five commits have been pushed each dependent on the next, then 5 verify builds will be triggered, one for each commit. If the setting was instead set to 3, only the 3 "most recent" commits would be verified, and 2 would be left unbuilt (but verifies could be triggered manually). If the setting was 0, an unlimited number of builds could be triggered (though still limited by the jenkins configuration setting as well, which puts a cap on it). -

-

Strict Verify Mode

-

-In strict mode, stashbot requires that every commit in a pull request has at least one successful build before it can be merged. This lets you enforce a higher level of verification so that git bisects are reliable. Another example where you might want to do this is if your build acts upon changed pieces only, and can therefore only guarantee consistency if each commit's parent has also been verified. -Note that if your verify regex does not match a feature branch, but does match an integration branch, and you push to your feature branch then try to merge into your integration branch, there will be missing verify builds. Therefore, if you want stashbot to perform these builds and operate in strict mode, you probably want your verify regex to cover all branches to which you directly push. +

+ +

+ {call aui.expander.trigger} + {param id: 'advanced-expand-documentation'/} + {param contentId: 'advanced-expand-documentation-content'/} + {param tag: 'a'/} + {param content: 'Show Documentation'/} + {param replaceText: 'Hide Documentation'/} + {/call}

-
+{call aui.expander.content} + {param id: 'advanced-expand-documentation-content'/} + {param content} +
+
+

Build/Job Types

+
    +
  • + Verify +
      +
    • verification – Each commit in a PR gets verified by its own run of the verification job
    • +
    • verify_pr – The PR gets tested in verify_pr. The difference between this and verification is + that the PR gets merged into the target branch. +
    • +
    +
  • +
  • + Publish +
      +
    • publish – The publish build is useful for publishing artifacts, releases, etc. It is expected + that the command you run for a publish will take care of the actual publishing of artifacts. In case you push + a commit to a branch that matches both the verify and publish regular expressions, the publish job will take + prescendence over the verification build. The commit will not be verified. +
    • +
    +
  • +
+
+
 
+
+

Branch Regular Expressions

+ The branch regex specify when a verification/verify_pr build will start and when a publish build will start. It requires + a full git reference and uses Java for matching regexes. +

Examples

+
+
refs/heads/master
+
Matches just the master branch.
+ +
refs/heads/.*
+
Matches all branches.
+ +
refs/heads/(master|develop)
+
Matches the master or develop branch
+ +
refs/(heads/master|tags/.*)
+
Matches the master branch and all tags
+
+

Publish Examples

+
refs/heads/(master|develop)
+
Publish on any commit pushed or PR merged into master or develop branch.
+ +
refs/(heads/master|tags/.*)
+
Any commit pushed or PR merged into master will cause a publish job to start. In addition, + a tag can be pushed independently and it will also start a publish job. This allows you to publish master + almost like a testable snapshot, and when you're happy, you can push a tag separately and actually create + a release.
+ +
refs/heads/(master|release/.*)
+
Publish commits/PRs to master or any branch starting with release/ such as release/2.4.0 +
+
+
+
 
+
+

Advanced

+ +

Build Pinning

+ If your jenkins instance has applied labels to build nodes, you can have verifiy or publish builds pinned to a specific build + node label by checking these checkboxes, and entering the desired label. + +

Build Timeouts

+ All Jenkins jobs created by Stashbot have a timeout set on them. By default, the jobs use the default timeout set by the admin + of Stash. If you’d like a different value, you can override it at the repository level. A value of -1 uses the Jenkins-wide + default. The allowable range is from 5 minutes to 1 week (10080 minutes). + +

Max Verify Chain

+ The max verify chain setting specifies the number of verification builds to trigger due to a single ref update, at most. For + example, if the setting is set to 5, and a reference is updated from pointing to commit A, to pointing to commit B, and commit B + has commit A as it's parent's parent's parent's parent, that is a chain of five commits have been pushed each dependent on the next, + then 5 verify builds will be triggered, one for each commit. If the setting was instead set to 3, only the 3 "most recent" commits + would be verified, and 2 would be left unbuilt (but verifies could be triggered manually). If the setting was 0, an unlimited number + of builds could be triggered (though still limited by the jenkins configuration setting as well, which puts a cap on it). + +

Strict Verify Mode

+ In strict mode, stashbot requires that every commit in a pull request has at least one successful build before it can be merged. + This lets you enforce a higher level of verification so that git bisects are reliable. Another example where you might want to do + this is if your build acts upon changed pieces only, and can therefore only guarantee consistency if each commit's parent has also + been verified. Note that if your verify regex does not match a feature branch, but does match an integration branch, and you push + to your feature branch then try to merge into your integration branch, there will be missing verify builds. Therefore, if you want + stashbot to perform these builds and operate in strict mode, you probably want your verify regex to cover all branches to which you + directly push. Strict mode is disabled by default, and when enabled it cannot be overridden with the override flag due to + implementation details (but users may still perform the merge locally and directly push it, if they have adequate permissions to do so). + +

Preserve Jenkins Job Config

+ When you click save, normally, the job is destroyed and recreated. This option disables that, so editing this page still changes internal + state but no longer effects a job (that already exists) at all. Some features will work, some will not, but changes made directly in + jenkins will no longer be destroyed. +
+
+ {/param} +{/call} + + {/template} diff --git a/src/test/java/com/palantir/stash/stashbot/config/ConfigurationTest.java b/src/test/java/com/palantir/stash/stashbot/config/ConfigurationTest.java index 4c113ca..97e9016 100644 --- a/src/test/java/com/palantir/stash/stashbot/config/ConfigurationTest.java +++ b/src/test/java/com/palantir/stash/stashbot/config/ConfigurationTest.java @@ -42,6 +42,7 @@ import com.atlassian.stash.repository.Repository; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.palantir.stash.stashbot.config.ConfigurationPersistenceService.BuildResultExpirySettings; import com.palantir.stash.stashbot.config.ConfigurationPersistenceService.EmailSettings; import com.palantir.stash.stashbot.config.ConfigurationTest.DataStuff; import com.palantir.stash.stashbot.event.StashbotMetadataUpdatedEvent; @@ -183,7 +184,7 @@ public void storesRepoData() throws Exception { "verifyBranchRegex", "verifyBuildCommand", false, "N/A", "publishBranchRegex", "publishBuildCommand", false, "N/A", "prebuildCommand", "default", true, false, "N/A", false, "N/A", - size, new EmailSettings(true, "a@a.a", true, true, true), false, false); + size, new EmailSettings(true, "a@a.a", true, true, true), false, false, -1, new BuildResultExpirySettings()); RepositoryConfiguration rc = cpm .getRepositoryConfigurationForRepository(repo); @@ -212,7 +213,7 @@ public void failsWithBadData() throws Exception { "verifyBranchRegex", "verifyBuildCommand", false, "N/A", "publishBranchRegex", "publishBuildCommand", false, "N/A", "prebuildCommand", "BADNAME", true, false, - "N/A", false, "N/A", null, new EmailSettings(), false, false); + "N/A", false, "N/A", null, new EmailSettings(), false, false, -1, new BuildResultExpirySettings()); Assert.fail("Should have thrown exception"); } catch (Exception e) { // success @@ -290,6 +291,7 @@ public void testFixesUrlEndingInSlash() throws Exception { new DBParam("PASSWORD", "somepw"), new DBParam("STASH_USERNAME", "someuser"), new DBParam("STASH_PASSWORD", "somepw"), + new DBParam("PREFIX_TEMPLATE", "/"), new DBParam("MAX_VERIFY_CHAIN", 1)); JenkinsServerConfiguration jsc = cpm .getJenkinsServerConfiguration("sometest"); diff --git a/src/test/java/com/palantir/stash/stashbot/hooks/PullRequestBuildSuccessMergeCheckTest.java b/src/test/java/com/palantir/stash/stashbot/hooks/PullRequestBuildSuccessMergeCheckTest.java index 555705e..01e6991 100644 --- a/src/test/java/com/palantir/stash/stashbot/hooks/PullRequestBuildSuccessMergeCheckTest.java +++ b/src/test/java/com/palantir/stash/stashbot/hooks/PullRequestBuildSuccessMergeCheckTest.java @@ -24,9 +24,9 @@ import com.atlassian.stash.build.BuildStats; import com.atlassian.stash.build.BuildStatusService; +import com.atlassian.stash.commit.Commit; import com.atlassian.stash.commit.CommitService; -import com.atlassian.stash.content.Changeset; -import com.atlassian.stash.content.ChangesetsBetweenRequest; +import com.atlassian.stash.commit.CommitsBetweenRequest; import com.atlassian.stash.pull.PullRequest; import com.atlassian.stash.pull.PullRequestRef; import com.atlassian.stash.repository.Repository; @@ -78,18 +78,18 @@ public class PullRequestBuildSuccessMergeCheckTest { @Mock private PullRequestMetadata prm2; @Mock - private Page mockPage; + private Page mockPage; @Mock - private Changeset changeA; + private Commit changeA; @Mock - private Changeset changeB; + private Commit changeB; @Mock private BuildStats bsA; @Mock private BuildStats bsB; private final PluginLoggerFactory lf = new PluginLoggerFactory(); - private List changesets; + private List changesets; @Before public void setUp() throws SQLException { @@ -111,10 +111,10 @@ public void setUp() throws SQLException { Mockito.when(pr.getToRef()).thenReturn(toRef); Mockito.when(fromRef.getRepository()).thenReturn(repo); - Mockito.when(fromRef.getLatestChangeset()).thenReturn(TO_SHA); + Mockito.when(fromRef.getLatestCommit()).thenReturn(TO_SHA); Mockito.when(toRef.getRepository()).thenReturn(repo); Mockito.when(toRef.getId()).thenReturn(TO_SHA); - Mockito.when(toRef.getLatestChangeset()).thenReturn(TO_SHA); + Mockito.when(toRef.getLatestCommit()).thenReturn(TO_SHA); Mockito.when(cpm.getPullRequestMetadata(pr)).thenReturn(prm); Mockito.when(cpm.getPullRequestMetadataWithoutToRef(pr)).thenReturn(ImmutableList.of(prm, prm2)); @@ -127,7 +127,7 @@ public void setUp() throws SQLException { changesets = ImmutableList.of(changeA, changeB); Mockito.when( - cs.getChangesetsBetween(Mockito.any(ChangesetsBetweenRequest.class), Mockito.any(PageRequest.class))) + cs.getCommitsBetween(Mockito.any(CommitsBetweenRequest.class), Mockito.any(PageRequest.class))) .thenReturn(mockPage); Mockito.when(mockPage.getValues()).thenReturn(changesets); Mockito.when(mockPage.getIsLastPage()).thenReturn(true); @@ -185,7 +185,7 @@ public void testSkipsMergeCheckWhenPRVerifyDisabledTest() { @Test public void testSuccessMergeCheckWhenPartialMatchTest() { - Mockito.when(toRef.getLatestChangeset()).thenReturn(TO_SHA2); // instead of TO_SHA + Mockito.when(toRef.getLatestCommit()).thenReturn(TO_SHA2); // instead of TO_SHA // returns only prm2, not prm (so no success) Mockito.when(cpm.getPullRequestMetadataWithoutToRef(pr)).thenReturn(ImmutableList.of(prm2)); Mockito.when(rc.getRebuildOnTargetUpdate()).thenReturn(false); @@ -202,7 +202,7 @@ public void testSuccessMergeCheckWhenPartialMatchTest() { @Test public void testFailsMergeCheckWhenPartialMatchTest() { - Mockito.when(toRef.getLatestChangeset()).thenReturn(TO_SHA2); // instead of TO_SHA + Mockito.when(toRef.getLatestCommit()).thenReturn(TO_SHA2); // instead of TO_SHA Mockito.when(rc.getRebuildOnTargetUpdate()).thenReturn(false); // neither exact match nor inexact match have success diff --git a/src/test/java/com/palantir/stash/stashbot/managers/JenkinsClientManagerTest.java b/src/test/java/com/palantir/stash/stashbot/managers/JenkinsClientManagerTest.java index 8788a14..ed49218 100644 --- a/src/test/java/com/palantir/stash/stashbot/managers/JenkinsClientManagerTest.java +++ b/src/test/java/com/palantir/stash/stashbot/managers/JenkinsClientManagerTest.java @@ -13,6 +13,8 @@ // limitations under the License. package com.palantir.stash.stashbot.managers; +import static org.mockito.Matchers.any; + import java.net.URISyntaxException; import org.junit.Before; @@ -22,37 +24,40 @@ import org.mockito.MockitoAnnotations; import org.springframework.util.Assert; +import com.atlassian.stash.repository.Repository; import com.offbytwo.jenkins.JenkinsServer; -import com.palantir.stash.stashbot.managers.JenkinsClientManager; import com.palantir.stash.stashbot.persistence.JenkinsServerConfiguration; import com.palantir.stash.stashbot.persistence.RepositoryConfiguration; public class JenkinsClientManagerTest { - private static final String JENKINS_URL = "http://www.example.com:8080/jenkins"; - private static final String JENKINS_USERNAME = "jenkins_user"; - private static final String JENKINS_PW = "jenkins_pw"; - @Mock - private RepositoryConfiguration rc; - @Mock - private JenkinsServerConfiguration jsc; - - private JenkinsClientManager jcm; - - @Before - public void setUp() { - - MockitoAnnotations.initMocks(this); - - Mockito.when(jsc.getUrl()).thenReturn(JENKINS_URL); - Mockito.when(jsc.getUsername()).thenReturn(JENKINS_USERNAME); - Mockito.when(jsc.getPassword()).thenReturn(JENKINS_PW); - jcm = new JenkinsClientManager(); - } - - @Test - public void testJCM() throws URISyntaxException { - JenkinsServer js = jcm.getJenkinsServer(jsc, rc); - Assert.notNull(js); - } + private static final String JENKINS_URL = "http://www.example.com:8080/jenkins"; + private static final String JENKINS_USERNAME = "jenkins_user"; + private static final String JENKINS_PW = "jenkins_pw"; + @Mock + private RepositoryConfiguration rc; + @Mock + private JenkinsServerConfiguration jsc; + + private JenkinsClientManager jcm; + + @Before + public void setUp() { + + MockitoAnnotations.initMocks(this); + + Mockito.when(jsc.getUrl()).thenReturn(JENKINS_URL); + Mockito.when(jsc.getUsername()).thenReturn(JENKINS_USERNAME); + Mockito.when(jsc.getPassword()).thenReturn(JENKINS_PW); + Mockito.when(jsc.getPrefixTemplate()).thenReturn(""); + Mockito.when(jsc.getUrlForRepo(any(Repository.class))).thenReturn( + JENKINS_URL); + jcm = new JenkinsClientManager(); + } + + @Test + public void testJCM() throws URISyntaxException { + JenkinsServer js = jcm.getJenkinsServer(jsc, rc, null); + Assert.notNull(js); + } } diff --git a/src/test/java/com/palantir/stash/stashbot/managers/JenkinsManagerTest.java b/src/test/java/com/palantir/stash/stashbot/managers/JenkinsManagerTest.java index 1f78a4c..10b67ca 100644 --- a/src/test/java/com/palantir/stash/stashbot/managers/JenkinsManagerTest.java +++ b/src/test/java/com/palantir/stash/stashbot/managers/JenkinsManagerTest.java @@ -51,224 +51,231 @@ public class JenkinsManagerTest { - private static final String XML_STRING = ""; - - @Mock - private RepositoryService repositoryService; - @Mock - private ConfigurationPersistenceService cpm; - @Mock - private JenkinsJobXmlFormatter xmlFormatter; - @Mock - private JenkinsClientManager jenkinsClientManager; - @Mock - private JobTemplateManager jtm; - @Mock - private StashbotUrlBuilder sub; - @Mock - private UserService us; - @Mock - private UserManager um; + private static final String XML_STRING = ""; + + @Mock + private RepositoryService repositoryService; + @Mock + private ConfigurationPersistenceService cpm; + @Mock + private JenkinsJobXmlFormatter xmlFormatter; + @Mock + private JenkinsClientManager jenkinsClientManager; + @Mock + private JobTemplateManager jtm; + @Mock + private StashbotUrlBuilder sub; + @Mock + private UserService us; + @Mock + private UserManager um; - private JenkinsManager jenkinsManager; + private JenkinsManager jenkinsManager; - @Mock - private JenkinsServer jenkinsServer; - @Mock - private Repository repo; - @Mock - private Project proj; + @Mock + private JenkinsServer jenkinsServer; + @Mock + private Repository repo; + @Mock + private Project proj; - @Mock - private RepositoryConfiguration rc; - @Mock - private JenkinsServerConfiguration jsc; - @Mock - private UserProfile up; - @Mock - private StashUser su; + @Mock + private RepositoryConfiguration rc; + @Mock + private JenkinsServerConfiguration jsc; + @Mock + private UserProfile up; + @Mock + private StashUser su; - private SecurityService ss; + private SecurityService ss; - private final PluginLoggerFactory lf = new PluginLoggerFactory(); + private final PluginLoggerFactory lf = new PluginLoggerFactory(); - private MockJobTemplateFactory jtf; - private MockSecurityServiceBuilder mssb; + private MockJobTemplateFactory jtf; + private MockSecurityServiceBuilder mssb; + + @Before + public void setUp() throws Throwable { - @Before - public void setUp() throws Throwable { + MockitoAnnotations.initMocks(this); - MockitoAnnotations.initMocks(this); + Mockito.when( + jenkinsClientManager.getJenkinsServer( + Mockito.any(JenkinsServerConfiguration.class), + Mockito.any(RepositoryConfiguration.class), + Mockito.any(Repository.class))).thenReturn( + jenkinsServer); - Mockito.when( - jenkinsClientManager.getJenkinsServer( - Mockito.any(JenkinsServerConfiguration.class), - Mockito.any(RepositoryConfiguration.class))) - .thenReturn(jenkinsServer); + jtf = new MockJobTemplateFactory(jtm); + jtf.generateDefaultsForRepo(repo, rc); - jtf = new MockJobTemplateFactory(jtm); - jtf.generateDefaultsForRepo(repo, rc); + Mockito.when( + xmlFormatter.generateJobXml(Mockito.any(JobTemplate.class), + Mockito.eq(repo))).thenReturn(XML_STRING); - Mockito.when( - xmlFormatter.generateJobXml(Mockito.any(JobTemplate.class), - Mockito.eq(repo))).thenReturn(XML_STRING); + Mockito.when(cpm.getJenkinsServerConfiguration(Mockito.anyString())) + .thenReturn(jsc); + Mockito.when(cpm.getRepositoryConfigurationForRepository(repo)) + .thenReturn(rc); + Mockito.when(jsc.getStashUsername()).thenReturn("stash_username"); + Mockito.when(jsc.getStashPassword()).thenReturn("stash_password"); + Mockito.when(jsc.getPassword()).thenReturn("jenkins_password"); - Mockito.when(cpm.getJenkinsServerConfiguration(Mockito.anyString())) - .thenReturn(jsc); - Mockito.when(cpm.getRepositoryConfigurationForRepository(repo)) - .thenReturn(rc); - Mockito.when(jsc.getStashUsername()).thenReturn("stash_username"); - Mockito.when(jsc.getStashPassword()).thenReturn("stash_password"); - Mockito.when(jsc.getPassword()).thenReturn("jenkins_password"); + Mockito.when(repo.getName()).thenReturn("somename"); + Mockito.when(repo.getSlug()).thenReturn("slug"); + Mockito.when(repo.getProject()).thenReturn(proj); + Mockito.when(proj.getKey()).thenReturn("project_key"); - Mockito.when(repo.getName()).thenReturn("somename"); - Mockito.when(repo.getSlug()).thenReturn("slug"); - Mockito.when(repo.getProject()).thenReturn(proj); - Mockito.when(proj.getKey()).thenReturn("project_key"); + Mockito.when(um.getRemoteUser()).thenReturn(up); + Mockito.when(up.getUsername()).thenReturn("someuser"); + Mockito.when(us.getUserByName(Mockito.anyString())).thenReturn(su); - Mockito.when(um.getRemoteUser()).thenReturn(up); - Mockito.when(up.getUsername()).thenReturn("someuser"); - Mockito.when(us.getUserByName(Mockito.anyString())).thenReturn(su); + mssb = new MockSecurityServiceBuilder(); - mssb = new MockSecurityServiceBuilder(); + ss = mssb.getSecurityService(); - ss = mssb.getSecurityService(); + jenkinsManager = new JenkinsManager(repositoryService, cpm, jtm, + xmlFormatter, jenkinsClientManager, sub, lf, ss, us, um); + } - jenkinsManager = new JenkinsManager(repositoryService, cpm, jtm, - xmlFormatter, jenkinsClientManager, sub, lf, ss, us, um); - } + @Test + public void testCreateJob() throws Exception { - @Test - public void testCreateJob() throws Exception { + JobTemplate jt = jtm.getDefaultVerifyJob(); - JobTemplate jt = jtm.getDefaultVerifyJob(); + jenkinsManager.createJob(repo, jt); - jenkinsManager.createJob(repo, jt); + ArgumentCaptor xmlCaptor = ArgumentCaptor + .forClass(String.class); - ArgumentCaptor xmlCaptor = ArgumentCaptor - .forClass(String.class); + Mockito.verify(xmlFormatter).generateJobXml(jt, repo); + Mockito.verify(jenkinsServer).createJob(Mockito.anyString(), + xmlCaptor.capture()); - Mockito.verify(xmlFormatter).generateJobXml(jt, repo); - Mockito.verify(jenkinsServer).createJob(Mockito.anyString(), - xmlCaptor.capture()); + Assert.assertEquals(XML_STRING, xmlCaptor.getValue()); + } - Assert.assertEquals(XML_STRING, xmlCaptor.getValue()); - } + @Test + public void testUpdateJob() throws Exception { - @Test - public void testUpdateJob() throws Exception { + String jobName = "somename_verification"; - String jobName = "somename_verification"; + Job existingJob = Mockito.mock(Job.class); + Map jobMap = new HashMap(); + jobMap.put(jobName, existingJob); + Mockito.when(jenkinsServer.getJobs()).thenReturn(jobMap); - Job existingJob = Mockito.mock(Job.class); - Map jobMap = new HashMap(); - jobMap.put(jobName, existingJob); - Mockito.when(jenkinsServer.getJobs()).thenReturn(jobMap); + JobTemplate jt = jtm.getDefaultVerifyJob(); - JobTemplate jt = jtm.getDefaultVerifyJob(); + jenkinsManager.updateJob(repo, jt); - jenkinsManager.updateJob(repo, jt); + ArgumentCaptor xmlCaptor = ArgumentCaptor + .forClass(String.class); - ArgumentCaptor xmlCaptor = ArgumentCaptor - .forClass(String.class); + Mockito.verify(xmlFormatter).generateJobXml(jt, repo); + Mockito.verify(jenkinsServer).updateJob(Mockito.anyString(), + xmlCaptor.capture()); + Mockito.verify(jenkinsServer, Mockito.never()).createJob( + Mockito.anyString(), Mockito.anyString()); - Mockito.verify(xmlFormatter).generateJobXml(jt, repo); - Mockito.verify(jenkinsServer).updateJob(Mockito.anyString(), - xmlCaptor.capture()); - Mockito.verify(jenkinsServer, Mockito.never()).createJob( - Mockito.anyString(), Mockito.anyString()); + Assert.assertEquals(XML_STRING, xmlCaptor.getValue()); + } - Assert.assertEquals(XML_STRING, xmlCaptor.getValue()); - } + @Test + public void testTriggerBuildShort() throws Exception { + String HASH = "38356e8abe0e96538dd1007278ecc02c3bf3d2cb"; + String REF = "refs/heads/master"; - @Test - public void testTriggerBuildShort() throws Exception { - String HASH = "38356e8abe0e96538dd1007278ecc02c3bf3d2cb"; - String REF = "refs/heads/master"; + JobTemplate jt = jtm.getDefaultVerifyJob(); - JobTemplate jt = jtm.getDefaultVerifyJob(); + String jobName = jt.getBuildNameFor(repo, jsc); + Job existingJob = Mockito.mock(Job.class); + Mockito.when(existingJob.getName()).thenReturn(jobName); + Map jobMap = new HashMap(); + jobMap.put(jobName, existingJob); + Mockito.when(jenkinsServer.getJobs()).thenReturn(jobMap); - String jobName = jt.getBuildNameFor(repo); - Job existingJob = Mockito.mock(Job.class); - Mockito.when(existingJob.getName()).thenReturn(jobName); - Map jobMap = new HashMap(); - jobMap.put(jobName, existingJob); - Mockito.when(jenkinsServer.getJobs()).thenReturn(jobMap); + Mockito.when(jtm.getJobTemplate(JobType.VERIFY_COMMIT, rc)).thenReturn( + jt); - Mockito.when(jtm.getJobTemplate(JobType.VERIFY_COMMIT, rc)).thenReturn( - jt); + jenkinsManager.triggerBuild(repo, JobType.VERIFY_COMMIT, HASH, REF); + jenkinsManager.destroy(); - jenkinsManager.triggerBuild(repo, JobType.VERIFY_COMMIT, HASH, REF); - jenkinsManager.destroy(); + @SuppressWarnings({ "unchecked", "rawtypes" }) + Class> forClass = (Class) Map.class; + ArgumentCaptor> paramCaptor = ArgumentCaptor + .forClass(forClass); - @SuppressWarnings({ "unchecked", "rawtypes" }) - Class> forClass = (Class) Map.class; - ArgumentCaptor> paramCaptor = ArgumentCaptor - .forClass(forClass); + Mockito.verify(existingJob).build(paramCaptor.capture()); - Mockito.verify(existingJob).build(paramCaptor.capture()); + Map paramMap = paramCaptor.getValue(); + Assert.assertTrue(paramMap.containsKey("buildHead")); + Assert.assertTrue(paramMap.containsKey("buildRef")); + Assert.assertTrue(paramMap.containsKey("repoId")); + Assert.assertFalse(paramMap.containsKey("pullRequestId")); + Assert.assertFalse(paramMap.containsKey("mergeHead")); + } - Map paramMap = paramCaptor.getValue(); - Assert.assertTrue(paramMap.containsKey("buildHead")); - Assert.assertTrue(paramMap.containsKey("buildRef")); - Assert.assertTrue(paramMap.containsKey("repoId")); - Assert.assertFalse(paramMap.containsKey("pullRequestId")); - Assert.assertFalse(paramMap.containsKey("mergeHead")); - } + @Test + public void testUpdateRepoCIEnabled() throws IOException { - @Test - public void testUpdateRepoCIEnabled() throws IOException { + Mockito.when(rc.getCiEnabled()).thenReturn(true); - Mockito.when(rc.getCiEnabled()).thenReturn(true); + jenkinsManager.updateRepo(repo); - jenkinsManager.updateRepo(repo); + List templates = jtf.getMockTemplates(); - List templates = jtf.getMockTemplates(); + for (JobTemplate t : templates) { + Mockito.verify(jenkinsServer).createJob( + Mockito.eq(t.getBuildNameFor(repo, jsc)), Mockito.anyString()); + } + } - for (JobTemplate t : templates) { - Mockito.verify(jenkinsServer).createJob( - Mockito.eq(t.getBuildNameFor(repo)), Mockito.anyString()); - } - } + @Test + public void testUpdateRepoCIDisabled() throws IOException { - @Test - public void testUpdateRepoCIDisabled() throws IOException { + Mockito.when(rc.getCiEnabled()).thenReturn(false); - Mockito.when(rc.getCiEnabled()).thenReturn(false); + jenkinsManager.updateRepo(repo); - jenkinsManager.updateRepo(repo); + Mockito.verify(jenkinsServer, Mockito.never()).createJob( + Mockito.anyString(), Mockito.anyString()); + } - Mockito.verify(jenkinsServer, Mockito.never()).createJob( - Mockito.anyString(), Mockito.anyString()); - } + @Test + public void testPreserveJenkinsJobConfigDisabled() throws IOException { - @Test - public void testPreserveJenkinsJobConfigDisabled() throws IOException { + JobTemplate jt = jtm.getDefaultVerifyJob(); + HashMap jobs = Maps.newHashMap(); + jobs.put(jt.getBuildNameFor(repo, jsc), new Job()); // update job logic + // requires the job be + // there already - JobTemplate jt = jtm.getDefaultVerifyJob(); - HashMap jobs = Maps.newHashMap(); - jobs.put(jt.getBuildNameFor(repo), new Job()); // update job logic requires the job be there already + Mockito.when(rc.getPreserveJenkinsJobConfig()).thenReturn(false); + Mockito.when(jenkinsServer.getJobs()).thenReturn(jobs); - Mockito.when(rc.getPreserveJenkinsJobConfig()).thenReturn(false); - Mockito.when(jenkinsServer.getJobs()).thenReturn(jobs); + jenkinsManager.updateJob(repo, jt); - jenkinsManager.updateJob(repo, jt); + Mockito.verify(jenkinsServer).updateJob(Mockito.anyString(), + Mockito.anyString()); + } - Mockito.verify(jenkinsServer).updateJob(Mockito.anyString(), Mockito.anyString()); - } + @Test + public void testPreserveJenkinsJobConfigEnabled() throws IOException { - @Test - public void testPreserveJenkinsJobConfigEnabled() throws IOException { + JobTemplate jt = jtm.getDefaultVerifyJob(); + HashMap jobs = Maps.newHashMap(); + jobs.put(jt.getBuildNameFor(repo, jsc), new Job()); // update job logic + // requires the job be + // there already - JobTemplate jt = jtm.getDefaultVerifyJob(); - HashMap jobs = Maps.newHashMap(); - jobs.put(jt.getBuildNameFor(repo), new Job()); // update job logic requires the job be there already + Mockito.when(rc.getPreserveJenkinsJobConfig()).thenReturn(true); + Mockito.when(jenkinsServer.getJobs()).thenReturn(jobs); - Mockito.when(rc.getPreserveJenkinsJobConfig()).thenReturn(true); - Mockito.when(jenkinsServer.getJobs()).thenReturn(jobs); + jenkinsManager.updateJob(repo, jt); - jenkinsManager.updateJob(repo, jt); - - Mockito.verify(jenkinsServer, Mockito.never()).updateJob(Mockito.anyString(), Mockito.anyString()); - } + Mockito.verify(jenkinsServer, Mockito.never()).updateJob( + Mockito.anyString(), Mockito.anyString()); + } } diff --git a/src/test/java/com/palantir/stash/stashbot/mocks/MockJobTemplateFactory.java b/src/test/java/com/palantir/stash/stashbot/mocks/MockJobTemplateFactory.java index 89892d8..444b7b1 100644 --- a/src/test/java/com/palantir/stash/stashbot/mocks/MockJobTemplateFactory.java +++ b/src/test/java/com/palantir/stash/stashbot/mocks/MockJobTemplateFactory.java @@ -13,6 +13,9 @@ // limitations under the License. package com.palantir.stash.stashbot.mocks; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; + import java.util.ArrayList; import java.util.List; @@ -22,6 +25,7 @@ import com.google.common.collect.ImmutableList; import com.palantir.stash.stashbot.jobtemplate.JobTemplateManager; import com.palantir.stash.stashbot.jobtemplate.JobType; +import com.palantir.stash.stashbot.persistence.JenkinsServerConfiguration; import com.palantir.stash.stashbot.persistence.JobMapping; import com.palantir.stash.stashbot.persistence.JobTemplate; import com.palantir.stash.stashbot.persistence.RepositoryConfiguration; @@ -47,6 +51,7 @@ public void generateDefaultsForRepo(Repository repo, RepositoryConfiguration rc) Mockito.when(jtm.getDefaultVerifyJob()).thenReturn(verifyCommit); Mockito.when(jtm.getDefaultVerifyPullRequestJob()).thenReturn(verifyPR); Mockito.when(jtm.getDefaultPublishJob()).thenReturn(publish); + Mockito.when(jtm.getJenkinsJobsForRepository(rc)).thenReturn(ImmutableList.copyOf(templates)); } public JobTemplate getJobTemplate(Repository repo, RepositoryConfiguration rc, JobType jt) throws Exception { @@ -55,7 +60,9 @@ public JobTemplate getJobTemplate(Repository repo, RepositoryConfiguration rc, J Mockito.when(template.getJobType()).thenReturn(jt); Mockito.when(template.getName()).thenReturn(jt.toString()); - Mockito.when(template.getBuildNameFor(repo)).thenReturn("somename_" + jt.toString()); + Mockito.when(template.getBuildNameFor(eq(repo), any(JenkinsServerConfiguration.class))) + .thenReturn( + "somename_" + jt.toString()); Mockito.when(template.getTemplateFile()).thenReturn("src/test/resources/test-template.vm"); JobMapping jm = Mockito.mock(JobMapping.class); @@ -64,10 +71,11 @@ public JobTemplate getJobTemplate(Repository repo, RepositoryConfiguration rc, J Mockito.when(jm.isVisible()).thenReturn(true); Mockito.when(jm.isEnabled()).thenReturn(true); + templates.add(template); + Mockito.when(jtm.getJenkinsJobsForRepository(rc)).thenReturn(ImmutableList.copyOf(templates)); Mockito.when(jtm.fromString(rc, jt.toString())).thenReturn(template); - templates.add(template); mappings.add(jm); return template; }