[Buildbot-devel] Force Page, Default values for WithProperties Patch

Minesh Patel mpatel at 2wire.com
Tue Jan 9 19:55:24 UTC 2007


Minor tweaks to the force page patch from Paul Gain, give him all the 
credit for a great idea. Added default values to the WithProperties as 
well as username to the sourcestamp and build_status.properties so that 
it can be retrieved by the WithProperties class.

Here is an example of how to use the default values:
WithProperties("%s", "test", test='foo')


diff -Nuar buildbot-0.7.5.orig/buildbot/master.py 
buildbot-0.7.5/buildbot/master.py
--- buildbot-0.7.5.orig/buildbot/master.py 2006-12-10 21:40:11.000000000 
-0800
+++ buildbot-0.7.5/buildbot/master.py 2007-01-09 10:36:15.000000000 -0800
@@ -500,6 +500,7 @@
projectURL = None
buildbotURL = None
change_svc = None
+ customBuildProperties = None

def __init__(self, basedir, configFileName="master.cfg"):
service.MultiService.__init__(self)
@@ -653,7 +654,8 @@

known_keys = "bots sources schedulers builders slavePortnum " + \
"debugPassword manhole " + \
- "status projectName projectURL buildbotURL"
+ "status projectName projectURL buildbotURL " + \
+ "customBuildProperties"
known_keys = known_keys.split()
for k in config.keys():
if k not in known_keys:
@@ -674,6 +676,7 @@
projectName = config.get('projectName')
projectURL = config.get('projectURL')
buildbotURL = config.get('buildbotURL')
+ customBuildProperties = config.get('customBuildProperties')

except KeyError, e:
log.msg("config dictionary is missing a required parameter")
@@ -777,6 +780,7 @@
self.projectName = projectName
self.projectURL = projectURL
self.buildbotURL = buildbotURL
+ self.customBuildProperties = customBuildProperties

# self.bots: Disconnect any that were attached and removed from the
# list. Update self.checker with the new list of passwords,
diff -Nuar buildbot-0.7.5.orig/buildbot/process/base.py 
buildbot-0.7.5/buildbot/process/base.py
--- buildbot-0.7.5.orig/buildbot/process/base.py 2006-12-10 
21:40:11.000000000 -0800
+++ buildbot-0.7.5/buildbot/process/base.py 2007-01-09 
11:20:44.000000000 -0800
@@ -39,6 +39,9 @@
provide this, but for forced builds the user requesting the
build will provide a string.

+ @type custom_props: dictionary.
+ @ivar custom_props: custom user properties.
+
@ivar status: the IBuildStatus object which tracks our status

@ivar submittedAt: a timestamp (seconds since epoch) when this request
@@ -49,18 +52,20 @@
source = None
builder = None
startCount = 0 # how many times we have tried to start this build
+ custom_props = {}

if implements:
implements(interfaces.IBuildRequestControl)
else:
__implements__ = interfaces.IBuildRequestControl,

- def __init__(self, reason, source, builderName=None):
+ def __init__(self, reason, source, builderName=None, custom_props=None):
# TODO: remove the =None on builderName, it is there so I don't have
# to change a lot of tests that create BuildRequest objects
assert interfaces.ISourceStamp(source, None)
self.reason = reason
self.source = source
+ self.custom_props = custom_props
self.start_watchers = []
self.finish_watchers = []
self.status = BuildRequestStatus(source, builderName)
@@ -87,6 +92,9 @@
self.finish_watchers.append(d)
return d

+ def customProps(self):
+ return self.custom_props
+
# these are called by the Builder

def requestSubmitted(self, builder):
@@ -175,6 +183,9 @@
self.source = requests[0].mergeWith(requests[1:])
self.reason = requests[0].mergeReasons(requests[1:])

+ # Set custom properties.
+ self.custom_properties = requests[0].customProps()
+
#self.abandoned = False

self.progress = None
@@ -202,8 +213,10 @@
self.build_status.setProperty(propname, value)

def getProperty(self, propname):
- return self.build_status.properties[propname]
-
+ if self.build_status.properties.has_key(propname):
+ return self.build_status.properties[propname]
+ else:
+ return None

def allChanges(self):
return self.source.changes
@@ -267,8 +280,13 @@
self.build_status = build_status
self.setProperty("buildername", self.builder.name)
self.setProperty("buildnumber", self.build_status.number)
+ self.setProperty("username", self.source.username)
self.setProperty("branch", self.source.branch)
self.setProperty("revision", self.source.revision)
+ cp = self.custom_properties
+ if cp:
+ for key,userProp in cp.iteritems():
+ self.setProperty(key,userProp)

