Permalink
Browse files

Bug 793989: Self-serve should be able to request arbitrary builds on …

…a push. r=catlee
  • Loading branch information...
1 parent 0239281 commit 2a03ed5405b33ec6572ff7eefba30e29b70fe5bf @JohnLZeller JohnLZeller committed Feb 26, 2014
Showing with 135 additions and 11 deletions.
  1. +1 −3 buildapi/config/routing.py
  2. +30 −8 buildapi/controllers/selfserve.py
  3. +7 −0 buildapi/lib/mq.py
  4. +97 −0 buildapi/scripts/selfserve-agent.py
View
4 buildapi/config/routing.py
@@ -77,8 +77,7 @@ def make_map(config):
map.connect('new_build_at_rev', '/self-serve/{branch}/rev/{revision}', controller='selfserve', action='new_build_at_rev', conditions=dict(method=['POST']))
map.connect('new_pgobuild_at_rev', '/self-serve/{branch}/rev/{revision}/pgo', controller='selfserve', action='new_pgobuild_at_rev', conditions=dict(method=['POST']))
map.connect('new_nightly_at_rev', '/self-serve/{branch}/rev/{revision}/nightly', controller='selfserve', action='new_nightly_at_rev', conditions=dict(method=['POST']))
- #map.connect('new_build_for_builder', '/self-serve/{branch}/builders/{builder_name}', controller='selfserve', action='new_build_for_builder', conditions=dict(method=['POST']))
-
+ map.connect('new_build_for_builder', '/self-serve/{branch}/builders/{builder_name}/{revision}', controller='selfserve', action='new_build_for_builder', conditions=dict(method=['POST']))
# Status of jobs
map.connect('job_status', '/self-serve/jobs/{job_id}', controller='selfserve', action='job_status')
# History of requsts
@@ -93,7 +92,6 @@ def make_map(config):
map.connect('revision', '/self-serve/{branch}/rev/{revision}', controller='selfserve', action='revision')
map.connect('revision_is_done', '/self-serve/{branch}/rev/{revision}/is_done', controller='selfserve', action='revision_is_done')
map.connect('builders', '/self-serve/{branch}/builders', controller='selfserve', action='builders')
- map.connect('builder', '/self-serve/{branch}/builders/{builder_name}', controller='selfserve', action='builder')
map.connect('user', '/self-serve/{branch}/user/{user}', controller='selfserve', action='user')
# Redirect /foo/ to /foo
View
38 buildapi/controllers/selfserve.py
@@ -250,11 +250,6 @@ def builders(self, branch):
return self._format(retval)
@beaker_cache(query_args=True, expire=60)
- def builder(self, branch, builder_name):
- """Return a list of builds running for this builder"""
- abort(501, "Unimplemented")
-
- @beaker_cache(query_args=True, expire=60)
def user(self, branch, user):
"""Return a list of builds for this user"""
if branch not in self._branches_cache:
@@ -499,12 +494,39 @@ def new_nightly_at_rev(self, branch, revision):
# TODO: invalidate cache for branch
return self._format(retval)
- def new_build_for_builder(self, branch, builder_name):
+ def new_build_for_builder(self, branch, builder_name, revision):
who = self._require_auth()
if branch not in self._branches_cache:
return self._failed("Branch %s not found" % branch, 404)
- # TODO: Make sure that the 'fake' branches for sourcestamps are obeyed?
- abort(501, "Unimplemented")
+ # Get priority
+ try:
+ priority = validators.Int(if_empty=0).\
+ to_python(request.POST.get('priority'))
+ except formencode.Invalid:
+ return self._failed('Bad priority', 400)
+
+ # Get properties
+ try:
+ properties = json.loads(request.POST.get('properties'))
+ assert isinstance(properties, dict)
+ except Exception:
+ properties = {}
+
+ # Get the list of files
+ try:
+ files = json.loads(request.POST.get('files'))
+ assert isinstance(files, list)
+ except Exception:
+ files = []
+
+ # Set branch to ${branch}-selfserve to keep schedulers from triggering
+ branch += "-selfserve"
+ access_log.info("%s new_build_for_builder of %s %s %s",
+ who, branch, builder_name, revision)
+ retval = g.mq.newBuildForBuilder(
+ who, branch, revision, priority, builder_name, properties, files)
+ response.status = 202
+ return self._format(retval)
View
7 buildapi/lib/mq.py
@@ -169,6 +169,13 @@ def newPGOBuildAtRevision(self, who, branch, revision, priority):
def newNightlyAtRevision(self, who, branch, revision, priority):
return self.send_msg('new_nightly_at_revision', who=who, branch=branch, revision=revision, priority=priority)
+ def newBuildForBuilder(self, who, branch, revision, priority, builder_name,
+ properties, files):
+ return self.send_msg('new_build_for_builder', who=who, branch=branch,
+ revision=revision, priority=priority,
+ builder_name=builder_name, properties=properties,
+ files=files)
+
class JobRequestConsumer(ReliableConsumer):
"""For agents consuming job requests."""
View
97 buildapi/scripts/selfserve-agent.py
@@ -584,6 +584,103 @@ def do_cancel_revision(self, message_data, message):
msgs.append(result['msg'])
return {"errors": errors, "msg": "\n".join(msgs)}
+ def do_new_build_for_builder(self, message_data, message):
+ who = message_data['who']
+ branch = message_data['body']['branch']
+ revision = message_data['body']['revision']
+ priority = message_data['body']['priority']
+ builder_name = message_data['body']['builder_name']
+ files = message_data['body']['files']
+ log.info("New build for %s by %s of %s %s", builder_name, who, branch, revision)
+
+ # Create a sourcestamp
+ q = text("""INSERT INTO sourcestamps
+ (`branch`, `revision`, `patchid`, `repository`, `project`)
+ VALUES
+ (:branch, :revision, NULL, '', '')
+ """)
+ log.debug(q)
+ r = self.db.execute(q, branch=branch, revision=revision)
+ ssid = r.lastrowid # SourcestampID
+ log.debug("Created sourcestamp %s", ssid)
+
+ # Create change object
+ when = time.time()
+ q = text("""INSERT INTO changes
+ (`author`, `comments`, `is_dir`, `branch`,
+ `revision`, `revlink`, `when_timestamp`, `category`,
+ `repository`, `project`)
+ VALUES
+ (:who, '', 0, :branch, :revision, NULL, :when, NULL, '', '')
+ """)
+ log.debug(q)
+ r = self.db.execute(q, who=who, branch=branch, revision=revision, when=when)
+ cid = r.lastrowid
+ log.debug("Created change %s", cid)
+
+ # Create change-files
+ for f in files:
+ q = text("""INSERT INTO change_files
+ (`changeid`, `filename`)
+ VALUES
+ (:cid, :f)
+ """)
+ log.debug(q)
+ r = self.db.execute(q, cid=cid, f=f)
+ log.debug("Created change_file for change object %s", cid)
+
+ # Create sourcestamp_changes
+ q = text("""INSERT INTO sourcestamp_changes
+ (`sourcestampid`, `changeid`)
+ VALUES
+ (:ssid, :cid)
+ """)
+ log.debug(q)
+ r = self.db.execute(q, ssid=ssid, cid=cid)
+ log.debug("Created sourcestamp_changes for sourcestamp %s, change object %s", ssid, cid)
+
+ # Create a new buildset
+ now = time.time()
+ buildsetid = create_buildset(
+ self.db,
+ idstring=None,
+ reason='Self-serve: Requested by %s' % who,
+ ssid=ssid,
+ submitted_at=now,
+ )
+
+ # Create buildset properties (buildid, builduid)
+ q = text("""INSERT INTO buildset_properties
+ (`buildsetid`, `property_name`, `property_value`)
+ VALUES
+ (:buildsetid, :key, :value)
+ """)
+ props = {
+ 'buildid': json.dumps((genBuildID(now), "self-serve")),
+ 'builduid': json.dumps((genBuildUID(), "self-serve")),
+ }
+ # Making a tuple of each key and a tuple of it's associated property and the source "self-serve"
+ props.update(((k, json.dumps((v, "self-serve"))) for (k,v) in message_data['body']['properties'].iteritems()))
+ log.debug(q)
+ for key, value in props.items():
+ r = self.db.execute(q, buildsetid=buildsetid, key=key, value=value)
+ log.debug("Created buildset_property %s=%s", key, value)
+
+ # Create buildrequests
+ q = text("""INSERT INTO buildrequests
+ (`buildsetid`, `buildername`, `submitted_at`, `priority`, `claimed_at`, `claimed_by_name`, `claimed_by_incarnation`, `complete`, `results`, `complete_at`)
+ VALUES
+ (:buildsetid, :builder_name, :submitted_at, :priority, 0, NULL, NULL, 0, NULL, NULL)""")
+ log.debug(q)
+ r = self.db.execute(
+ q,
+ buildsetid=buildsetid,
+ builder_name=builder_name,
+ submitted_at=now,
+ priority=priority)
+ log.debug("Created buildrequest %s: %i", builder_name, r.lastrowid)
+ return {"errors": False, "msg": "Ok"}
+
def main():
import os

0 comments on commit 2a03ed5

Please sign in to comment.