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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | recipe_engine/step_runner.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: recipe_engine/recipe_api.py
diff --git a/recipe_engine/recipe_api.py b/recipe_engine/recipe_api.py
index fef517232a4354792d4b93efbf0850b62dee1280..7b6a862f351027a9824788dd7f746d261c9d179c 100644
--- a/recipe_engine/recipe_api.py
+++ b/recipe_engine/recipe_api.py
@@ -19,57 +19,153 @@ from .util import ModuleInjectionSite
from . import field_composer
-_StepConfig = collections.namedtuple('StepConfig',
+_TriggerSpec = collections.namedtuple('_TriggerSpec',
+ ('bucket', 'builder_name', 'properties', 'buildbot_changes', 'tags',
+ 'critical'))
+
+class TriggerSpec(_TriggerSpec):
+ """
+ TriggerSpec is the internal representation of a raw trigger step. You should
+ use the standard 'step' recipe module, which will construct trigger specs
+ via API.
+ """
+
+ @classmethod
+ def _make_from_api_dict(cls, trig):
iannucci 2016/09/12 22:35:16 could we **explode this and add docstring?
+ builder_name = trig.pop('builder_name')
+ if not builder_name:
+ raise ValueError('Trigger spec: builder_name is not set')
+
+ changes = trig.pop('buildbot_changes', None)
+ if changes is not None:
+ 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.
+
+ inst = cls(
+ bucket=trig.pop('bucket', None),
+ builder_name=builder_name,
+ properties=trig.pop('properties', None),
+ buildbot_changes=changes,
+ tags=trig.pop('tags', None),
+ critical=trig.pop('critical', True),
+ )
+
+ # Confirm that all dictionary keys have been consumed.
+ if trig:
+ unknown_keys = sorted(trig.iterkeys())
+ 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.
+ ', '.join(unknown_keys)))
+
+ return inst
+
+ def _render_to_dict(self):
+ d = dict((k, v) for k, v in self._asdict().iteritems() if v)
+ if d['critical']:
+ d.pop('critical')
+ return d
+
+
+_StepConfig = collections.namedtuple('_StepConfig',
('name', 'cmd', 'cwd', 'env', 'allow_subannotations', 'trigger_specs',
- 'timeout', 'infra_step', 'stdout', 'stderr', 'stdin', 'ok_ret',
- 'step_test_data', 'nest_level'))
+ 'timeout', 'infra_step', 'stdout', 'stderr', 'stdin', 'ok_ret',
+ 'step_test_data', 'nest_level'))
class StepConfig(_StepConfig):
"""
+ StepConfig is the representation of a raw step as the recipe_engine sees it.
+ You should use the standard 'step' recipe module, which will construct and
+ pass this data to the engine for you, instead. The only reason why you would
+ need to worry about this object is if you're modifying the step module itself.
+
+ The optional "env" parameter provides optional overrides for environment
+ variables. Each value is % formatted with the entire existing os.environ. A
+ value of `None` will remove that envvar from the environ. e.g.
+
+ {
+ "envvar": "%(envvar)s;%(envvar2)s;extra",
+ "delete_this": None,
+ "static_value": "something",
+ }
+
StepConfig parameters:
- name: name of the step, will appear in buildbots waterfall
- cmd: command to run, list of one or more strings
- cwd: absolute path to working directory for the command
- env: dict with overrides for environment variables
- allow_subannotations: if True, lets the step emit its own annotations
+ name (str): name of the step, will appear in buildbots waterfall
+ cmd: command to run. Acceptable types: str, Path, Placeholder, or None.
+ cwd (str or None): absolute path to working directory for the command
+ env (dict): overrides for environment variables, described above.
+ allow_subannotations (bool): if True, lets the step emit its own annotations
+ NOTE: Enabling this can cause some buggy behavior. Please strongly
+ consider using step_result.presentation instead. If you have questions,
+ please contact infra-dev@chromium.org.
trigger_specs: a list of trigger specifications, see also _trigger_builds.
timeout: if not None, a datetime.timedelta for the step timeout.
- infra_step: if True, this is an infrastructure step.
- stdout: Path to a file to put step stdout into. If used, stdout won't
- appear in annotator's stdout (and |allow_subannotations| is
- ignored).
- stderr: Path to a file to put step stderr into. If used, stderr won't
- appear in annotator's stderr.
- stdin: Path to a file to read step stdin from.
- ok_ret: Allowed return code list.
- step_test_data: Possible associated step test data.
- nest_level: the step's nesting level.
+ infra_step: if True, this is an infrastructure step. Failures will raise
+ InfraFailure instead of StepFailure.
+ stdout: Placeholder to put step stdout into. If used, stdout won't appear in
+ annotator's stdout (and |allow_subannotations| is ignored).
+ stderr: Placeholder to put step stderr into. If used, stderr won't appear in
+ annotator's stderr.
+ stdin: Placeholder to read step stdin from.
+ 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
+ something not on this list, it will raise a StepFailure (or InfraFailure
+ if infra_step is True). If omitted, {0} will be used.
+ step_test_data (func -> recipe_test_api.StepTestData): A factory which
+ returns a StepTestData object that will be used as the default test data
+ for this step. The recipe author can override/augment this object in the
+ GenTests function.
+ nest_level (int): the step's nesting level.
"""
+ _RENDER_WHITELIST=frozenset((
+ 'cmd',
+ ))
+
+ _RENDER_BLACKLIST=frozenset((
+ 'nest_level',
+ 'ok_ret',
+ 'infra_step',
+ 'step_test_data',
+ ))
+
+ @classmethod
+ def _make_from_api_dict(cls, step):
+ step_config = StepConfig(
+ name=step.pop('name'),
+ cmd=step.pop('cmd', None),
+ cwd=step.pop('cwd', None),
+ env=step.pop('env', None),
+ allow_subannotations=step.pop('allow_subannotations', False),
+ trigger_specs=[TriggerSpec._make_from_api_dict(trig)
+ for trig in step.pop('trigger_specs', ())],
+ timeout=step.pop('timeout', None),
+ infra_step=step.pop('infra_step', False),
+ stdout=step.pop('stdout', None),
+ stderr=step.pop('stderr', None),
+ stdin=step.pop('stdin', None),
+ ok_ret=set(step.pop('ok_ret', {0})),
+ step_test_data=step.pop('step_test_data', None),
+ nest_level=int(step.pop('step_nest_level', 0)),
+ )
+
+ # Confirm that all dictionary keys have been consumed.
+ if step:
+ unknown_keys = sorted(step.iterkeys())
+ raise KeyError('Unknown step dictionary keys: %s' % (
+ ', '.join(unknown_keys)))
+
+ return step_config
+
+ def render_to_dict(self):
+ self = self._replace(
+ trigger_specs=[trig._render_to_dict()
+ for trig in (self.trigger_specs or ())],
+ )
+ return dict((k, v) for k, v in self._asdict().iteritems()
+ if (v or k in self._RENDER_WHITELIST)
+ and k not in self._RENDER_BLACKLIST)
+
def _make_step_config(**step):
- """Galvanize a step dictionary into a formal StepConfig."""
- step_config = StepConfig(
- name=step.pop('name'),
- cmd=step.pop('cmd', None),
- cwd=step.pop('cwd', None),
- env=step.pop('env', None),
- allow_subannotations=step.pop('allow_subannotations', False),
- trigger_specs=step.pop('trigger_specs', ()),
- timeout=step.pop('timeout', None),
- infra_step=step.pop('infra_step', False),
- stdout=step.pop('stdout', None),
- stderr=step.pop('stderr', None),
- stdin=step.pop('stdin', None),
- ok_ret=step.pop('ok_ret', {0}),
- step_test_data=step.pop('step_test_data', None),
- nest_level=step.pop('step_nest_level', 0),
- )
- if step:
- unknown_keys = sorted(step.iterkeys())
- raise KeyError('Unknown step dictionary keys: %s' % (
- ', '.join(unknown_keys)))
- return step_config
+ """Convert a step API dictionary into a formal StepConfig."""
+ return StepConfig._make_from_api_dict(step)
class StepFailure(Exception):
« 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