| OLD | NEW |
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """This module integrates buildbucket with swarming. | 5 """This module integrates buildbucket with swarming. |
| 6 | 6 |
| 7 A bucket config may have "swarming" field that specifies how a builder | 7 A bucket config may have "swarming" field that specifies how a builder |
| 8 is mapped to a recipe. If build is scheduled for a bucket/builder | 8 is mapped to a recipe. If build is scheduled for a bucket/builder |
| 9 with swarming configuration, the integration overrides the default behavior. | 9 with swarming configuration, the integration overrides the default behavior. |
| 10 | 10 |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 143 author = c.get('author') | 143 author = c.get('author') |
| 144 if not isinstance(author, dict): | 144 if not isinstance(author, dict): |
| 145 bad('change author must be an object') | 145 bad('change author must be an object') |
| 146 email = author.get('email') | 146 email = author.get('email') |
| 147 if not isinstance(email, basestring): | 147 if not isinstance(email, basestring): |
| 148 bad('change author email must be a string') | 148 bad('change author email must be a string') |
| 149 if not email: | 149 if not email: |
| 150 bad('change author email not specified') | 150 bad('change author email not specified') |
| 151 | 151 |
| 152 | 152 |
| 153 def read_properties(recipe): |
| 154 """Parses build properties from the recipe message.""" |
| 155 result = dict(p.split(':', 1) for p in recipe.properties) |
| 156 for p in recipe.properties_j: |
| 157 k, v = p.split(':', 1) |
| 158 result[k] = json.loads(v) |
| 159 return result |
| 160 |
| 161 |
| 153 def merge_recipe(r1, r2): | 162 def merge_recipe(r1, r2): |
| 154 """Merges two Recipe messages. Values in r2 overwrite values in r1.""" | 163 """Merges two Recipe messages. Values in r2 overwrite values in r1.""" |
| 155 if not r1: # pragma: no branch | 164 if not r1: # pragma: no branch |
| 156 return r2 # pragma: no cover | 165 return r2 # pragma: no cover |
| 157 r1_props = dict(p.split(':', 1) for p in r1.properties) | 166 props = read_properties(r1) |
| 158 r2_props = dict(p.split(':', 1) for p in r2.properties) | 167 props.update(read_properties(r2)) |
| 159 r1_props.update(r2_props) | 168 recipe = project_config_pb2.Swarming.Recipe( |
| 160 return project_config_pb2.Swarming.Recipe( | |
| 161 repository=r2.repository or r1.repository, | 169 repository=r2.repository or r1.repository, |
| 162 name=r2.name or r1.name, | 170 name=r2.name or r1.name, |
| 163 properties=['%s:%s' % item for item in sorted(r1_props.iteritems())], | |
| 164 ) | 171 ) |
| 172 return recipe, props |
| 165 | 173 |
| 166 | 174 |
| 167 @ndb.tasklet | 175 @ndb.tasklet |
| 168 def create_task_def_async(swarming_cfg, builder_cfg, build): | 176 def create_task_def_async(swarming_cfg, builder_cfg, build): |
| 169 """Creates a swarming task definition for the |build|. | 177 """Creates a swarming task definition for the |build|. |
| 170 | 178 |
| 171 Supports build properties that are supported by Buildbot-Buildbucket | 179 Supports build properties that are supported by Buildbot-Buildbucket |
| 172 integration. See | 180 integration. See |
| 173 https://chromium.googlesource.com/chromium/tools/build/+/eff4ceb/scripts/maste
r/buildbucket/README.md#Build-parameters | 181 https://chromium.googlesource.com/chromium/tools/build/+/eff4ceb/scripts/maste
r/buildbucket/README.md#Build-parameters |
| 174 | 182 |
| 175 Raises: | 183 Raises: |
| 176 errors.InvalidInputError if build.parameters are invalid. | 184 errors.InvalidInputError if build.parameters are invalid. |
| 177 """ | 185 """ |
| 178 params = build.parameters or {} | 186 params = build.parameters or {} |
| 179 validate_build_parameters(builder_cfg.name, params) | 187 validate_build_parameters(builder_cfg.name, params) |
| 180 swarming_param = params.get(PARAM_SWARMING) or {} | 188 swarming_param = params.get(PARAM_SWARMING) or {} |
| 181 | 189 |
| 182 # Render task template. | 190 # Render task template. |
| 183 task_template = yield get_task_template_async() | 191 task_template = yield get_task_template_async() |
| 184 task_template_params = { | 192 task_template_params = { |
| 185 'bucket': build.bucket, | 193 'bucket': build.bucket, |
| 186 'builder': builder_cfg.name, | 194 'builder': builder_cfg.name, |
| 187 } | 195 } |
| 188 | 196 |
| 189 is_recipe = ( | 197 is_recipe = ( |
| 190 builder_cfg.HasField('recipe') or swarming_cfg.HasField('common_recipe')) | 198 builder_cfg.HasField('recipe') or swarming_cfg.HasField('common_recipe')) |
| 191 if is_recipe: # pragma: no branch | 199 if is_recipe: # pragma: no branch |
| 192 recipe = merge_recipe(swarming_cfg.common_recipe, builder_cfg.recipe) | 200 recipe, build_properties = merge_recipe( |
| 201 swarming_cfg.common_recipe, builder_cfg.recipe) |
| 193 revision = swarming_param.get('recipe', {}).get('revision') or '' | 202 revision = swarming_param.get('recipe', {}).get('revision') or '' |
| 194 | 203 |
| 195 build_properties = dict( | |
| 196 p.split(':', 1) for p in recipe.properties or []) | |
| 197 build_properties['buildername'] = builder_cfg.name | 204 build_properties['buildername'] = builder_cfg.name |
| 198 | 205 |
| 199 changes = params.get(PARAM_CHANGES) | 206 changes = params.get(PARAM_CHANGES) |
| 200 if changes: # pragma: no branch | 207 if changes: # pragma: no branch |
| 201 # Buildbucket-Buildbot integration passes repo_url of the first change in | 208 # Buildbucket-Buildbot integration passes repo_url of the first change in |
| 202 # build parameter "changes" as "repository" attribute of SourceStamp. | 209 # build parameter "changes" as "repository" attribute of SourceStamp. |
| 203 # https://chromium.googlesource.com/chromium/tools/build/+/2c6023d/scripts
/master/buildbucket/changestore.py#140 | 210 # https://chromium.googlesource.com/chromium/tools/build/+/2c6023d/scripts
/master/buildbucket/changestore.py#140 |
| 204 # Buildbot passes repository of the build source stamp as "repository" | 211 # Buildbot passes repository of the build source stamp as "repository" |
| 205 # build property. Recipes, in partiular bot_update recipe module, rely on | 212 # build property. Recipes, in partiular bot_update recipe module, rely on |
| 206 # "repository" property and it is an almost sane property to support in | 213 # "repository" property and it is an almost sane property to support in |
| (...skipping 460 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 667 def _extend_unique(target, items): | 674 def _extend_unique(target, items): |
| 668 for x in items: | 675 for x in items: |
| 669 if x not in target: # pragma: no branch | 676 if x not in target: # pragma: no branch |
| 670 target.append(x) | 677 target.append(x) |
| 671 | 678 |
| 672 | 679 |
| 673 class TaskToken(tokens.TokenKind): | 680 class TaskToken(tokens.TokenKind): |
| 674 expiration_sec = 60 * 60 * 24 # 24 hours. | 681 expiration_sec = 60 * 60 * 24 # 24 hours. |
| 675 secret_key = auth.SecretKey('swarming_task_token', scope='local') | 682 secret_key = auth.SecretKey('swarming_task_token', scope='local') |
| 676 version = 1 | 683 version = 1 |
| OLD | NEW |