from buildbot.plugins import util, steps, schedulers from buildbot_buildslist import BuildsList __all__ = [ "force_scheduler", "deploy_scheduler", "hook_scheduler", "clean_branch", "package_and_upload", "SlackStatusPush" ] # Small helpers" @util.renderer def clean_branch(props): if props.hasProperty("branch") and len(props["branch"]) > 0: return props["branch"].replace("/", "_") else: return "HEAD" def package_and_upload(package, package_dest, package_url): return [ steps.ShellCommand(name="build package", logEnviron=False, haltOnFailure=True, workdir="source", command=["git", "archive", "HEAD", "-o", package]), steps.FileUpload(name="upload package", workersrc=package, workdir="source", masterdest=package_dest, url=package_url, mode=0o644), steps.ShellCommand(name="cleanup package", logEnviron=False, haltOnFailure=True, workdir="source", alwaysRun=True, command=["rm", "-f", package]), ] # Schedulers def force_scheduler(name, builders): return schedulers.ForceScheduler(name=name, label="Force build", buttonName="Force build", reason=util.StringParameter(name="reason", label="Reason", default="Force build"), codebases=[ util.CodebaseParameter("", branch=util.StringParameter( name="branch", label="Git reference (tag, branch)", required=True), revision=util.FixedParameter(name="revision", default=""), repository=util.FixedParameter(name="repository", default=""), project=util.FixedParameter(name="project", default=""), ), ], username=util.FixedParameter(name="username", default="Web button"), builderNames=builders) def deploy_scheduler(name, builders): return schedulers.ForceScheduler(name=name, builderNames=builders, label="Deploy built package", buttonName="Deploy", username=util.FixedParameter(name="username", default="Web button"), codebases=[ util.CodebaseParameter(codebase="", branch=util.FixedParameter(name="branch", default=""), revision=util.FixedParameter(name="revision", default=""), repository=util.FixedParameter(name="repository", default=""), project=util.FixedParameter(name="project", default=""))], reason=util.FixedParameter(name="reason", default="Deploy"), properties=[ util.ChoiceStringParameter(label="Environment", name="environment", default="integration", choices=["integration", "production"]), BuildsList(label="Build to deploy", name="build"), ] ) def hook_scheduler(project, timer=10): return schedulers.AnyBranchScheduler( change_filter=util.ChangeFilter(category="hooks", project=project), name=project, treeStableTimer=timer, builderNames=["{}_build".format(project)]) # Slack status push from buildbot.reporters.http import HttpStatusPushBase from twisted.internet import defer from twisted.python import log from buildbot.util import httpclientservice from buildbot.reporters import utils from buildbot.process import results class SlackStatusPush(HttpStatusPushBase): name = "SlackStatusPush" @defer.inlineCallbacks def reconfigService(self, serverUrl, **kwargs): yield HttpStatusPushBase.reconfigService(self, **kwargs) self._http = yield httpclientservice.HTTPClientService.getService( self.master, serverUrl) @defer.inlineCallbacks def send(self, build): yield utils.getDetailsForBuild(self.master, build, wantProperties=True) response = yield self._http.post("", json=self.format(build)) if response.code != 200: log.msg("%s: unable to upload status: %s" % (response.code, response.content)) def format(self, build): colors = [ "#36A64F", # success "#F1E903", # warnings "#DA0505", # failure "#FFFFFF", # skipped "#000000", # exception "#FFFFFF", # retry "#D02CA9", # cancelled ] if "environment" in build["properties"]: msg = "{} environment".format(build["properties"]["environment"][0]) if "build" in build["properties"]: msg = "of archive {} in ".format(build["properties"]["build"][0]) + msg elif len(build["buildset"]["sourcestamps"][0]["branch"]) > 0: msg = "revision {}".format(build["buildset"]["sourcestamps"][0]["branch"]) else: msg = "build" if build["complete"]: timedelta = int((build["complete_at"] - build["started_at"]).total_seconds()) hours, rest = divmod(timedelta, 3600) minutes, seconds = divmod(rest, 60) if hours > 0: duration = "{}h {}min {}s".format(hours, minutes, seconds) elif minutes > 0: duration = "{}min {}s".format(minutes, seconds) else: duration = "{}s".format(seconds) text = "Build <{}|{}> of {}'s {} was {} in {}.".format( build["url"], build["buildid"], build["builder"]["name"], msg, results.Results[build["results"]], duration, ) fields = [ { "title": "Build", "value": "<{}|{}>".format(build["url"], build["buildid"]), "short": True, }, { "title": "Project", "value": build["builder"]["name"], "short": True, }, { "title": "Build status", "value": results.Results[build["results"]], "short": True, }, { "title": "Build duration", "value": duration, "short": True, }, ] if "environment" in build["properties"]: fields.append({ "title": "Environment", "value": build["properties"]["environment"][0], "short": True, }) if "build" in build["properties"]: fields.append({ "title": "Archive", "value": build["properties"]["build"][0], "short": True, }) attachments = [{ "fallback": "", "color": colors[build["results"]], "fields": fields }] else: text = "Build <{}|{}> of {}'s {} started.".format( build["url"], build["buildid"], build["builder"]["name"], msg, ) attachments = [] return { "username": "Buildbot", "icon_url": "http://docs.buildbot.net/current/_static/icon.png", "text": text, "attachments": attachments, }