Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(723)

Side by Side Diff: recipe_engine/recipe_api.py

Issue 2332833003: Add better documentation, trigger namedtuple. (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | recipe_engine/step_runner.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2016 The LUCI Authors. All rights reserved. 1 # Copyright 2016 The LUCI Authors. All rights reserved.
2 # Use of this source code is governed under the Apache License, Version 2.0 2 # Use of this source code is governed under the Apache License, Version 2.0
3 # that can be found in the LICENSE file. 3 # that can be found in the LICENSE file.
4 4
5 from __future__ import absolute_import 5 from __future__ import absolute_import
6 import contextlib 6 import contextlib
7 import collections 7 import collections
8 import keyword 8 import keyword
9 import re 9 import re
10 import types 10 import types
11 11
12 from functools import wraps 12 from functools import wraps
13 13
14 from .recipe_test_api import DisabledTestData, ModuleTestData 14 from .recipe_test_api import DisabledTestData, ModuleTestData
15 from .config import Single 15 from .config import Single
16 16
17 from .util import ModuleInjectionSite 17 from .util import ModuleInjectionSite
18 18
19 from . import field_composer 19 from . import field_composer
20 20
21 21
22 _StepConfig = collections.namedtuple('StepConfig', 22 _TriggerSpec = collections.namedtuple('_TriggerSpec',
23 ('bucket', 'builder_name', 'properties', 'buildbot_changes', 'tags',
24 'critical'))
25
26 class TriggerSpec(_TriggerSpec):
27 """
28 TriggerSpec is the internal representation of a raw trigger step. You should
29 use the standard 'step' recipe module, which will construct trigger specs
30 via API.
31 """
32
33 @classmethod
34 def _make_from_api_dict(cls, trig):
iannucci 2016/09/12 22:35:16 could we **explode this and add docstring?
35 builder_name = trig.pop('builder_name')
36 if not builder_name:
37 raise ValueError('Trigger spec: builder_name is not set')
38
39 changes = trig.pop('buildbot_changes', None)
40 if changes is not None:
41 assert isinstance(changes, list), 'buildbot_changes must be a list'
iannucci 2016/09/12 22:35:16 raise valueerror
dnj 2016/09/12 23:30:11 Done.
42
43 inst = cls(
44 bucket=trig.pop('bucket', None),
45 builder_name=builder_name,
46 properties=trig.pop('properties', None),
47 buildbot_changes=changes,
48 tags=trig.pop('tags', None),
49 critical=trig.pop('critical', True),
50 )
51
52 # Confirm that all dictionary keys have been consumed.
53 if trig:
54 unknown_keys = sorted(trig.iterkeys())
55 raise KeyError('Unknown trigger spec keys: %s' % (
iannucci 2016/09/12 22:35:16 I think this is still ValueError. I think KeyError
dnj 2016/09/12 23:30:11 Done.
56 ', '.join(unknown_keys)))
57
58 return inst
59
60 def _render_to_dict(self):
61 d = dict((k, v) for k, v in self._asdict().iteritems() if v)
62 if d['critical']:
63 d.pop('critical')
64 return d
65
66
67 _StepConfig = collections.namedtuple('_StepConfig',
23 ('name', 'cmd', 'cwd', 'env', 'allow_subannotations', 'trigger_specs', 68 ('name', 'cmd', 'cwd', 'env', 'allow_subannotations', 'trigger_specs',
24 'timeout', 'infra_step', 'stdout', 'stderr', 'stdin', 'ok_ret', 69 'timeout', 'infra_step', 'stdout', 'stderr', 'stdin', 'ok_ret',
25 'step_test_data', 'nest_level')) 70 'step_test_data', 'nest_level'))
26 71
27 class StepConfig(_StepConfig): 72 class StepConfig(_StepConfig):
28 """ 73 """
74 StepConfig is the representation of a raw step as the recipe_engine sees it.
75 You should use the standard 'step' recipe module, which will construct and
76 pass this data to the engine for you, instead. The only reason why you would
77 need to worry about this object is if you're modifying the step module itself.
78
79 The optional "env" parameter provides optional overrides for environment
80 variables. Each value is % formatted with the entire existing os.environ. A
81 value of `None` will remove that envvar from the environ. e.g.
82
83 {
84 "envvar": "%(envvar)s;%(envvar2)s;extra",
85 "delete_this": None,
86 "static_value": "something",
87 }
88
29 StepConfig parameters: 89 StepConfig parameters:
30 name: name of the step, will appear in buildbots waterfall 90 name (str): name of the step, will appear in buildbots waterfall
31 cmd: command to run, list of one or more strings 91 cmd: command to run. Acceptable types: str, Path, Placeholder, or None.
32 cwd: absolute path to working directory for the command 92 cwd (str or None): absolute path to working directory for the command
33 env: dict with overrides for environment variables 93 env (dict): overrides for environment variables, described above.
34 allow_subannotations: if True, lets the step emit its own annotations 94 allow_subannotations (bool): if True, lets the step emit its own annotations
95 NOTE: Enabling this can cause some buggy behavior. Please strongly
96 consider using step_result.presentation instead. If you have questions,
97 please contact infra-dev@chromium.org.
35 trigger_specs: a list of trigger specifications, see also _trigger_builds. 98 trigger_specs: a list of trigger specifications, see also _trigger_builds.
36 timeout: if not None, a datetime.timedelta for the step timeout. 99 timeout: if not None, a datetime.timedelta for the step timeout.
37 infra_step: if True, this is an infrastructure step. 100 infra_step: if True, this is an infrastructure step. Failures will raise
38 stdout: Path to a file to put step stdout into. If used, stdout won't 101 InfraFailure instead of StepFailure.
39 appear in annotator's stdout (and |allow_subannotations| is 102 stdout: Placeholder to put step stdout into. If used, stdout won't appear in
40 ignored). 103 annotator's stdout (and |allow_subannotations| is ignored).
41 stderr: Path to a file to put step stderr into. If used, stderr won't 104 stderr: Placeholder to put step stderr into. If used, stderr won't appear in
42 appear in annotator's stderr. 105 annotator's stderr.
43 stdin: Path to a file to read step stdin from. 106 stdin: Placeholder to read step stdin from.
44 ok_ret: Allowed return code list. 107 ok_ret (iter): set of return codes allowed. If the step process returns
iannucci 2016/09/12 22:35:16 if you want to say this is an iter, then we should
dnj 2016/09/12 23:30:11 Was converting to a set, but frozenset is even bet
45 step_test_data: Possible associated step test data. 108 something not on this list, it will raise a StepFailure (or InfraFailure
46 nest_level: the step's nesting level. 109 if infra_step is True). If omitted, {0} will be used.
110 step_test_data (func -> recipe_test_api.StepTestData): A factory which
111 returns a StepTestData object that will be used as the default test data
112 for this step. The recipe author can override/augment this object in the
113 GenTests function.
114 nest_level (int): the step's nesting level.
47 """ 115 """
48 116
117 _RENDER_WHITELIST=frozenset((
118 'cmd',
119 ))
120
121 _RENDER_BLACKLIST=frozenset((
122 'nest_level',
123 'ok_ret',
124 'infra_step',
125 'step_test_data',
126 ))
127
128 @classmethod
129 def _make_from_api_dict(cls, step):
130 step_config = StepConfig(
131 name=step.pop('name'),
132 cmd=step.pop('cmd', None),
133 cwd=step.pop('cwd', None),
134 env=step.pop('env', None),
135 allow_subannotations=step.pop('allow_subannotations', False),
136 trigger_specs=[TriggerSpec._make_from_api_dict(trig)
137 for trig in step.pop('trigger_specs', ())],
138 timeout=step.pop('timeout', None),
139 infra_step=step.pop('infra_step', False),
140 stdout=step.pop('stdout', None),
141 stderr=step.pop('stderr', None),
142 stdin=step.pop('stdin', None),
143 ok_ret=set(step.pop('ok_ret', {0})),
144 step_test_data=step.pop('step_test_data', None),
145 nest_level=int(step.pop('step_nest_level', 0)),
146 )
147
148 # Confirm that all dictionary keys have been consumed.
149 if step:
150 unknown_keys = sorted(step.iterkeys())
151 raise KeyError('Unknown step dictionary keys: %s' % (
152 ', '.join(unknown_keys)))
153
154 return step_config
155
156 def render_to_dict(self):
157 self = self._replace(
158 trigger_specs=[trig._render_to_dict()
159 for trig in (self.trigger_specs or ())],
160 )
161 return dict((k, v) for k, v in self._asdict().iteritems()
162 if (v or k in self._RENDER_WHITELIST)
163 and k not in self._RENDER_BLACKLIST)
164
49 165
50 def _make_step_config(**step): 166 def _make_step_config(**step):
51 """Galvanize a step dictionary into a formal StepConfig.""" 167 """Convert a step API dictionary into a formal StepConfig."""
52 step_config = StepConfig( 168 return StepConfig._make_from_api_dict(step)
53 name=step.pop('name'),
54 cmd=step.pop('cmd', None),
55 cwd=step.pop('cwd', None),
56 env=step.pop('env', None),
57 allow_subannotations=step.pop('allow_subannotations', False),
58 trigger_specs=step.pop('trigger_specs', ()),
59 timeout=step.pop('timeout', None),
60 infra_step=step.pop('infra_step', False),
61 stdout=step.pop('stdout', None),
62 stderr=step.pop('stderr', None),
63 stdin=step.pop('stdin', None),
64 ok_ret=step.pop('ok_ret', {0}),
65 step_test_data=step.pop('step_test_data', None),
66 nest_level=step.pop('step_nest_level', 0),
67 )
68 if step:
69 unknown_keys = sorted(step.iterkeys())
70 raise KeyError('Unknown step dictionary keys: %s' % (
71 ', '.join(unknown_keys)))
72 return step_config
73 169
74 170
75 class StepFailure(Exception): 171 class StepFailure(Exception):
76 """ 172 """
77 This is the base class for all step failures. 173 This is the base class for all step failures.
78 174
79 Raising a StepFailure counts as 'running a step' for the purpose of 175 Raising a StepFailure counts as 'running a step' for the purpose of
80 infer_composite_step's logic. 176 infer_composite_step's logic.
81 """ 177 """
82 def __init__(self, name_or_reason, result=None): 178 def __init__(self, name_or_reason, result=None):
(...skipping 635 matching lines...) Expand 10 before | Expand all | Expand 10 after
718 """ 814 """
719 Gets the BoundProperty version of this Property. Requires a name. 815 Gets the BoundProperty version of this Property. Requires a name.
720 """ 816 """
721 return BoundProperty( 817 return BoundProperty(
722 self._default, self.help, self.kind, name, property_type, module, 818 self._default, self.help, self.kind, name, property_type, module,
723 self.param_name) 819 self.param_name)
724 820
725 class UndefinedPropertyException(TypeError): 821 class UndefinedPropertyException(TypeError):
726 pass 822 pass
727 823
OLDNEW
« no previous file with comments | « no previous file | recipe_engine/step_runner.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698