diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..95db575
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+.gradle
+build
+
+gradle/wrapper/gradle-wrapper.jar
diff --git a/README.md b/README.md
index f460dba..0024c00 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,29 @@
-# xlr-teamcity-plugin
-Plugin to trigger builds in TeamCity
+# Preface #
+
+This document describes the xlr-teamcity-plugin.
+
+See the **XL Release Reference Manual** for background information on XL Release and release concepts.
+
+# Overview #
+
+A Plugin to trigger builds in TeamCity. Currently a very simple implementation which only supports triggering a build using the TeamCity buildConfID and returns the build number.
+
+## Installation ##
+
+Place the latest released version under the `plugins` dir.
+
+## Types ##
+
++ Build
+ * `server` - TeamCity server definition (see below)
+ * `username` - Used to override the TeamCity username - optional
+ * `password` - Used to override the TeamCity password - optional
+ * `buildConfID` - The buildConfID for the TeamCity build job, usually found in the settings screen for the build job.
+ * `buildNumber` - Output field where the build number will be set on successful completion
++ Server - In the XL Release Configuration screen
+ * `name` - Friendly name for this TeamCity server
+ * `URL` - URL to the TeamCity server, include port here
+ * `username` - Default username for TeamCity
+ * `password` - Password for the default user
+ * `proxyHost` - Proxy host if required
+ * `proxyPort` - Proxy port if required
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..464da87
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,18 @@
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath "nl.javadude.gradle.plugins:license-gradle-plugin:0.11.0"
+ }
+}
+
+version="1.0.0"
+
+apply plugin: "com.github.hierynomus.license"
+apply plugin: 'java'
+
+license {
+ header rootProject.file('src/main/license/xebialabs_community.license')
+ strictCheck true
+}
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..3df3396
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Fri Nov 28 19:11:09 CET 2014
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.1-bin.zip
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..91a7e26
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..aec9973
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..13d8f54
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'xlr-teamcity-plugin'
diff --git a/src/main/license/xebialabs_community.license b/src/main/license/xebialabs_community.license
new file mode 100644
index 0000000..6bb5c13
--- /dev/null
+++ b/src/main/license/xebialabs_community.license
@@ -0,0 +1,3 @@
+THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS
+FOR A PARTICULAR PURPOSE. THIS CODE AND INFORMATION ARE NOT SUPPORTED BY XEBIALABS.
\ No newline at end of file
diff --git a/src/main/resources/httputil/HttpRequest.py b/src/main/resources/httputil/HttpRequest.py
new file mode 100644
index 0000000..5f68601
--- /dev/null
+++ b/src/main/resources/httputil/HttpRequest.py
@@ -0,0 +1,206 @@
+#
+# THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS
+# FOR A PARTICULAR PURPOSE. THIS CODE AND INFORMATION ARE NOT SUPPORTED BY XEBIALABS.
+#
+
+import re
+import urllib
+
+from java.lang import String
+
+from org.apache.commons.codec.binary import Base64
+from org.apache.http import HttpHost
+from org.apache.http.client.config import RequestConfig
+from org.apache.http.client.methods import HttpGet, HttpPost, HttpPut, HttpDelete
+from org.apache.http.util import EntityUtils
+from org.apache.http.entity import StringEntity
+from org.apache.http.impl.client import HttpClients
+
+from com.xebialabs.xlrelease.domain.configuration import HttpConnection
+from httputil.HttpResponse import HttpResponse
+
+class HttpRequest:
+ def __init__(self, params, username = None, password = None):
+ """
+ Builds an HttpRequest
+
+ :param params: an HttpConnection
+ :param username: the username
+ (optional, it will override the credentials defined on the HttpConnection object)
+ :param password: an password
+ (optional, it will override the credentials defined on the HttpConnection object)
+ """
+ self.params = HttpConnection(params)
+ self.username = username
+ self.password = password
+
+ def doRequest(self, **options):
+ """
+ Performs an HTTP Request
+
+ :param options: A keyword arguments object with the following properties :
+ method: the HTTP method : 'GET', 'PUT', 'POST', 'DELETE'
+ (optional: GET will be used if empty)
+ context: the context url
+ (optional: the url on HttpConnection will be used if empty)
+ body: the body of the HTTP request for PUT & POST calls
+ (optional: an empty body will be used if empty)
+ contentType: the content type to use
+ (optional, no content type will be used if empty)
+ headers: a dictionary of headers key/values
+ (optional, no headers will be used if empty)
+ :return: an HttpResponse instance
+ """
+ request = self.buildRequest(
+ options.get('method', 'GET'),
+ options.get('context', ''),
+ options.get('body', ''),
+ options.get('contentType', None),
+ options.get('headers', None))
+ return self.executeRequest(request)
+
+
+ def get(self, context, **options):
+ """
+ Performs an Http GET Request
+
+ :param context: the context url
+ :param options: the options keyword argument described in doRequest()
+ :return: an HttpResponse instance
+ """
+ options['method'] = 'GET'
+ options['context'] = context
+ return self.doRequest(**options)
+
+
+ def put(self, context, body, **options):
+ """
+ Performs an Http PUT Request
+
+ :param context: the context url
+ :param body: the body of the HTTP request
+ :param options: the options keyword argument described in doRequest()
+ :return: an HttpResponse instance
+ """
+ options['method'] = 'PUT'
+ options['context'] = context
+ options['body'] = body
+ return self.doRequest(**options)
+
+
+ def post(self, context, body, **options):
+ """
+ Performs an Http POST Request
+
+ :param context: the context url
+ :param body: the body of the HTTP request
+ :param options: the options keyword argument described in doRequest()
+ :return: an HttpResponse instance
+ """
+ options['method'] = 'POST'
+ options['context'] = context
+ options['body'] = body
+ return self.doRequest(**options)
+
+
+ def delete(self, context, **options):
+ """
+ Performs an Http DELETE Request
+
+ :param context: the context url
+ :param options: the options keyword argument described in doRequest()
+ :return: an HttpResponse instance
+ """
+ options['method'] = 'DELETE'
+ options['context'] = context
+ return self.doRequest(**options)
+
+
+ def buildRequest(self, method, context, body, contentType, headers):
+ url = self.quote(self.createPath(self.params.getUrl(), context))
+
+ method = method.upper()
+
+ if method == 'GET':
+ request = HttpGet(url)
+ elif method == 'POST':
+ request = HttpPost(url)
+ request.setEntity(StringEntity(body))
+ elif method == 'PUT':
+ request = HttpPut(url)
+ request.setEntity(StringEntity(body))
+ elif method == 'DELETE':
+ request = HttpDelete(url)
+ else:
+ raise Exception('Unsupported method: ' + method)
+
+ request.addHeader('Content-Type', contentType)
+ request.addHeader('Accept', contentType)
+ self.setCredentials(request)
+ self.setProxy(request)
+ self.setHeaders(request, headers)
+
+ return request
+
+
+ def createPath(self, url, context):
+ url = re.sub('/*$', '', url)
+ if context is None:
+ return url
+ elif context.startswith('/'):
+ return url + context
+ else:
+ return url + '/' + context
+
+ def quote(self, url):
+ return urllib.quote(url, ':/?&=%')
+
+
+ def setCredentials(self, request):
+ if self.username:
+ username = self.username
+ password = self.password
+ elif self.params.getUsername():
+ username = self.params.getUsername()
+ password = self.params.getPassword()
+ else:
+ return
+
+ encoding = Base64.encodeBase64String(String(username + ':' + password).getBytes())
+ request.addHeader('Authorization', 'Basic ' + encoding)
+
+
+ def setProxy(self, request):
+ if not self.params.getProxyHost():
+ return
+
+ proxy = HttpHost(self.params.getProxyHost(), int(self.params.getProxyPort()))
+ config = RequestConfig.custom().setProxy(proxy).build()
+ request.setConfig(config)
+
+
+ def setHeaders(self, request, headers):
+ if headers:
+ for key in headers:
+ request.setHeader(key, headers[key])
+
+
+ def executeRequest(self, request):
+ client = None
+ response = None
+ try:
+ client = HttpClients.createDefault()
+ response = client.execute(request)
+ status = response.getStatusLine().getStatusCode()
+ entity = response.getEntity()
+ result = EntityUtils.toString(entity, "UTF-8") if entity else None
+ headers = response.getAllHeaders()
+ EntityUtils.consume(entity)
+
+ return HttpResponse(status, result, headers)
+ finally:
+ if response:
+ response.close()
+ if client:
+ client.close()
diff --git a/src/main/resources/httputil/HttpResponse.py b/src/main/resources/httputil/HttpResponse.py
new file mode 100644
index 0000000..69d4619
--- /dev/null
+++ b/src/main/resources/httputil/HttpResponse.py
@@ -0,0 +1,49 @@
+#
+# THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS
+# FOR A PARTICULAR PURPOSE. THIS CODE AND INFORMATION ARE NOT SUPPORTED BY XEBIALABS.
+#
+
+class HttpResponse:
+ def getStatus(self):
+ """
+ Gets the status code
+ :return: the http status code
+ """
+ return self.status
+
+ def getResponse(self):
+ """
+ Gets the response content
+ :return: the reponse as text
+ """
+ return self.response
+
+ def isSuccessful(self):
+ """
+ Checks if request successful
+ :return: true if successful, false otherwise
+ """
+ return 200 <= self.status < 400
+
+ def getHeaders(self):
+ """
+ Returns the response headers
+ :return: a dictionary of all response headers
+ """
+ return self.headers
+
+ def errorDump(self):
+ """
+ Dumps the whole response
+ """
+ print 'Status: ', self.status, '\n'
+ print 'Response: ', self.response, '\n'
+ print 'Response headers: ', self.headers, '\n'
+
+ def __init__(self, status, response, headers):
+ self.status = status
+ self.response = response
+ self.headers = {}
+ for header in headers:
+ self.headers[str(header.getName())] = str(header.getValue())
diff --git a/src/main/resources/httputil/__init__.py b/src/main/resources/httputil/__init__.py
new file mode 100644
index 0000000..9c1cd73
--- /dev/null
+++ b/src/main/resources/httputil/__init__.py
@@ -0,0 +1,6 @@
+#
+# THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS
+# FOR A PARTICULAR PURPOSE. THIS CODE AND INFORMATION ARE NOT SUPPORTED BY XEBIALABS.
+#
+
diff --git a/src/main/resources/synthetic.xml b/src/main/resources/synthetic.xml
new file mode 100644
index 0000000..00f7d69
--- /dev/null
+++ b/src/main/resources/synthetic.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/teamcity/Build.py b/src/main/resources/teamcity/Build.py
new file mode 100644
index 0000000..9d8eaf7
--- /dev/null
+++ b/src/main/resources/teamcity/Build.py
@@ -0,0 +1,48 @@
+#
+# THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS
+# FOR A PARTICULAR PURPOSE. THIS CODE AND INFORMATION ARE NOT SUPPORTED BY XEBIALABS.
+#
+
+import sys, time, ast, re
+from xml.etree import ElementTree as ET
+from httputil.HttpRequest import HttpRequest
+
+poll_interval = 5
+
+httpRequest = HttpRequest(teamcityServer, username, password)
+
+queueBuildURL = 'httpAuth/app/rest/buildQueue'
+buildBody = ''
+
+queue_response = httpRequest.post(queueBuildURL, buildBody, contentType='application/xml')
+
+if queue_response.isSuccessful():
+ # polls until the job completes
+ root = ET.fromstring(queue_response.getResponse())
+ runID = root.attrib['id']
+ statusURL = 'httpAuth/app/rest/buildQueue/taskId:' + runID
+ while True:
+ time.sleep(poll_interval)
+ status_response = httpRequest.get(statusURL, contentType='application/xml')
+ if status_response.isSuccessful():
+ root = ET.fromstring(status_response.getResponse())
+ if root.attrib['state'] == 'finished':
+ # Have a build completed
+ if root.attrib['status'] == 'SUCCESS':
+ buildNumber = root.attrib['number']
+ print('Build successful with build numner: ' + buildNumber)
+ sys.exit(0)
+ else:
+ print('Build failed, run ID: ' + runID)
+ print(status_response.getResponse())
+ sys.exit(1)
+ else:
+ print('Waiting for buildID: ' + buildID + ' to start/finish')
+ continue
+ else:
+ print('Status request failed')
+ sys.exit(1)
+else:
+ print('Queuing failed for buildID: ' + buildID)
+