| # Copyright 2019 The Fuchsia Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| from recipe_engine import recipe_api |
| |
| from PB.go.chromium.org.luci.buildbucket.proto import common as bb_common_pb2 |
| |
| |
| class BuildbucketUtilApi(recipe_api.RecipeApi): |
| """Module for high-level buildbucket utilities specific to Fuchsia infra.""" |
| |
| @property |
| def id(self): |
| """A unique string identifier for the current build.""" |
| if self.m.led.launched_by_led: |
| return self.m.led.run_id |
| else: |
| return str(self.m.buildbucket.build.id) |
| |
| @property |
| def is_tryjob(self): |
| """Whether the current build is running as a tryjob.""" |
| bucket_name = self.m.buildbucket.build.builder.bucket |
| return bucket_name.endswith('try') |
| |
| def display_builds(self, step_name, builds, raise_on_failure=False): |
| """ |
| Display build links and status for each input build. |
| Optionally raise on build failure(s). |
| |
| Args: |
| builds (seq[buildbucket.v2.Build]): buildbucket Build objects. See |
| recipe_engine/buildbucket recipe module for more info. |
| build_group_name (str): Name of build group to display in step name. |
| raise_on_failure (bool): Raise InfraFailure or StepFailure on failure. |
| |
| Raises: |
| InfraFailure: One or more input builds had infra failure. Takes priority |
| over step failures. |
| StepFailure: One or more of input builds failed. |
| """ |
| infra_failed_builders = [] |
| failed_builders = [] |
| # Create per-build display steps. |
| with self.m.step.nest(step_name): |
| for build in builds: |
| with self.m.step.nest(build.builder.builder) as display_step: |
| step_links = display_step.presentation.links |
| step_links[str(build.id)] = self.m.buildbucket.build_url( |
| build_id=build.id) # yapf: disable |
| if build.status == bb_common_pb2.SUCCESS: |
| display_step.presentation.status = self.m.step.SUCCESS |
| elif build.status == bb_common_pb2.INFRA_FAILURE: |
| display_step.presentation.status = self.m.step.EXCEPTION |
| infra_failed_builders.append(build.builder.builder) |
| elif build.status == bb_common_pb2.FAILURE: |
| display_step.presentation.status = self.m.step.FAILURE |
| failed_builders.append(build.builder.builder) |
| # For any other status, use warning color. |
| else: |
| display_step.presentation.status = self.m.step.WARNING |
| |
| if raise_on_failure: |
| # Construct failure header and message. Include both types of failures, |
| # regardless of whether we raise purple or red. |
| failure_header = 'build(s) failed' |
| failure_message = [] |
| if infra_failed_builders: |
| failure_message.append( |
| 'infra failures: {infra_failed_builders}'.format( |
| infra_failed_builders=', '.join(infra_failed_builders))) |
| if failed_builders: |
| failure_message.append('step failures: {failed_builders}'.format( |
| failed_builders=', '.join(failed_builders))) |
| failure_message = ', '.join(failure_message) |
| # If there were any infra failures, raise purple. |
| if infra_failed_builders: |
| self.m.python.infra_failing_step( |
| failure_header, |
| failure_message, |
| ) |
| # Otherwise if there were any step failures, raise red. |
| if failed_builders: |
| self.m.python.failing_step( |
| failure_header, |
| failure_message, |
| ) |