def setupSlaveBuilder(self, slavebuilder):
self.slavebuilder = slavebuilder
diff -Nuar buildbot-0.7.5.orig/buildbot/sourcestamp.py 
buildbot-0.7.5/buildbot/sourcestamp.py
--- buildbot-0.7.5.orig/buildbot/sourcestamp.py 2006-12-10 
21:40:11.000000000 -0800
+++ buildbot-0.7.5/buildbot/sourcestamp.py 2007-01-03 14:54:33.000000000 
-0800
@@ -32,8 +32,9 @@
else:
__implements__ = interfaces.ISourceStamp,

- def __init__(self, branch=None, revision=None, patch=None,
- changes=None):
+ def __init__(self, branch=None, revision=None,
+ patch=None, changes=None, username=None):
+ self.username = username
self.branch = branch
self.revision = revision
self.patch = patch
@@ -77,7 +78,8 @@
for req in others:
assert self.canBeMergedWith(req) # should have been checked already 
changes.extend(req.changes)
- newsource = SourceStamp(branch=self.branch,
+ newsource = SourceStamp(username=self.username,
+ branch=self.branch,
revision=self.revision,
patch=self.patch,
changes=changes)
diff -Nuar buildbot-0.7.5.orig/buildbot/status/builder.py 
buildbot-0.7.5/buildbot/status/builder.py
--- buildbot-0.7.5.orig/buildbot/status/builder.py 2006-12-10 
21:40:11.000000000 -0800
+++ buildbot-0.7.5/buildbot/status/builder.py 2006-12-18 
17:00:26.000000000 -0800
@@ -1786,6 +1786,8 @@
return self.botmaster.parent.projectURL
def getBuildbotURL(self):
return self.botmaster.parent.buildbotURL
+ def getCustomBuildProperties(self):
+ return self.botmaster.parent.customBuildProperties

def getURLForThing(self, thing):
prefix = self.getBuildbotURL()
diff -Nuar buildbot-0.7.5.orig/buildbot/status/html.py 
buildbot-0.7.5/buildbot/status/html.py
--- buildbot-0.7.5.orig/buildbot/status/html.py 2006-12-10 
21:40:11.000000000 -0800
+++ buildbot-0.7.5/buildbot/status/html.py 2006-12-21 16:08:26.000000000 
-0800
@@ -3,6 +3,7 @@
from __future__ import generators

from twisted.python import log, components
+from twisted.python.util import sibpath
import urllib, re

from twisted.internet import defer, reactor
@@ -538,6 +539,7 @@
"<input type='text' name='branch' />")
+ make_row("Revision to build:",
"<input type='text' name='revision' />")
+ + self.make_user_defined_rows()
+ """
<input type='submit' value='Force Build' />
</form>
@@ -560,12 +562,46 @@

return data

+ # Providing the users custom properties are set in the master.cfg file
+ # this method will generate custom widgets (text fields, radio buttons and
+ # check boxes) for the slave build page. The method returns a html string
+ # representing the widgets. This string is added to the body of the slave
+ # build page.
+ def make_user_defined_rows(self):
+ userDefRows = name = type = label = value = ""
+ customBuildProperties = self.status.getCustomBuildProperties()
+ if customBuildProperties:
+ for property in customBuildProperties:
+ name = property['propertyName']
+ type = property['propertyType']
+ label = property['propertyLabel']
+ if type == 'radio':
+ value = properties['groupValue']
+ field = "<input type=" + "\'" + type + "\'" + "name=" + "\'" + \
+ name + "\'" + "value=" + "\'" + value + "\'" + " />"
+ else:
+ field = "<input type=" + "\'" + type + "\'" + \
+ "name=" + "\'" + name + "\'" + " />"
+
+ userDefRows += make_row(label, field)
+
+ return userDefRows
+
def force(self, request):
name = request.args.get("username", ["<unknown>"])[0]
reason = request.args.get("comments", ["<no reason specified>"])[0]
branch = request.args.get("branch", [""])[0]
revision = request.args.get("revision", [""])[0]

+ # Custom properties.
+ custom_props = {}
+ forceBuildProperties = self.status.getCustomBuildProperties()
+ if forceBuildProperties:
+ for dict in forceBuildProperties:
+ for key, value in dict.iteritems():
+ if key == 'propertyName':
+ custom_props[value] = request.args.get(value, [""])[0]
+
r = "The web-page 'force build' button was pressed by '%s': %s\n" \
% (name, reason)
log.msg("web forcebuild of builder '%s', branch='%s', revision='%s'"
@@ -592,8 +628,8 @@
# TODO: if we can authenticate that a particular User pushed the
# button, use their name instead of None, so they'll be informed of
# the results.
- s = SourceStamp(branch=branch, revision=revision)
- req = BuildRequest(r, s, self.builder.getName())
+ s = SourceStamp(username=name, branch=branch, revision=revision)
+ req = BuildRequest(r, s, self.builder.getName(), custom_props)
try:
self.control.requestBuildSoon(req)
except interfaces.NoSlaveError:
diff -Nuar buildbot-0.7.5.orig/buildbot/steps/shell.py 
buildbot-0.7.5/buildbot/steps/shell.py
--- buildbot-0.7.5.orig/buildbot/steps/shell.py 2006-12-10 
21:40:12.000000000 -0800
+++ buildbot-0.7.5/buildbot/steps/shell.py 2007-01-09 11:40:42.000000000 
-0800
@@ -22,16 +22,19 @@

compare_attrs = ('fmtstring', 'args')

- def __init__(self, fmtstring, *args):
+ def __init__(self, fmtstring, *args, **kwargs):
self.fmtstring = fmtstring
self.args = args
+ self.kwargs = kwargs

def render(self, build):
if self.args:
strings = []
for name in self.args:
p = build.getProperty(name)
- if p is None:
+ if p is None and self.kwargs.has_key(name):
+ p = self.kwargs[name]
+ elif p is None:
p = ""
strings.append(p)
s = self.fmtstring % tuple(strings)

Thanks,
Minesh Patel


buildbot-devel-request at lists.sourceforge.net wrote:
> Send Buildbot-devel mailing list submissions to
> 	buildbot-devel at lists.sourceforge.net
>
> To subscribe or unsubscribe via the World Wide Web, visit
> 	https://lists.sourceforge.net/lists/listinfo/buildbot-devel
> or, via email, send a message with subject or body 'help' to
> 	buildbot-devel-request at lists.sourceforge.net
>
> You can reach the person managing the list at
> 	buildbot-devel-owner at lists.sourceforge.net
>
> When replying, please edit your Subject line so it is more specific
> than "Re: Contents of Buildbot-devel digest..."
>
>
> Today's Topics:
>
>    1. Accessing Build Parameters from LogObserver (Tim Flink)
>    2. parallel steps (christian unger)
>    3. [patch] user build properties (paul.gain at virgin.net)
>    4.  Patch for custom build properties (Paul Gain)
>
>
> ----------------------------------------------------------------------
>
> Message: 1
> Date: Wed, 15 Nov 2006 13:24:42 +0900
> From: Tim Flink <tim at mail.mew.co.jp>
> Subject: [Buildbot-devel] Accessing Build Parameters from LogObserver
> To: buildbot-devel at lists.sourceforge.net
> Message-ID: <455A968A.7050905 at mail.mew.co.jp>
> Content-Type: text/plain; charset=ISO-8859-1; format=flowed
>
> I am using Buildbot 0.7.4 on a C++ project with unit tests and I would 
> like to have a new bug created in my bug tracking system when a test 
> fails on the build. I have been able to add a bug when a test fails but 
> I would like to include more information about the build like the build 
> number, the user responsible for the build and the SVN revision number 
> but I'm having trouble accessing that information from the LogLineObserver.
>
> Is there a good way to access these properties from the LogLineObserver? 
> If not, is there a way to pass non-standard parameters into the 
> LogLineObserver without changing the buildbot source?
>
> Thanks in advance for your time,
>
> Tim
>
>
>
> from buildbot.process.step import ShellCommand, LogLineObserver, 
> WithProperties
> from makeFailureTicket import makeTicket
>  
> class TracIssueReporter(LogLineObserver):
>     buildNumber = 0
>     properties = ""
>    
>     def outLineReceived(self, line):
>         if "error:" in line:
>             
> makeTicket('/etc/tracTest.conf',self.buildNumber,self.properties)
>    
>     def setProperties(self,args):
>         self.properties = args['properties']
>            
>  
> class RunUtppTests(ShellCommand):
>     command = ["scons test"]
>     properties = "not changed"
>     name = "utppTest"
>     warnOnFailure = 1
>     description = ["Running UTPP Tests"]
>     descriptionDone = ["UTPP Tests"]
>     
>     def __init__(self, **kwargs):
>         ShellCommand.__init__(self, **kwargs)   # always upcall!
>         reporter = TracIssueReporter()
>         self.addLogObserver('stdio', reporter)
>
>
>
> ------------------------------
>
> Message: 2
> Date: Wed, 15 Nov 2006 11:47:05 +0100
> From: christian unger <christian_unger at mac.com>
> Subject: [Buildbot-devel] parallel steps
> To: buildbot-devel <buildbot-devel at lists.sourceforge.net>
> Message-ID: <B03AA941-C132-41B8-BEFE-197378C97AFD at mac.com>
> Content-Type: text/plain; charset=US-ASCII; delsp=yes; format=flowed
>
>
> Hi,
>
> is it possible to checkout multiple modules from a repository in  
> parallel?
>
> how can I work with build phases such that I create a dependency  
> table which detemines which projects are able to build in parallel?
>
>
> Is there a way to have two builders work in the same directory when  
> using dependent schedulers?
>
> cu
> christian unger
> ______________
>
>
>
> ------------------------------
>
> Message: 3
> Date: Wed, 15 Nov 2006 16:00:59 +0000 (UTC)
> From: "paul.gain at virgin.net" <paul.gain at virgin.net>
> Subject: [Buildbot-devel] [patch] user build properties
> To: buildbot-devel at lists.sourceforge.net
> Message-ID: <49900.1163606459074.JavaMail.?@fh1006.dia.cp.net>
> Content-Type: text/plain;charset="UTF-8"
>
> Hi 
>
> I have a patch below that enables users to easily add widgets (e.g. text fields, 
> radio buttons and check boxes) to the slave/force build page.  Once the 
> user has added their properties they can easily be retrieved via a build 
> step such as a clean build step (e.g. extend buildbot.process.step.Compile) 
> with the following method call(s).
>
> ticked = self.getProperty('check_box')
> message = self.getProperty('text_field')
> maleFemale = self.getProperty('radio_group')
>
>
> For testing I used the following class:
>
> from buildbot.process.step import Compile
>
> class CleanBuild(Compile):
>
> 	name = "Clean Build"
>         description = ["Clean Build"]
>         descriptionDone = ["Done"]
>
>         def getText(self, cmd, results):
>
> 		cb = ["Clean Build"]                
>                 
> 		ticked = self.getProperty('check_box')
> 		if ticked == 'on':
>                 	cb.append('Yes')
>                 else:
>                 	cb.append('No')
>
>                 message = self.getProperty('text_field')
>                 cb.append(message)
>                                 
>                 mf = self.getProperty('radio_group')                
>                 if mf == 'm':
>                     cb.append('male')              	
>                 if mf == 'f':
>                     cb.append('female')
>         
>                 return cb
>
> Here is the patch:
>
> ### Eclipse Workspace Patch 1.0
> #P buildbot_new
> Index: buildbot/status/html.py
> ===================================================================
> RCS file: /cvsroot/buildbot/buildbot/buildbot/status/html.py,v
> retrieving revision 1.92
> diff -u -r1.92 html.py
> --- buildbot/status/html.py	2 Oct 2006 00:13:32 -0000	1.92
> +++ buildbot/status/html.py	15 Nov 2006 15:21:32 -0000
> @@ -538,6 +538,8 @@
>                             "<input type='text' name='branch' />")
>                  + make_row("Revision to build:",
>                             "<input type='text' name='revision' />")
> +                + self.make_user_defined_rows()
> +
>                  + """
>                  <input type='submit' value='Force Build' />
>                  </form>
> @@ -560,12 +562,45 @@
>  
>          return data
>  
> +    # Providing the users custom properties are set in the master.cfg file 
> +    # this method will generate custom widgets (text fields, radio buttons 
> and
> +    # check boxes) for the slave build page. The method returns a html string 
> +    # representing the widgets. This string is added to the body of the 
> slave 
> +    # build page.
> +    def make_user_defined_rows(self):
> +        userDefRows = name = type = label = value = ""
> +        customBuildProperties = self.status.getCustomBuildProperties()    
> +        for properties in customBuildProperties:
> +            name = properties['propertyName']
> +            type = properties['propertyType']
> +            label = properties['propertyLabel']                
> +            if type == 'radio':                
> +                value = properties['groupValue']
> +                field = "<input type=" + "\'" + type + "\'" + "name=" 
> + "\'" + \
> +                                name + "\'" + "value=" + "\'" + value 
> + "\'" + " />"
> +            else:
> +                field = "<input type=" + "\'" + type + "\'" +  \
> +                                "name=" + "\'" + name + "\'" + " />"
> +
> +            userDefRows += make_row(label, field)
> +            name = type = label = value = ""
> +
> +        return userDefRows
> +
>      def force(self, request):
>          name = request.args.get("username", ["<unknown>"])[0]
>          reason = request.args.get("comments", ["<no reason specified>"])
> [0]
>          branch = request.args.get("branch", [""])[0]
>          revision = request.args.get("revision", [""])[0]
>  
> +        # Custom properties.
> +        custom_props = {}           
> +        forceBuildProperties = self.status.getCustomBuildProperties()    
> +        for dict in forceBuildProperties:
> +            for key, value in dict.iteritems():            	
> +               if key == 'propertyName':
> +                   custom_props[value] = request.args.get(value, [""])
> [0]
> +
>          r = "The web-page 'force build' button was pressed by '%s': %s\n" 
> \
>              % (name, reason)
>          log.msg("web forcebuild of builder '%s', branch='%s', revision='%
> s'"
> @@ -593,7 +628,7 @@
>          # button, use their name instead of None, so they'll be informed 
> of
>          # the results.
>          s = SourceStamp(branch=branch, revision=revision)
> -        req = BuildRequest(r, s, self.builder.getName())
> +        req = BuildRequest(r, s, custom_props, self.builder.getName())
>          try:
>              self.control.requestBuildSoon(req)
>          except interfaces.NoSlaveError:
> Index: buildbot/status/builder.py
> ===================================================================
> RCS file: /cvsroot/buildbot/buildbot/buildbot/status/builder.py,v
> retrieving revision 1.88
> diff -u -r1.88 builder.py
> --- buildbot/status/builder.py	15 Sep 2006 14:48:53 -0000	1.88
> +++ buildbot/status/builder.py	15 Nov 2006 15:21:31 -0000
> @@ -1777,6 +1777,8 @@
>          return self.botmaster.parent.projectURL
>      def getBuildbotURL(self):
>          return self.botmaster.parent.buildbotURL
> +    def getCustomBuildProperties(self):
> +    	return self.botmaster.parent.customBuildProperties
>  
>      def getURLForThing(self, thing):
>          prefix = self.getBuildbotURL()
> Index: buildbot/process/base.py
> ===================================================================
> RCS file: /cvsroot/buildbot/buildbot/buildbot/process/base.py,v
> retrieving revision 1.71
> diff -u -r1.71 base.py
> --- buildbot/process/base.py	25 Sep 2006 02:43:56 -0000	1.71
> +++ buildbot/process/base.py	15 Nov 2006 15:21:31 -0000
> @@ -39,6 +39,9 @@
>                    provide this, but for forced builds the user requesting 
> the
>                    build will provide a string.
>  
> +    @type custom_props: dictionary.
> +    @ivar custom_props: custom user properties.
> +
>      @ivar status: the IBuildStatus object which tracks our status
>  
>      @ivar submittedAt: a timestamp (seconds since epoch) when this request
> @@ -49,18 +52,20 @@
>      source = None
>      builder = None
>      startCount = 0 # how many times we have tried to start this build
> +    custom_props = {}
>  
>      if implements:
>          implements(interfaces.IBuildRequestControl)
>      else:
>          __implements__ = interfaces.IBuildRequestControl,
>  
> -    def __init__(self, reason, source, builderName=None):
> +    def __init__(self, reason, source, custom_props, builderName=None):
>          # TODO: remove the =None on builderName, it is there so I don't 
> have
>          # to change a lot of tests that create BuildRequest objects
>          assert interfaces.ISourceStamp(source, None)
>          self.reason = reason
>          self.source = source
> +        self.custom_props = custom_props
>          self.start_watchers = []
>          self.finish_watchers = []
>          self.status = BuildRequestStatus(source, builderName)
> @@ -87,6 +92,9 @@
>          self.finish_watchers.append(d)
>          return d
>  
> +    def customProps(self):
> +    	return self.custom_props;
> +
>      # these are called by the Builder
>  
>      def requestSubmitted(self, builder):
> @@ -175,6 +183,9 @@
>          self.source = requests[0].mergeWith(requests[1:])
>          self.reason = requests[0].mergeReasons(requests[1:])
>  
> +        # Set custom properties.
> +        self.custom_properties = requests[0].customProps()
> +
>          #self.abandoned = False
>  
>          self.progress = None
> @@ -269,6 +280,9 @@
>          self.setProperty("buildnumber", self.build_status.number)
>          self.setProperty("branch", self.source.branch)
>          self.setProperty("revision", self.source.revision)
> +        cp = self.custom_properties
> +        for key,userProp in cp.iteritems():
> +        	self.setProperty(key,userProp)
>  
>      def setupSlaveBuilder(self, slavebuilder):
>          self.slavebuilder = slavebuilder
> Index: buildbot/master.py
> ===================================================================
> RCS file: /cvsroot/buildbot/buildbot/buildbot/master.py,v
> retrieving revision 1.97
> diff -u -r1.97 master.py
> --- buildbot/master.py	17 Sep 2006 20:43:39 -0000	1.97
> +++ buildbot/master.py	15 Nov 2006 15:21:31 -0000
> @@ -543,6 +543,7 @@
>      projectURL = None
>      buildbotURL = None
>      change_svc = None
> +    customBuildProperties = None
>  
>      def __init__(self, basedir, configFileName="master.cfg"):
>          service.MultiService.__init__(self)
> @@ -694,7 +695,8 @@
>  
>          known_keys = "bots sources schedulers builders slavePortnum " 
> + \
>                       "debugPassword manhole " + \
> -                     "status projectName projectURL buildbotURL"
> +                     "status projectName projectURL buildbotURL " + \
> +                     "customBuildProperties"
>          known_keys = known_keys.split()
>          for k in config.keys():
>              if k not in known_keys:
> @@ -715,6 +717,7 @@
>              projectName = config.get('projectName')
>              projectURL = config.get('projectURL')
>              buildbotURL = config.get('buildbotURL')
> +            customBuildProperties = config.get('customBuildProperties')
>  
>          except KeyError, e:
>              log.msg("config dictionary is missing a required parameter")
> @@ -818,6 +821,7 @@
>          self.projectName = projectName
>          self.projectURL = projectURL
>          self.buildbotURL = buildbotURL
> +        self.customBuildProperties = customBuildProperties
>  
>          # self.bots: Disconnect any that were attached and removed from the
>          # list. Update self.checker with the new list of passwords,
> Index: buildbot/scripts/sample.cfg
> ===================================================================
> RCS file: /cvsroot/buildbot/buildbot/buildbot/scripts/sample.cfg,v
> retrieving revision 1.12
> diff -u -r1.12 sample.cfg
> --- buildbot/scripts/sample.cfg	22 Sep 2006 05:46:28 -0000	1.12
> +++ buildbot/scripts/sample.cfg	15 Nov 2006 15:21:31 -0000
> @@ -173,3 +173,31 @@
>  # without some help.
>  
>  c['buildbotURL'] = "http://localhost:8010/"
> +
> +###### CUSTOM BUILD PROPERTIES FOR THE SLAVE BUILD PAGE.
> +
> +"""
> +textField = {'propertyName' : 'text_field',
> +             'propertyType' : 'text',
> +             'propertyLabel': 'Text Label',
> +             }
> +
> +checkBox = {'propertyName' : 'check_box',
> +            'propertyType' : 'checkbox',
> +            'propertyLabel': 'Check Box',
> +            }
> +
> +radio1 = {'propertyName' : 'radio_group',
> +          'propertyType' : 'radio',
> +          'propertyLabel': 'Male',
> +          'groupValue'   : 'm',
> +          }
> +
> +radio2 = {'propertyName' : 'radio_group',
> +          'propertyType' : 'radio',
> +          'propertyLabel': 'Female',
> +          'groupValue'   : 'f',
> +          }
> +
> +c['customBuildProperties'] = [textField, checkBox, radio1, radio2]
> +"""
>
> I'm fairly new to Python to if you spot an error please let me know.
>
> Regards
>
> Paul Gain
>
>
>
>
>
>
>
> ------------------------------
>
> Message: 4
> Date: Wed, 15 Nov 2006 19:45:35 -0000
> From: "Paul Gain" <paul.gain at virgin.net>
> Subject: [Buildbot-devel]  Patch for custom build properties
> To: <Buildbot-devel at lists.sourceforge.net>
> Message-ID: <009001c708ee$9f418b60$37560352 at paul>
> Content-Type: text/plain; charset="iso-8859-1"
>
> Hi 
>
> I have a patch below that enables users to easily add widgets (e.g. text fields, radio buttons and check boxes) to the slave/force build page.  Once the user has added their properties they can easily be retrieved via a build step such as a clean build step (e.g. extend buildbot.process.step.Compile) with the following method call(s).
>
> ticked = self.getProperty('check_box')
> message = self.getProperty('text_field')
> maleFemale = self.getProperty('radio_group')
>
>
> For testing I used the following class:
>
> from buildbot.process.step import Compile
>
> class CleanBuild(Compile):
>
>  name = "Clean Build"
>         description = ["Clean Build"]
>         descriptionDone = ["Done"]
>
>         def getText(self, cmd, results):
>
>   cb = ["Clean Build"]                
>                 
>   ticked = self.getProperty('check_box')
>   if ticked == 'on':
>                  cb.append('Yes')
>                 else:
>                  cb.append('No')
>
>                 message = self.getProperty('text_field')
>                 cb.append(message)
>                                 
>                 mf = self.getProperty('radio_group')                
>                 if mf == 'm':
>                     cb.append('male')               
>                 if mf == 'f':
>                     cb.append('female')
>         
>                 return cb
>
> Here is the patch:
>
> ### Eclipse Workspace Patch 1.0
> #P buildbot_new
> Index: buildbot/status/html.py
> ===================================================================
> RCS file: /cvsroot/buildbot/buildbot/buildbot/status/html.py,v
> retrieving revision 1.92
> diff -u -r1.92 html.py
> --- buildbot/status/html.py 2 Oct 2006 00:13:32 -0000 1.92
> +++ buildbot/status/html.py 15 Nov 2006 15:21:32 -0000
> @@ -538,6 +538,8 @@
>                             "<input type='text' name='branch' />")
>                  + make_row("Revision to build:",
>                             "<input type='text' name='revision' />")
> +                + self.make_user_defined_rows()
> +
>                  + """
>                  <input type='submit' value='Force Build' />
>                  </form>
> @@ -560,12 +562,45 @@
>  
>          return data
>  
> +    # Providing the users custom properties are set in the master.cfg file 
> +    # this method will generate custom widgets (text fields, radio buttons and
> +    # check boxes) for the slave build page. The method returns a html string 
> +    # representing the widgets. This string is added to the body of the slave 
> +    # build page.
> +    def make_user_defined_rows(self):
> +        userDefRows = name = type = label = value = ""
> +        customBuildProperties = self.status.getCustomBuildProperties()    
> +        for properties in customBuildProperties:
> +            name = properties['propertyName']
> +            type = properties['propertyType']
> +            label = properties['propertyLabel']                
> +            if type == 'radio':                
> +                value = properties['groupValue']
> +                field = "<input type=" + "\'" + type + "\'" + "name=" + "\'" + \
> +                                name + "\'" + "value=" + "\'" + value + "\'" + " />"
> +            else:
> +                field = "<input type=" + "\'" + type + "\'" +  \
> +                                "name=" + "\'" + name + "\'" + " />"
> +
> +            userDefRows += make_row(label, field)
> +            name = type = label = value = ""
> +
> +        return userDefRows
> +
>      def force(self, request):
>          name = request.args.get("username", ["<unknown>"])[0]
>          reason = request.args.get("comments", ["<no reason specified>"])[0]
>          branch = request.args.get("branch", [""])[0]
>          revision = request.args.get("revision", [""])[0]
>  
> +        # Custom properties.
> +        custom_props = {}           
> +        forceBuildProperties = self.status.getCustomBuildProperties()    
> +        for dict in forceBuildProperties:
> +            for key, value in dict.iteritems():             
> +               if key == 'propertyName':
> +                   custom_props[value] = request.args.get(value, [""])[0]
> +
>          r = "The web-page 'force build' button was pressed by '%s': %s\n" \
>              % (name, reason)
>          log.msg("web forcebuild of builder '%s', branch='%s', revision='%s'"
> @@ -593,7 +628,7 @@
>          # button, use their name instead of None, so they'll be informed of
>          # the results.
>          s = SourceStamp(branch=branch, revision=revision)
> -        req = BuildRequest(r, s, self.builder.getName())
> +        req = BuildRequest(r, s, custom_props, self.builder.getName())
>          try:
>              self.control.requestBuildSoon(req)
>          except interfaces.NoSlaveError:
> Index: buildbot/status/builder.py
> ===================================================================
> RCS file: /cvsroot/buildbot/buildbot/buildbot/status/builder.py,v
> retrieving revision 1.88
> diff -u -r1.88 builder.py
> --- buildbot/status/builder.py 15 Sep 2006 14:48:53 -0000 1.88
> +++ buildbot/status/builder.py 15 Nov 2006 15:21:31 -0000
> @@ -1777,6 +1777,8 @@
>          return self.botmaster.parent.projectURL
>      def getBuildbotURL(self):
>          return self.botmaster.parent.buildbotURL
> +    def getCustomBuildProperties(self):
> +     return self.botmaster.parent.customBuildProperties
>  
>      def getURLForThing(self, thing):
>          prefix = self.getBuildbotURL()
> Index: buildbot/process/base.py
> ===================================================================
> RCS file: /cvsroot/buildbot/buildbot/buildbot/process/base.py,v
> retrieving revision 1.71
> diff -u -r1.71 base.py
> --- buildbot/process/base.py 25 Sep 2006 02:43:56 -0000 1.71
> +++ buildbot/process/base.py 15 Nov 2006 15:21:31 -0000
> @@ -39,6 +39,9 @@
>                    provide this, but for forced builds the user requesting the
>                    build will provide a string.
>  
> +    @type custom_props: dictionary.
> +    @ivar custom_props: custom user properties.
> +
>      @ivar status: the IBuildStatus object which tracks our status
>  
>      @ivar submittedAt: a timestamp (seconds since epoch) when this request
> @@ -49,18 +52,20 @@
>      source = None
>      builder = None
>      startCount = 0 # how many times we have tried to start this build
> +    custom_props = {}
>  
>      if implements:
>          implements(interfaces.IBuildRequestControl)
>      else:
>          __implements__ = interfaces.IBuildRequestControl,
>  
> -    def __init__(self, reason, source, builderName=None):
> +    def __init__(self, reason, source, custom_props, builderName=None):
>          # TODO: remove the =None on builderName, it is there so I don't have
>          # to change a lot of tests that create BuildRequest objects
>          assert interfaces.ISourceStamp(source, None)
>          self.reason = reason
>          self.source = source
> +        self.custom_props = custom_props
>          self.start_watchers = []
>          self.finish_watchers = []
>          self.status = BuildRequestStatus(source, builderName)
> @@ -87,6 +92,9 @@
>          self.finish_watchers.append(d)
>          return d
>  
> +    def customProps(self):
> +     return self.custom_props;
> +
>      # these are called by the Builder
>  
>      def requestSubmitted(self, builder):
> @@ -175,6 +183,9 @@
>          self.source = requests[0].mergeWith(requests[1:])
>          self.reason = requests[0].mergeReasons(requests[1:])
>  
> +        # Set custom properties.
> +        self.custom_properties = requests[0].customProps()
> +
>          #self.abandoned = False
>  
>          self.progress = None
> @@ -269,6 +280,9 @@
>          self.setProperty("buildnumber", self.build_status.number)
>          self.setProperty("branch", self.source.branch)
>          self.setProperty("revision", self.source.revision)
> +        cp = self.custom_properties
> +        for key,userProp in cp.iteritems():
> +         self.setProperty(key,userProp)
>  
>      def setupSlaveBuilder(self, slavebuilder):
>          self.slavebuilder = slavebuilder
> Index: buildbot/master.py
> ===================================================================
> RCS file: /cvsroot/buildbot/buildbot/buildbot/master.py,v
> retrieving revision 1.97
> diff -u -r1.97 master.py
> --- buildbot/master.py 17 Sep 2006 20:43:39 -0000 1.97
> +++ buildbot/master.py 15 Nov 2006 15:21:31 -0000
> @@ -543,6 +543,7 @@
>      projectURL = None
>      buildbotURL = None
>      change_svc = None
> +    customBuildProperties = None
>  
>      def __init__(self, basedir, configFileName="master.cfg"):
>          service.MultiService.__init__(self)
> @@ -694,7 +695,8 @@
>  
>          known_keys = "bots sources schedulers builders slavePortnum " + \
>                       "debugPassword manhole " + \
> -                     "status projectName projectURL buildbotURL"
> +                     "status projectName projectURL buildbotURL " + \
> +                     "customBuildProperties"
>          known_keys = known_keys.split()
>          for k in config.keys():
>              if k not in known_keys:
> @@ -715,6 +717,7 @@
>              projectName = config.get('projectName')
>              projectURL = config.get('projectURL')
>              buildbotURL = config.get('buildbotURL')
> +            customBuildProperties = config.get('customBuildProperties')
>  
>          except KeyError, e:
>              log.msg("config dictionary is missing a required parameter")
> @@ -818,6 +821,7 @@
>          self.projectName = projectName
>          self.projectURL = projectURL
>          self.buildbotURL = buildbotURL
> +        self.customBuildProperties = customBuildProperties
>  
>          # self.bots: Disconnect any that were attached and removed from the
>          # list. Update self.checker with the new list of passwords,
> Index: buildbot/scripts/sample.cfg
> ===================================================================
> RCS file: /cvsroot/buildbot/buildbot/buildbot/scripts/sample.cfg,v
> retrieving revision 1.12
> diff -u -r1.12 sample.cfg
> --- buildbot/scripts/sample.cfg 22 Sep 2006 05:46:28 -0000 1.12
> +++ buildbot/scripts/sample.cfg 15 Nov 2006 15:21:31 -0000
> @@ -173,3 +173,31 @@
>  # without some help.
>  
>  c['buildbotURL'] = "http://localhost:8010/"
> +
> +###### CUSTOM BUILD PROPERTIES FOR THE SLAVE BUILD PAGE.
> +
> +"""
> +textField = {'propertyName' : 'text_field',
> +             'propertyType' : 'text',
> +             'propertyLabel': 'Text Label',
> +             }
> +
> +checkBox = {'propertyName' : 'check_box',
> +            'propertyType' : 'checkbox',
> +            'propertyLabel': 'Check Box',
> +            }
> +
> +radio1 = {'propertyName' : 'radio_group',
> +          'propertyType' : 'radio',
> +          'propertyLabel': 'Male',
> +          'groupValue'   : 'm',
> +          }
> +
> +radio2 = {'propertyName' : 'radio_group',
> +          'propertyType' : 'radio',
> +          'propertyLabel': 'Female',
> +          'groupValue'   : 'f',
> +          }
> +
> +c['customBuildProperties'] = [textField, checkBox, radio1, radio2]
> +"""
>
> I'm fairly new to Python to if you spot an error please let me know.
>
> Regards
>
> Paul Gain
> -------------- next part --------------
> An HTML attachment was scrubbed...
> URL: http://sourceforge.net/mailarchive/forum.php?forum=buildbot-devel/attachments/20061115/5b55e574/attachment.html 
>
> ------------------------------
>
> -------------------------------------------------------------------------
> Take Surveys. Earn Cash. Influence the Future of IT
> Join SourceForge.net's Techsay panel and you'll get the chance to share your
> opinions on IT & business topics through brief surveys - and earn cash
> http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
>
> ------------------------------
>
> _______________________________________________
> Buildbot-devel mailing list
> Buildbot-devel at lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/buildbot-devel
>
>
> End of Buildbot-devel Digest, Vol 7, Issue 17
> *********************************************
>   





More information about the devel mailing list