1# This file is part of Buildbot. Buildbot is free software: you can 2# redistribute it and/or modify it under the terms of the GNU General Public 3# License as published by the Free Software Foundation, version 2. 4# 5# This program is distributed in the hope that it will be useful, but WITHOUT 6# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 7# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 8# details. 9# 10# You should have received a copy of the GNU General Public License along with 11# this program; if not, write to the Free Software Foundation, Inc., 51 12# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 13# 14# Copyright Buildbot Team Members 15 16 17from twisted.internet import defer 18 19from buildbot.data import base 20from buildbot.data import types 21 22 23class Db2DataMixin: 24 25 def db2data(self, dbdict): 26 data = { 27 'stepid': dbdict['id'], 28 'number': dbdict['number'], 29 'name': dbdict['name'], 30 'buildid': dbdict['buildid'], 31 'started_at': dbdict['started_at'], 32 'complete': dbdict['complete_at'] is not None, 33 'complete_at': dbdict['complete_at'], 34 'state_string': dbdict['state_string'], 35 'results': dbdict['results'], 36 'urls': dbdict['urls'], 37 'hidden': dbdict['hidden'], 38 } 39 return defer.succeed(data) 40 41 42class StepEndpoint(Db2DataMixin, base.BuildNestingMixin, base.Endpoint): 43 44 isCollection = False 45 pathPatterns = """ 46 /steps/n:stepid 47 /builds/n:buildid/steps/i:step_name 48 /builds/n:buildid/steps/n:step_number 49 /builders/n:builderid/builds/n:build_number/steps/i:step_name 50 /builders/n:builderid/builds/n:build_number/steps/n:step_number 51 /builders/i:buildername/builds/n:build_number/steps/i:step_name 52 /builders/i:buildername/builds/n:build_number/steps/n:step_number 53 """ 54 55 @defer.inlineCallbacks 56 def get(self, resultSpec, kwargs): 57 if 'stepid' in kwargs: 58 dbdict = yield self.master.db.steps.getStep(kwargs['stepid']) 59 return (yield self.db2data(dbdict)) if dbdict else None 60 buildid = yield self.getBuildid(kwargs) 61 if buildid is None: 62 return None 63 dbdict = yield self.master.db.steps.getStep( 64 buildid=buildid, 65 number=kwargs.get('step_number'), 66 name=kwargs.get('step_name')) 67 return (yield self.db2data(dbdict)) if dbdict else None 68 69 70class StepsEndpoint(Db2DataMixin, base.BuildNestingMixin, base.Endpoint): 71 72 isCollection = True 73 pathPatterns = """ 74 /builds/n:buildid/steps 75 /builders/n:builderid/builds/n:build_number/steps 76 /builders/i:buildername/builds/n:build_number/steps 77 """ 78 79 @defer.inlineCallbacks 80 def get(self, resultSpec, kwargs): 81 if 'buildid' in kwargs: 82 buildid = kwargs['buildid'] 83 else: 84 buildid = yield self.getBuildid(kwargs) 85 if buildid is None: 86 return None 87 steps = yield self.master.db.steps.getSteps(buildid=buildid) 88 results = [] 89 for dbdict in steps: 90 results.append((yield self.db2data(dbdict))) 91 return results 92 93 94class UrlEntityType(types.Entity): 95 name = types.String() 96 url = types.String() 97 98 99class Step(base.ResourceType): 100 101 name = "step" 102 plural = "steps" 103 endpoints = [StepEndpoint, StepsEndpoint] 104 keyField = 'stepid' 105 eventPathPatterns = """ 106 /builds/:buildid/steps/:stepid 107 /steps/:stepid 108 """ 109 subresources = ["Log"] 110 111 class EntityType(types.Entity): 112 stepid = types.Integer() 113 number = types.Integer() 114 name = types.Identifier(50) 115 buildid = types.Integer() 116 started_at = types.NoneOk(types.DateTime()) 117 complete = types.Boolean() 118 complete_at = types.NoneOk(types.DateTime()) 119 results = types.NoneOk(types.Integer()) 120 state_string = types.String() 121 urls = types.List( 122 of=UrlEntityType("Url", "Url")) 123 hidden = types.Boolean() 124 entityType = EntityType(name, 'Step') 125 126 @defer.inlineCallbacks 127 def generateEvent(self, stepid, event): 128 step = yield self.master.data.get(('steps', stepid)) 129 self.produceEvent(step, event) 130 131 @base.updateMethod 132 @defer.inlineCallbacks 133 def addStep(self, buildid, name): 134 stepid, num, name = yield self.master.db.steps.addStep( 135 buildid=buildid, name=name, state_string='pending') 136 yield self.generateEvent(stepid, 'new') 137 return (stepid, num, name) 138 139 @base.updateMethod 140 @defer.inlineCallbacks 141 def startStep(self, stepid): 142 yield self.master.db.steps.startStep(stepid=stepid) 143 yield self.generateEvent(stepid, 'started') 144 145 @base.updateMethod 146 @defer.inlineCallbacks 147 def setStepStateString(self, stepid, state_string): 148 yield self.master.db.steps.setStepStateString( 149 stepid=stepid, state_string=state_string) 150 yield self.generateEvent(stepid, 'updated') 151 152 @base.updateMethod 153 @defer.inlineCallbacks 154 def addStepURL(self, stepid, name, url): 155 yield self.master.db.steps.addURL( 156 stepid=stepid, name=name, url=url) 157 yield self.generateEvent(stepid, 'updated') 158 159 @base.updateMethod 160 @defer.inlineCallbacks 161 def finishStep(self, stepid, results, hidden): 162 yield self.master.db.steps.finishStep( 163 stepid=stepid, results=results, hidden=hidden) 164 yield self.generateEvent(stepid, 'finished') 165