[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 <dshi@chromium.org>
Reviewed-by: Simran Basi <sbasi@chromium.org>
Commit-Queue: Dan Shi <dshi@chromium.org>
Trybot-Ready: Dan Shi <dshi@chromium.org>
diff --git a/cli/stable_version.py b/cli/stable_version.py
new file mode 100644
index 0000000..11b5726
--- /dev/null
+++ b/cli/stable_version.py
@@ -0,0 +1,178 @@
+# Copyright 2014 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+This module contains functions to get or update stable version for a given
+board.
+
+The valid actions are:
+list: Show version of a given board or list all boards and their stable
+ versions if --board option is not specified.
+modify: Set the stable version of a given board to the given value.
+delete: Delete the stable version of a given board. So its stable version will
+ use the value for board `DEFAULT`.
+"""
+
+import common
+
+from autotest_lib.cli import topic_common
+
+
+class stable_version(topic_common.atest):
+ """stable_version class
+
+ atest stable_version [list|delete|modify] <options>
+ """
+ usage_action = '[list|delete|modify]'
+ topic = msg_topic = 'stable_version'
+ msg_items = '<stable_version>'
+
+ def __init__(self):
+ """Add to the parser the options common to all the
+ stable_version actions.
+ """
+ super(stable_version, self).__init__()
+
+ self.parser.add_option('-b', '--board',
+ help='Name of the board',
+ type='string',
+ default=None,
+ metavar='BOARD')
+
+ self.topic_parse_info = topic_common.item_parse_info(
+ attribute_name='board', use_leftover=True)
+
+
+ def parse(self):
+ """Parse command arguments.
+ """
+ board_info = topic_common.item_parse_info(attribute_name='board')
+ (options, leftover) = super(stable_version, self).parse([board_info])
+
+ self.board = options.board
+ return (options, leftover)
+
+
+ def output(self, results):
+ """Display output.
+
+ For most actions, the return is a string message, no formating needed.
+
+ @param results: return of the execute call.
+ """
+ if results:
+ print results
+
+
+class stable_version_help(stable_version):
+ """Just here to get the atest logic working. Usage is set by its parent.
+ """
+ pass
+
+
+class stable_version_list(stable_version):
+ """atest stable_version list [--board <board>]"""
+
+ def execute(self):
+ """Execute list stable version action.
+ """
+ if self.board:
+ version = self.execute_rpc(op='get_stable_version',
+ board=self.board)
+ return {self.board: version}
+ else:
+ return self.execute_rpc(op='get_all_stable_versions')
+
+
+ def output(self, results):
+ """Display output.
+
+ @param results: A dictionary of board:version.
+ """
+ format = '%-12s| %-20s'
+ print '='*30
+ print format % ('board', 'version')
+ print '-'*30
+ for board,version in results.iteritems():
+ print format % (board, version)
+ print '='*30
+
+
+class stable_version_modify(stable_version):
+ """atest stable_version modify --board <board> --version <version>
+
+ Change the stable version of a given board to the given value.
+ """
+
+ def __init__(self):
+ """Add to the parser the options common to all the
+ stable_version actions.
+ """
+ super(stable_version_modify, self).__init__()
+
+ self.parser.add_option('-i', '--version',
+ help='Stable version.',
+ type='string',
+ metavar='VERSION')
+
+ self.topic_parse_info = topic_common.item_parse_info(
+ attribute_name='board', use_leftover=True)
+
+
+ def parse(self):
+ """Parse command arguments.
+ """
+ options,leftover = super(stable_version_modify, self).parse()
+
+ self.version = options.version
+ if not self.board or not self.version:
+ self.invalid_syntax('Both --board and --version arguments must be '
+ 'specified.')
+
+
+ def execute(self):
+ """Execute delete stable version action.
+ """
+ current_version = self.execute_rpc(op='get_stable_version',
+ board=self.board)
+ if current_version == self.version:
+ print ('Board %s already has stable version of %s.' %
+ (self.board, self.version))
+ return
+
+ self.execute_rpc(op='set_stable_version', board=self.board,
+ version=self.version)
+ print ('Stable version for board %s is changed from %s to %s.' %
+ (self.board, current_version, self.version))
+
+
+class stable_version_delete(stable_version):
+ """atest stable_version delete --board <board>
+
+ Delete a stable version entry in afe_stable_versions table for a given
+ board, so default stable version will be used.
+ """
+
+ def parse(self):
+ """Parse command arguments.
+ """
+ super(stable_version_delete, self).parse()
+ if not self.board:
+ self.invalid_syntax('`board` argument must be specified to delete '
+ 'a stable version entry.')
+ if self.board == 'DEFAULT':
+ self.invalid_syntax('Stable version for board DEFAULT can not be '
+ 'deleted.')
+
+
+ @topic_common.atest.require_confirmation(
+ 'Are you sure to delete stable version for the given board?')
+ def execute(self):
+ """Execute delete stable version action.
+ """
+ self.execute_rpc(op='delete_stable_version', board=self.board)
+ print 'Stable version for board %s is deleted.' % self.board
+ default_stable_version = self.execute_rpc(op='get_stable_version')
+ print ('Stable version for board %s is default to %s' %
+ (self.board, default_stable_version))