From f8be7a65b659c9bf925af8f629351647337c731c Mon Sep 17 00:00:00 2001
From: Benoit Sigoure <tsuna@lrde.epita.fr>
Date: Wed, 14 Nov 2007 11:39:08 +0100
Subject: [PATCH v4 10/12] Allow patches to be submitted through the web interface.
If and only if user authentication is used to allow force/stop
builds, users can also attach a patch to the `force build' request.
* buildbot/sourcestamp.py (SourceStamp.__init__): Enhance the
documentation.
(make_force_build_form): Add fields to upload a patch and specify a
patch-level.
* buildbot/status/web/builder.py (StatusResourceBuilder.force):
Handle the new fields of the form to allow patches for authenticated
users.
Signed-off-by: Benoit Sigoure <tsuna@lrde.epita.fr>
---
buildbot/sourcestamp.py | 3 ++-
buildbot/status/web/base.py | 16 ++++++++++++++--
buildbot/status/web/builder.py | 30 ++++++++++++++++++++++++------
3 files changed, 40 insertions(+), 9 deletions(-)
diff --git a/buildbot/sourcestamp.py b/buildbot/sourcestamp.py
index 69d3c30..a388014 100644
|
a
|
b
|
class SourceStamp(util.ComparableMixin): |
| 12 | 12 | None, build the HEAD revision from the given branch. |
| 13 | 13 | - (revision=REV, patchspec=(LEVEL, DIFF), changes=None): checkout REV, |
| 14 | 14 | then apply a patch to the source, with C{patch -pPATCHLEVEL <DIFF}. |
| 15 | | If REV is None, checkout HEAD and patch it. |
| | 15 | If REV is C{None}, checkout HEAD and patch it. DIFF is a string that |
| | 16 | contains the unified diff to apply. |
| 16 | 17 | - (revision=None, patchspec=None, changes=[CHANGES]): let the Source |
| 17 | 18 | step check out the latest revision indicated by the given Changes. |
| 18 | 19 | CHANGES is a tuple of L{buildbot.changes.changes.Change} instances, |
diff --git a/buildbot/status/web/base.py b/buildbot/status/web/base.py
index 7b6e5e8..fc9b2d4 100644
|
a
|
b
|
def make_force_build_form(forceURL, useLoginPassword, on_all=False): |
| 95 | 95 | where = " on all builders" |
| 96 | 96 | else: |
| 97 | 97 | where = "" |
| 98 | | data = """<form action="%s" class="command forcebuild"> |
| | 98 | if useLoginPassword: |
| | 99 | form_type = ' method="post" enctype="multipart/form-data"' |
| | 100 | form_attach = (make_row("Build with a patch?", |
| | 101 | '<input type="file" name="patch" />') |
| | 102 | + make_row("Patch level:", |
| | 103 | '<input type="text" name="plevel" size="2" ' |
| | 104 | 'maxlength="2" value="1" />')) |
| | 105 | form_attach = "" |
| | 106 | form_type = "" |
| | 107 | |
| | 108 | data = """<form action="%s"%s class="command forcebuild"> |
| 99 | 109 | <p>To force a build%s, fill out the following fields and |
| 100 | | click the `Force Build' button</p>""" % (forceURL, where) |
| | 110 | click the `Force Build' button</p> |
| | 111 | """ % (forceURL, form_type, where) |
| 101 | 112 | return (data |
| 102 | 113 | + make_name_login_password_form(useLoginPassword) |
| 103 | 114 | + make_row("Reason for build:", |
| … |
… |
def make_force_build_form(forceURL, useLoginPassword, on_all=False): |
| 106 | 117 | '<input type="text" name="branch" />') |
| 107 | 118 | + make_row("Revision to build:", |
| 108 | 119 | '<input type="text" name="revision" />') |
| | 120 | + form_attach |
| 109 | 121 | + '<input type="submit" value="Force Build" /></form>\n') |
| 110 | 122 | |
| 111 | 123 | colormap = { |
diff --git a/buildbot/status/web/builder.py b/buildbot/status/web/builder.py
index fbc8fb5..51b30fe 100644
|
a
|
b
|
class StatusResourceBuilder(HtmlResource, OneLineMixin): |
| 132 | 132 | reason = req.args.get("comments", ["<no reason specified>"])[0] |
| 133 | 133 | branch = req.args.get("branch", [""])[0] |
| 134 | 134 | revision = req.args.get("revision", [""])[0] |
| | 135 | patch = req.args.get("patch", [""])[0] |
| | 136 | if patch: |
| | 137 | patch_level = req.args.get("plevel", ["1"])[0] |
| | 138 | try: |
| | 139 | patch_level = int(patch_level) |
| | 140 | except ValueError: |
| | 141 | # TODO: tell the web user that their request was invalid |
| | 142 | return Redirect("..") |
| | 143 | patch = (patch_level, patch) |
| | 144 | has_patch = "yes" |
| | 145 | else: |
| | 146 | has_patch = "no" |
| | 147 | patch = None |
| 135 | 148 | |
| 136 | | r = "The web-page 'force build' button was pressed by '%s': %s\n" \ |
| 137 | | % (name, reason) |
| 138 | | log.msg("web forcebuild of builder '%s', branch='%s', revision='%s'" |
| 139 | | "by user '%s'" % (self.builder_status.getName(), branch, |
| 140 | | revision, name)) |
| | 149 | r = "The web-page 'force build' button was pressed by '%s': %s" \ |
| | 150 | "(patch: %s)\n" % (name, reason, has_patch) |
| | 151 | log.msg("web forcebuild of builder '%s', branch='%s', " |
| | 152 | "revision='%s', by user '%s' (patch: %s)" \ |
| | 153 | % (self.builder_status.getName(), branch, revision, name, |
| | 154 | has_patch)) |
| 141 | 155 | |
| 142 | 156 | if not self.builder_control: |
| 143 | 157 | # TODO: tell the web user that their request was denied |
| … |
… |
class StatusResourceBuilder(HtmlResource, OneLineMixin): |
| 148 | 162 | if not self.authUser(req): |
| 149 | 163 | # TODO: tell the web user that their request was denied |
| 150 | 164 | return Redirect("..") |
| | 165 | else: |
| | 166 | if patch: |
| | 167 | log.msg("user is not authenticated: discarding the patch") |
| | 168 | patch = None |
| 151 | 169 | |
| 152 | 170 | # keep weird stuff out of the branch and revision strings. TODO: |
| 153 | 171 | # centralize this somewhere. |
| … |
… |
class StatusResourceBuilder(HtmlResource, OneLineMixin): |
| 168 | 186 | # buildbot.changes.changes.Change instance which doesn't really fit |
| 169 | 187 | # this use case (it requires a list of changed files which is tedious |
| 170 | 188 | # to compute at this stage) |
| 171 | | s = SourceStamp(branch=branch, revision=revision) |
| | 189 | s = SourceStamp(branch=branch, revision=revision, patch=patch) |
| 172 | 190 | req = BuildRequest(r, s, self.builder_status.getName()) |
| 173 | 191 | try: |
| 174 | 192 | self.builder_control.requestBuildSoon(req) |