xref: /aosp_15_r20/external/autotest/utils/frozen_chromite/lib/buildbot_annotations.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1# -*- coding: utf-8 -*-
2# Copyright 2016 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Functions and classes for formatting buildbot stage annotations."""
7
8from __future__ import print_function
9
10import abc
11import itertools
12import json
13
14import six
15
16
17class Annotation(object):
18  """Formatted annotation for buildbot."""
19
20  def __init__(self, name, args):
21    """Initialize instance.
22
23    Args:
24      name: Annotation name.
25      args: A sequence of string arguments.
26    """
27    self.name = name
28    self.args = args
29
30  def __str__(self):
31    inner_text = '@'.join(
32        _EscapeArgText(text)
33        for text in itertools.chain([self.name], self.args)
34    )
35    return '@@@%s@@@' % (inner_text,)
36
37  @property
38  def human_friendly(self):
39    """Human-friendly format."""
40    if self.args:
41      return '%s: %s' % (self.name, '; '.join(self.args))
42    else:
43      return self.name
44
45
46@six.add_metaclass(abc.ABCMeta)
47class _NamedAnnotation(Annotation):
48  """Abstract subclass for creating named annotations.
49
50  Concrete subclasses should define the ANNOTATION_NAME class attribute.
51  """
52
53  def __init__(self, *args):
54    super(_NamedAnnotation, self).__init__(self.ANNOTATION_NAME, args)
55
56  @abc.abstractproperty
57  def ANNOTATION_NAME(self):
58    raise NotImplementedError()
59
60
61class StepLink(_NamedAnnotation):
62  """STEP_LINK annotation."""
63  ANNOTATION_NAME = 'STEP_LINK'
64
65  # Some callers pass in text/url by kwarg.  We leave the full signature here
66  # so the API is a bit cleaner/more obvious.
67  # pylint: disable=useless-super-delegation
68  def __init__(self, text, url):
69    super(StepLink, self).__init__(text, url)
70
71
72class StepText(_NamedAnnotation):
73  """STEP_TEXT annotation."""
74  ANNOTATION_NAME = 'STEP_TEXT'
75
76
77class StepWarnings(_NamedAnnotation):
78  """STEP_WARNINGS annotation."""
79  ANNOTATION_NAME = 'STEP_WARNINGS'
80
81
82class StepFailure(_NamedAnnotation):
83  """STEP_FAILURE annotation."""
84  ANNOTATION_NAME = 'STEP_FAILURE'
85
86
87class BuildStep(_NamedAnnotation):
88  """BUILD_STEP annotation."""
89  ANNOTATION_NAME = 'BUILD_STEP'
90
91
92class SetBuildProperty(_NamedAnnotation):
93  """SET_BUILD_PROPERTY annotation."""
94  ANNOTATION_NAME = 'SET_BUILD_PROPERTY'
95
96  def __init__(self, name, value):
97    super(SetBuildProperty, self).__init__(name, json.dumps(value))
98
99
100class SetEmailNotifyProperty(_NamedAnnotation):
101  """SET_BUILD_PROPERTY annotation for email_notify."""
102  ANNOTATION_NAME = 'SET_BUILD_PROPERTY'
103
104  def __init__(self, name, value):
105    super(SetEmailNotifyProperty, self).__init__(name, json.dumps(value))
106
107  def __str__(self):
108    inner_text = '@'.join(
109        text for text in itertools.chain([self.name], self.args))
110    return '@@@%s@@@' % (inner_text)
111
112
113def _EscapeArgText(text):
114  """Escape annotation argument text.
115
116  Args:
117    text: String to escape.
118  """
119  return text.replace('@', '-AT-')
120