[autotest] Add atest stable_version command to manage stable versions.
Add a decorator require_confirmation to atest, any delete action will prompt
for confirmation, use option --no-confirmation to skip that. It's applicable
to command like atest label delete, atest host delete.
Add 3 actions for topic stable_version:
list: Show version of a given board or list all boards and their stable
versions if --board option is not specified.
$ ./atest stable_version list
==============================
board | version
------------------------------
DEFAULT | R41-4687.0.0
peppy | R40-4555.0.0
==============================
modify: Set the stable version of a given board to the given value.
$ ./atest stable_version modify -b peppy -i R40-4515.0.0
Stable version for board peppy is changed from R40-4555.0.0.0 to R40-4515.0.0.
delete: Delete the stable version of a given board. So its stable version will
use the value for board `DEFAULT`.
$ ./atest stable_version delete -b peppy
Are you sure to delete stable version for board peppy? After this action is
done, stable version for board peppy will be R41.0.0.0
Continue? [y/N] y
Stable version for board peppy is deleted.
DEPLOY=apache
BUG=chromium:436656
TEST=local setup, unittest
Change-Id: I31047740a4886854aa653b1bf0f16c5f5c7a3f14
Reviewed-on: https://chromium-review.googlesource.com/236951
Tested-by: Dan Shi <[email protected]>
Reviewed-by: Simran Basi <[email protected]>
Commit-Queue: Dan Shi <[email protected]>
Trybot-Ready: Dan Shi <[email protected]>
diff --git a/cli/topic_common.py b/cli/topic_common.py
index c9c0a7f..2ee42b8 100644
--- a/cli/topic_common.py
+++ b/cli/topic_common.py
@@ -253,8 +253,9 @@
Should only be instantiated by itself for usage
references, otherwise, the <topic> objects should
be used."""
- msg_topic = "[acl|host|job|label|shard|atomicgroup|test|user|server]"
- usage_action = "[action]"
+ msg_topic = ('[acl|host|job|label|shard|atomicgroup|test|user|server|'
+ 'stable_version]')
+ usage_action = '[action]'
msg_items = ''
def invalid_arg(self, header, follow_up=''):
@@ -392,6 +393,7 @@
self.kill_on_failure = False
self.web_server = ''
self.verbose = False
+ self.no_confirmation = False
self.topic_parse_info = item_parse_info(attribute_name='not_used')
self.parser = optparse.OptionParser(self._get_usage())
@@ -408,6 +410,10 @@
self.parser.add_option('--parse-delim',
help='Delimiter to use to separate the '
'key=value fields', default='|')
+ self.parser.add_option('--no-confirmation',
+ help=('Skip all confirmation in when function '
+ 'require_confirmation is called.'),
+ action='store_true', default=False)
self.parser.add_option('-v', '--verbose',
action='store_true', default=False)
self.parser.add_option('-w', '--web',
@@ -491,6 +497,7 @@
self.parse_delim = options.parse_delim
self.verbose = options.verbose
+ self.no_confirmation = options.no_confirmation
self.web_server = options.web_server
try:
self.afe = rpc.afe_comm(self.web_server)
@@ -773,3 +780,56 @@
return
print '%s=%s' % (KEYS_TO_NAMES_EN[key],
','.join(_get_item_key(item, key) for item in items))
+
+
+ @staticmethod
+ def prompt_confirmation(message=None):
+ """Prompt a question for user to confirm the action before proceeding.
+
+ @param message: A detailed message to explain possible impact of the
+ action.
+
+ @return: True to proceed or False to abort.
+ """
+ if message:
+ print message
+ sys.stdout.write('Continue? [y/N] ')
+ read = raw_input().lower()
+ if read == 'y':
+ return True
+ else:
+ print 'User did not confirm. Aborting...'
+ return False
+
+
+ @staticmethod
+ def require_confirmation(message=None):
+ """Decorator to prompt a question for user to confirm action before
+ proceeding.
+
+ If user chooses not to proceed, do not call the function.
+
+ @param message: A detailed message to explain possible impact of the
+ action.
+
+ @return: A decorator wrapper for calling the actual function.
+ """
+ def deco_require_confirmation(func):
+ """Wrapper for the decorator.
+
+ @param func: Function to be called.
+
+ @return: the actual decorator to call the function.
+ """
+ def func_require_confirmation(*args, **kwargs):
+ """Decorator to prompt a question for user to confirm.
+
+ @param message: A detailed message to explain possible impact of
+ the action.
+ """
+ if (args[0].no_confirmation or
+ atest.prompt_confirmation(message)):
+ func(*args, **kwargs)
+
+ return func_require_confirmation
+ return deco_require_confirmation