Add raise_on_failure argument to step API.

A common idiom in recipe code is to do a try finally block where a step
will be executed in the try block and then in the finally block the code
will call api.step.active_result in order to update its presentation or
get values from the result. Unfortunately, if an exception is raised in
the try block that is not due to a step failure then depending on the
state of the previous steps api.step.active_result will either raise an
exception due to the previous step being closed or get an unrelated
result object. This will either obscure the actual problem or result in
unexpected behavior.

The alternative is a cumbersome construct where a variable for the
result is initialized to None, the result is assigned to in the try
block and an "except StepFailure" block is added and the result variable
is set to the result value on the exception. The finally block can then
check if result is None before attempting to update it. This construct
was exactly what active_result was added to remove the need for, but it
has the above stated problems.

This change provides an alternate construct where the step can be run
with raise_on_failure=False with the return value being assigned to the
result. The code can then update the presentation unconditionally and
call api.step.raise_on_failure to possibly raise an exception depending
on the status. Since there is no exception-handling code necessary with
such a construct, exceptions that are not due to step failures will be
propagated without additional code being run.

Bug: 1246180
Change-Id: I7d17e450d8a3c3f44f3aa89f4235a9cc85505fd4
Reviewed-on: https://chromium-review.googlesource.com/c/infra/luci/recipes-py/+/3150380
Auto-Submit: Garrett Beaty <gbeaty@google.com>
Commit-Queue: Garrett Beaty <gbeaty@google.com>
Reviewed-by: Yiwei Zhang <yiwzhang@google.com>
4 files changed
tree: 72b6d0ca3396c95515418cd592d2bc70a3cb8646
  1. doc/
  2. infra/
  3. misc/
  4. recipe_engine/
  5. recipe_modules/
  6. recipe_proto/
  7. recipes/
  8. unittests/
  9. .gitattributes
  10. .gitignore
  11. .style.yapf
  12. .vpython
  13. .vpython3
  14. .vpython3_dev
  15. AUTHORS
  16. codereview.settings
  17. CONTRIBUTORS
  18. LICENSE
  19. OWNERS
  20. PRESUBMIT.py
  21. README.md
  22. README.recipes.md
  23. recipes.py
README.md

Recipes

Recipes are a domain-specific language (embedded in Python) for specifying sequences of subprocess calls in a cross-platform and testable way.

They allow writing build flows which integrate with the rest of LUCI.

Documentation for the recipe engine (including this file!). Take a look at the user guide for some hints on how to get started. See the implementation details doc for more detailed implementation information about the recipe engine.

Contributing

  • Sign the Google CLA.
  • Make sure your user.email and user.name are configured in git config.

Run the following to setup the code review tool and create your first review:

# Get `depot_tools` in $PATH if you don't have it
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git $HOME/src/depot_tools
export PATH="$PATH:$HOME/src/depot_tools"

# Check out the recipe engine repo
git clone https://chromium.googlesource.com/infra/luci/recipes-py $HOME/src/recipes-py

# make your change
cd $HOME/src/recipes-py
git new-branch cool_feature
# hack hack
git commit -a -m "This is awesome"

# This will ask for your Google Account credentials.
git cl upload -s -r joe@example.com
# Wait for approval over email.
# Click "Submit to CQ" button or ask reviewer to do it for you.
# Wait for the change to be tested and landed automatically.

Use git cl help and git cl help <cmd> for more details.