diff --git a/recipes/README.recipes.md b/recipes/README.recipes.md index a16b5444ab..9a3aa7d193 100644 --- a/recipes/README.recipes.md +++ b/recipes/README.recipes.md @@ -13,6 +13,7 @@ * [gitiles](#recipe_modules-gitiles) * [gsutil](#recipe_modules-gsutil) * [infra_paths](#recipe_modules-infra_paths) + * [luci_migration](#recipe_modules-luci_migration) * [presubmit](#recipe_modules-presubmit) * [rietveld](#recipe_modules-rietveld) * [tryserver](#recipe_modules-tryserver) @@ -31,6 +32,7 @@ * [gitiles:examples/full](#recipes-gitiles_examples_full) * [gsutil:examples/full](#recipes-gsutil_examples_full) * [infra_paths:examples/full](#recipes-infra_paths_examples_full) + * [luci_migration:tests/full](#recipes-luci_migration_tests_full) * [presubmit:examples/full](#recipes-presubmit_examples_full) * [rietveld:examples/full](#recipes-rietveld_examples_full) * [tryserver:examples/full](#recipes-tryserver_examples_full) @@ -612,6 +614,30 @@ It returns git_cache path if it is defined (Buildbot world), otherwise uses the more generic [CACHE]/git path (LUCI world). — **def [initialize](/recipes/recipe_modules/infra_paths/api.py#11)(self):** +### *recipe_modules* / [luci\_migration](/recipes/recipe_modules/luci_migration) + +[DEPS](/recipes/recipe_modules/luci_migration/__init__.py#5): [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/properties][recipe_engine/recipe_modules/properties] + +#### **class [LuciMigrationApi](/recipes/recipe_modules/luci_migration/api.py#8)([RecipeApi][recipe_engine/wkt/RecipeApi]):** + +This module assists in migrating builders from Buildbot to pure LUCI stack. + +Finishing migration means you no longer depend on this module. + +  **@property**
— **def [is\_luci](/recipes/recipe_modules/luci_migration/api.py#18)(self):** + +True if runs on LUCI stack. + +  **@property**
— **def [is\_prod](/recipes/recipe_modules/luci_migration/api.py#23)(self):** + +True if this builder is in production. + +Typical usage is to modify steps which produce external side-effects so that +non-production runs of the recipe do not affect production data. + +Examples: + * Uploading to an alternate google storage file name when in non-prod mode + * Appending a 'non-production' tag to external RPCs ### *recipe_modules* / [presubmit](/recipes/recipe_modules/presubmit) [DEPS](/recipes/recipe_modules/presubmit/__init__.py#1): [recipe\_engine/context][recipe_engine/recipe_modules/context], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/python][recipe_engine/recipe_modules/python], [recipe\_engine/step][recipe_engine/recipe_modules/step] @@ -817,6 +843,11 @@ Move things around in a loop! [DEPS](/recipes/recipe_modules/infra_paths/examples/full.py#7): [infra\_paths](#recipe_modules-infra_paths), [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/platform][recipe_engine/recipe_modules/platform], [recipe\_engine/properties][recipe_engine/recipe_modules/properties], [recipe\_engine/step][recipe_engine/recipe_modules/step] — **def [RunSteps](/recipes/recipe_modules/infra_paths/examples/full.py#16)(api):** +### *recipes* / [luci\_migration:tests/full](/recipes/recipe_modules/luci_migration/tests/full.py) + +[DEPS](/recipes/recipe_modules/luci_migration/tests/full.py#7): [luci\_migration](#recipe_modules-luci_migration), [recipe\_engine/step][recipe_engine/recipe_modules/step] + +— **def [RunSteps](/recipes/recipe_modules/luci_migration/tests/full.py#13)(api):** ### *recipes* / [presubmit:examples/full](/recipes/recipe_modules/presubmit/examples/full.py) [DEPS](/recipes/recipe_modules/presubmit/examples/full.py#5): [presubmit](#recipe_modules-presubmit) diff --git a/recipes/recipe_modules/luci_migration/__init__.py b/recipes/recipe_modules/luci_migration/__init__.py new file mode 100644 index 0000000000..23fb5ff5da --- /dev/null +++ b/recipes/recipe_modules/luci_migration/__init__.py @@ -0,0 +1,25 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +DEPS = [ + 'recipe_engine/path', + 'recipe_engine/properties', +] + +from recipe_engine.recipe_api import Property +from recipe_engine.config import ConfigGroup, Single + +PROPERTIES = { + '$depot_tools/luci_migration': Property( + help='Properties specifically for the luci_migration module', + param_name='migration_properties', + kind=ConfigGroup( + # Whether builder runs on LUCI stack. + is_luci=Single(bool), + # Whether builder is in production. + is_prod=Single(bool), + ), + default={}, + ), +} diff --git a/recipes/recipe_modules/luci_migration/api.py b/recipes/recipe_modules/luci_migration/api.py new file mode 100644 index 0000000000..92fd3981a3 --- /dev/null +++ b/recipes/recipe_modules/luci_migration/api.py @@ -0,0 +1,34 @@ +# Copyright 2017 The Chromium 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 + + +class LuciMigrationApi(recipe_api.RecipeApi): + """This module assists in migrating builders from Buildbot to pure LUCI stack. + + Finishing migration means you no longer depend on this module. + """ + + def __init__(self, migration_properties, **kwargs): + super(LuciMigrationApi, self).__init__(**kwargs) + self._migration_properties = migration_properties + + @property + def is_luci(self): + """True if this recipe is currently running on LUCI stack.""" + return bool(self._migration_properties.get('is_luci', False)) + + @property + def is_prod(self): + """True if this recipe is currently running in production. + + Typical usage is to modify steps which produce external side-effects so that + non-production runs of the recipe do not affect production data. + + Examples: + * Uploading to an alternate google storage file name when in non-prod mode + * Appending a 'non-production' tag to external RPCs + """ + return bool(self._migration_properties.get('is_prod', True)) diff --git a/recipes/recipe_modules/luci_migration/test_api.py b/recipes/recipe_modules/luci_migration/test_api.py new file mode 100644 index 0000000000..0655405367 --- /dev/null +++ b/recipes/recipe_modules/luci_migration/test_api.py @@ -0,0 +1,20 @@ +# Copyright 2017 The Chromium 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_test_api + + +class LuciMigrationTestApi(recipe_test_api.RecipeTestApi): + def __call__(self, is_luci, is_prod): + """Simulate luci migration state of a builder.""" + assert isinstance(is_luci, bool), '%r (%s)' % (is_luci, type(is_luci)) + assert isinstance(is_prod, bool), '%r (%s)' % (is_prod, type(is_prod)) + ret = self.test(None) + ret.properties = { + '$depot_tools/luci_migration': { + 'is_luci': is_luci, + 'is_prod': is_prod, + }, + } + return ret diff --git a/recipes/recipe_modules/luci_migration/tests/full.expected/basic.json b/recipes/recipe_modules/luci_migration/tests/full.expected/basic.json new file mode 100644 index 0000000000..ad81ee21a1 --- /dev/null +++ b/recipes/recipe_modules/luci_migration/tests/full.expected/basic.json @@ -0,0 +1,16 @@ +[ + { + "cmd": [], + "name": "show properties", + "~followup_annotations": [ + "@@@STEP_LOG_LINE@result@is_luci: True@@@", + "@@@STEP_LOG_LINE@result@is_prod: False@@@", + "@@@STEP_LOG_END@result@@@" + ] + }, + { + "name": "$result", + "recipe_result": null, + "status_code": 0 + } +] \ No newline at end of file diff --git a/recipes/recipe_modules/luci_migration/tests/full.py b/recipes/recipe_modules/luci_migration/tests/full.py new file mode 100644 index 0000000000..5b177e1431 --- /dev/null +++ b/recipes/recipe_modules/luci_migration/tests/full.py @@ -0,0 +1,22 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import json + +DEPS = [ + 'depot_tools/luci_migration', + 'recipe_engine/step', +] + + +def RunSteps(api): + api.step('show properties', []) + api.step.active_result.presentation.logs['result'] = [ + 'is_luci: %r' % (api.luci_migration.is_luci,), + 'is_prod: %r' % (api.luci_migration.is_prod,), + ] + + +def GenTests(api): + yield api.test('basic') + api.luci_migration(is_luci=True, is_prod=False)