# -*- python -*- # ex: set syntax=python: from buildbot.plugins import * from buildbot.plugins import buildslave, util # This is a sample buildmaster config file. It must be installed as # 'master.cfg' in your buildmaster's base directory. # This is the dictionary that the buildmaster pays attention to. We also use # a shorter alias to save typing. c = BuildmasterConfig = {} quaggagit = 'git://git.sv.gnu.org/quagga.git' # password defs execfile("pass.cfg") # filter a given 'workers' entry into a property list # suitable for public display def workers2publicprops (worker): publicprops = [ "os", "version", "vm", "pkg", "texi", "cc", "latent", ] return { k:worker[k] for k in worker if k in publicprops } # vm: non-VM are assumed faster and used for initial build # pkg: rpm, sysv, dpkg - only do test rpm builds at moment # texi: True or "true" if we can use for doc building # cc: List of tuples of installed compilers, with: # (, , ) # tag: gcc, clang, sunpro # latent: VM spun up on demand via LatentSlave, uses "session" for # the libvirt URI. # session: libvirt URI to use for latent workers. Default will be set on # latent VMs if not specified. # hd_image: libvirt image to use workers = { "fedora-24": { "os": "Fedora", "version": "24", "vm": False, "pkg": "rpm", "texi": True, "cc": [ ("gcc", "6.3.1"), ("clang", "3.8.1"), ("gcc", "3.4.6", "gcc34"), ], }, "fedora-26": { "os": "Fedora", "version": "26", "vm": False, "pkg": "rpm", "cc": [ ("gcc", "7.0.1"), ("clang", "3.9.0"), ("gcc", "3.4.6", "gcc34"), ], }, "centos-7": { "os": "CentOS", "version": "7", "vm": False, "pkg": "rpm", "cc": [ ("gcc", "4.8.5") ], }, "debian-8": { "os": "Debian", "version": "8", "vm": True, "pkg": "dpkg", "latent": True, "cc": [ ("gcc", "4.9.2") ], "hd_image": "/var/lib/libvirt/images/debian8.qcow2", }, "debian-9": { "os": "Debian", "version": "9", "vm": True, "pkg": "dpkg", "cc": [ ("gcc", "6.3.0") ], "latent": True, "hd_image": "/var/lib/libvirt/images/debian9.qcow2", }, "freebsd-10": { "os": "FreeBSD", "version": "10", "vm": True, "pkg": "", "latent": True, "cc": [ ("clang", "3.4.1") ], "hd_image": "/var/lib/libvirt/images/freebsd103.qcow2", }, "freebsd-11": { "os": "FreeBSD", "version": "11", "vm": True, "pkg": "", "cc": [ ("gcc", "4.9.4"), ("clang", "3.8.0"), ], "latent": True, "hd_image": "/var/lib/libvirt/images/freebsd110.qcow2", }, "oi-hipster": { "os": "OpenIndiana", "version": "hipster", "vm": True, "pkg": "sysv", "latent": True, "cc": [ ("gcc", "6.3.0"), ("sunpro", "12.0"), ("gcc", "4.4.4") ], "hd_image": "/var/lib/libvirt/images/buildbot-oi-hipster.qcow2", }, } # ensure "latent" is set to false, where not set. # add in the passwords for kw in workers: w = workers[kw] w["bot"] = "buildbot-" + kw if "latent" not in w: w["latent"] = False w["pass"] = workers_pass[kw] analyses_builders = [ "clang-analyzer" ] # default Libvirt session for w in (w for w in workers.values () if ("latent" in w and w["latent"]) and ("session" not in w)): w["session"] = 'qemu+ssh://buildbot@sagan.jakma.org/system' osbuilders = ["build-" + kw for kw in workers] osfastbuilders = ["build-" + kw for kw in workers if workers[kw]["vm"] == False] osslowbuilders = ["build-" + kw for kw in workers if workers[kw]["vm"] == True] rpmbuilders = ["rpm-" + kw for kw in workers if workers[kw]["pkg"] == "rpm"] # compilers # not using yet # [kw for kw in workers if len([v for (c,v) in workers[kw]["cc"] if c == "gcc"]) > 0 ] allbuilders = [] allbuilders += osbuilders allbuilders += rpmbuilders allbuilders += analyses_builders allbuilders += ["commit-builder"] allbuilders += ["build-distcheck"] allbuilders += ["build-docs" ] # Force merging of requests. # c['mergeRequests'] = lambda *args, **kwargs: True ####### BUILDSLAVES c['slaves'] = [] # The 'slaves' list defines the set of recognized buildslaves. Each element is # a BuildSlave object, specifying a unique slave name and password. The same # slave name and password must be configured on the slave. for w in (w for w in workers.values() if ("latent" not in w) or (w["latent"] == False)): c['slaves'].append(buildslave.BuildSlave(w["bot"], w["pass"], properties=workers2publicprops (w), )) for w in (w for w in workers.values() if ("latent" in w) and w["latent"] and "hd_image" in w): c['slaves'].append(buildslave.LibVirtSlave( w["bot"], w["pass"], util.Connection(w["session"]), w["hd_image"], properties=workers2publicprops (w), )) # 'protocols' contains information about protocols which master will use for # communicating with slaves. # You must define at least 'port' option that slaves could connect to your master # with this protocol. # 'port' must match the value configured into the buildslaves (with their # --master option) c['protocols'] = {'pb': {'port': 9989}} ####### CHANGESOURCES # the 'change_source' setting tells the buildmaster how it should find out # about source code changes. Here we point to the buildbot clone of pyflakes. c['change_source'] = [] c['change_source'].append(changes.GitPoller( quaggagit, workdir='gitpoller-workdir', branches=['master','volatile/next'], pollinterval=300)) ####### REVISION LINKS # associate changesouce repositories to URI templates for code view # c['revlink'] = util.RevlinkMatch([quaggagit + r"(.*)"], r"http://git.savannah.gnu.org/cgit/quagga.git/commit/?id=%s") ####### SCHEDULERS # Configure the Schedulers, which decide how to react to incoming changes. # We want a first line of 'quick' builds, which then trigger further builds. # # A control-flow builder, "commit-builder", used to sequence the 'real' # sets of builders, via Triggers. c['schedulers'] = [] c['schedulers'].append(schedulers.SingleBranchScheduler( name="master-change", change_filter=util.ChangeFilter(branch='master'), treeStableTimer=10, builderNames=[ "commit-builder" ])) c['schedulers'].append(schedulers.SingleBranchScheduler( name="next-change", change_filter=util.ChangeFilter( branch='volatile/next'), treeStableTimer=10, builderNames=[ "commit-builder" ] )) # Initial build checks on faster, non-VM c['schedulers'].append(schedulers.Triggerable( name="trigger-build-first", builderNames=osfastbuilders)) # Build using remaining builders, after firstbuilders. c['schedulers'].append(schedulers.Triggerable( name="trigger-build-rest", builderNames=osslowbuilders)) # Analyses tools, e.g. CLang Analyzer scan-build c['schedulers'].append(schedulers.Triggerable( name="trigger-build-analyses", builderNames=analyses_builders)) # Dist check c['schedulers'].append(schedulers.Triggerable( name="trigger-distcheck", builderNames=["build-distcheck"])) # RPM check and build c['schedulers'].append(schedulers.Triggerable( name="trigger-rpm", builderNames=rpmbuilders)) # Doc build check (non-nightly, so no upload) c['schedulers'].append(schedulers.Triggerable( name="trigger-build-docs", builderNames=["build-docs"])) # Try and force schedulers c['schedulers'].append(schedulers.ForceScheduler( name="force", builderNames=allbuilders)) c['schedulers'].append(schedulers.Try_Userpass( name="try", builderNames=osbuilders + rpmbuilders + ["build-distcheck", "clang-analyzer", "build-docs" ], userpass=users, port=8031)) ## nightly docs build c['schedulers'].append(schedulers.Nightly( name="nightly-docs", branch="master", builderNames=[ "build-docs" ], hour=3, minute=0, onlyIfChanged=True, properties = { "nightly": True }, )) ####### BUILDERS c['builders'] = [] # The 'builders' list defines the Builders, which tell Buildbot how to perform a build: # what steps, and which slaves can execute them. Note that any particular build will # only take place on one slave. common_setup = [ steps.Git(repourl=quaggagit, mode='incremental'), steps.ShellCommand(command=["./update-autotools"], description="generating autoconf", descriptionDone="autoconf"), steps.Configure(command="../build/configure"), steps.ShellCommand(command=["make", "clean"], description="cleaning", descriptionDone="make clean"), ] ### Default 'check' build, builder instantiated for each OS factory = util.BuildFactory() # check out the source factory.addStep(steps.Git(repourl=quaggagit, mode='incremental')) factory.addStep(steps.ShellCommand(command=["./update-autotools"], description="generating autoconf", descriptionDone="autoconf")) factory.addStep(steps.Configure()) factory.addStep(steps.ShellCommand(command=["make", "clean"], description="cleaning", descriptionDone="clean")) #factory.addSteps(common_setup) factory.addStep(steps.Compile(command=["make", "-j", "2", "all"])) factory.addStep(steps.ShellCommand(command=["make", "check"], description="checking", descriptionDone="make check")) # create builder for every OS, for every buildbot # XXX: at moment this assumes 1:1 OS<->bot for kw in workers: c['builders'].append(util.BuilderConfig( name="build-" + kw, slavenames=workers[kw]["bot"], factory=factory)) ### distcheck Builder, executed on any available bot factory = util.BuildFactory() # check out the source factory.addStep(steps.Git(repourl=quaggagit, mode='incremental')) factory.addStep(steps.ShellCommand(command=["./update-autotools"], description="generating autoconf", descriptionDone="autoconf")) factory.addStep(steps.Configure()) factory.addStep(steps.ShellCommand(command=["make", "clean"], description="cleaning", descriptionDone="make clean")) factory.addStep(steps.ShellCommand(command=["make", "distcheck"], description="run make distcheck", descriptionDone="make distcheck")) c['builders'].append( util.BuilderConfig(name="build-distcheck", slavenames=list(w["bot"] for w in workers.values()), factory=factory, )) ### LLVM clang-analyzer build, executed on any available non-VM bot f = util.BuildFactory() # check out the source f.addStep(steps.Git(repourl=quaggagit, mode='incremental', getDescription=True)) f.addStep(steps.ShellCommand(command=["./update-autotools"], description="run autotools", descriptionDone="autoconf")) f.addStep(steps.Configure()) f.addStep(steps.ShellCommand(command=["make", "clean"], description="cleaning", descriptionDone="make clean")) f.addStep(steps.SetProperty(property="clang-id", value=util.Interpolate("%(prop:commit-description)s-%(prop:buildnumber)s"))) f.addStep(steps.SetProperty(property="clang-output-dir", value=util.Interpolate("../CLANG-%(prop:clang-id)s"))) f.addStep(steps.SetProperty(property="clang-uri", value=util.Interpolate("/clang-analyzer/%(prop:clang-id)s"))) # relative to buildbot master working directory f.addStep(steps.SetProperty(property="clang-upload-dir", value=util.Interpolate("public_html/clang-analyzer/%(prop:clang-id)s"))) f.addStep(steps.Compile(command=["scan-build", "-analyze-headers", "-o", util.Interpolate("%(prop:clang-output-dir)s"), "make", "-j", "all"])) f.addStep(steps.DirectoryUpload( slavesrc=util.Interpolate("%(prop:clang-output-dir)s"), masterdest = util.Interpolate("%(prop:clang-upload-dir)s"), compress = 'bz2', name = "clang report", url = util.Interpolate("%(prop:clang-uri)s"), )) f.addStep(steps.RemoveDirectory( dir=util.Interpolate("%(prop:clang-output-dir)s") )) c['builders'].append( util.BuilderConfig(name="clang-analyzer", slavenames=list(w["bot"] for w in workers.values() if not w["vm"]), factory=f)) ### RPM: check and build f = util.BuildFactory () # check out the source f.addStep(steps.Git(repourl=quaggagit, mode='full')) f.addStep(steps.ShellCommand(command=["./update-autotools"], description="run autotools", descriptionDone="autotools")) f.addStep(steps.Configure()) f.addStep(steps.ShellCommand(command=["make", "dist"], description="run make dist", descriptionDone="make dist")) # not imported somehow #f.addStep(steps.RpmLint(fileloc="redhat/quagga.spec")) f.addStep(steps.ShellCommand(command=["rpmlint", "-i", "redhat/quagga.spec"], description="run rpmlint", descriptionDone="rpmlint")) f.addStep(steps.RpmBuild(specfile="redhat/quagga.spec")) # rpmdir=util.Interpolate("%(prop:builddir)s/rpm"))) # XXX: assuming 1:1 OS:buildbot mapping for kw in (kw for kw in workers if workers[kw]["pkg"] == "rpm"): c['builders'].append( util.BuilderConfig(name="rpm-" + kw, slavenames="buildbot-" + kw, factory=f ) ) ### Build documentation def build_is_nightly (step): n = step.getProperty("nightly") if n == True or n == "True" or n == "true": return True return False f = util.BuildFactory () f.addStep(steps.Git(repourl=quaggagit, mode='full')) f.addStep(steps.ShellCommand(command=["./update-autotools"], description="run autotools", descriptionDone="autotools")) f.addStep(steps.Configure(command=["../build/configure"], workdir="docs")) f.addStep(steps.ShellCommand(command=["make", "V=99", "quagga.html"], description="making split HTML doc", descriptionDone="docs: split HTML", workdir="docs/doc", haltOnFailure=True, )) #f.addStep(steps.FileUpload( # slavesrc="build/doc/fig-normal-processing.png", # masterdest = "public_html/docs/nightly/quagga/", # name = "Upload Fig 1", # doStepIf=build_is_nightly, #)) #f.addStep(steps.FileUpload( # slavesrc="build/doc/fig-rs-processing.png", # masterdest = "public_html/docs/nightly/quagga/", # name = "Upload Fig 2", # doStepIf=build_is_nightly, #)) f.addStep(steps.MultipleFileUpload( slavesrcs=[ "doc/fig-rs-processing.png", "doc/fig-normal-processing.png" ], masterdest = "public_html/docs/nightly/quagga/", name = "Upload Figures", doStepIf=build_is_nightly, )) f.addStep(steps.DirectoryUpload( slavesrc="quagga.html", masterdest = "public_html/docs/nightly/quagga", compress = 'bz2', name = "Upload split HTML", url = "/docs/nightly/quagga/index.html", workdir="docs/doc", doStepIf=build_is_nightly, )) f.addStep(steps.RemoveDirectory( dir="docs/doc/quagga.html", )) f.addStep(steps.ShellCommand(command=["make", "V=99", "MAKEINFOFLAGS=--no-split", "quagga.html"], description="making one-page HTML doc", descriptionDone="docs: one-page HTML", workdir="docs/doc", haltOnFailure=True )) f.addStep(steps.FileUpload( slavesrc="quagga.html", masterdest = "public_html/docs/nightly/quagga/quagga.html", name = "Upload single HTML", url = "/docs/nightly/quagga/quagga.html", workdir="docs/doc", doStepIf=build_is_nightly, )) f.addStep(steps.ShellCommand(command=["make", "V=99", "quagga.pdf"], description="making PDF docs", descriptionDone="docs: PDF", workdir="docs/doc" )) f.addStep(steps.FileUpload( slavesrc="quagga.pdf", masterdest = "public_html/docs/nightly/quagga/quagga.pdf", name = "Upload PDF", url = "/docs/nightly/quagga/quagga.pdf", workdir="docs/doc", doStepIf=build_is_nightly, )) c['builders'].append( util.BuilderConfig(name="build-docs", slavenames=[w["bot"] for w in workers.values() if "texi" in w and w["texi"] == True ], factory=f )) ### Co-ordination builds used to sequence parallel builds via Triggerable # to understand this you have to read this list and the Triggered schedulers # to see what sets of builds are being sequenced. Bit clunky, but Buildbot # doesn't have a way to just specify a pipeline of groups of builders more # cleanly. f = util.BuildFactory() f.addStep(steps.Trigger ( schedulerNames = [ "trigger-build-first" ], waitForFinish=True, updateSourceStamp=True )) f.addStep(steps.Trigger ( schedulerNames = [ "trigger-build-rest" ], waitForFinish=True, updateSourceStamp=True )) f.addStep(steps.Trigger ( schedulerNames = [ "trigger-build-analyses", "trigger-distcheck", "trigger-build-docs" ], waitForFinish=True, updateSourceStamp=True )) f.addStep(steps.Trigger ( schedulerNames = [ "trigger-rpm" ], waitForFinish=True, updateSourceStamp=True )) c['builders'].append( util.BuilderConfig(name="commit-builder", slavenames=[w["bot"] for w in workers.values() if not w["vm"]], factory=f) ) ####### STATUS TARGETS # 'status' is a list of Status Targets. The results of each build will be # pushed to these targets. buildbot/status/*.py has a variety to choose from, # including web pages, email senders, and IRC bots. c['status'] = [] from buildbot.status import html from buildbot.status.web import authz, auth authz_cfg=authz.Authz( # change any of these to True to enable; see the manual for more # options #auth=auth.BasicAuth([("pyflakes","pyflakes")]), auth=util.BasicAuth(users), gracefulShutdown = False, forceBuild = 'auth', # use this to test your slave once it is set up forceAllBuilds = 'auth', # ..or this pingBuilder = 'auth', stopBuild = 'auth', stopAllBuilds = 'auth', cancelPendingBuild = 'auth', cancelAllPendingBuilds = 'auth', pauseSlave = 'auth', ) c['status'].append(html.WebStatus(http_port=8010, authz=authz_cfg)) c['status'].append(status.MailNotifier( fromaddr="buildbot@quagga.net", extraRecipients=["paul@jakma.org"], sendToInterestedUsers=False, )) c['status'].append (status.IRC( "irc.freenode.net", "bb-quagga", useColors=True, channels=[{"channel": "#quagga"}], notify_events={ 'exception': 1, 'successToFailure': 1, 'failureToSuccess': 1, }, )) ####### PROJECT IDENTITY # the 'title' string will appear at the top of this buildbot # installation's html.WebStatus home page (linked to the # 'titleURL') and is embedded in the title of the waterfall HTML page. c['title'] = "Quagga" c['titleURL'] = "https://www.quagga.net/" # the 'buildbotURL' string should point to the location where the buildbot's # internal web server (usually the html.WebStatus page) is visible. This # typically uses the port number set in the Waterfall 'status' entry, but # with an externally-visible host name which the buildbot cannot figure out # without some help. c['buildbotURL'] = "http://buildbot.quagga.net/" ####### DB URL c['db'] = { # This specifies what database buildbot uses to store its state. You can leave # this at its default for all but the largest installations. 'db_url' : "sqlite:///state.sqlite", } #### debug c['debugPassword'] = debugPassword