https://www.mediawiki.org/wiki/Special:Code/MediaWiki/114637
Revision: 114637
Author: awjrichards
Date: 2012-03-30 23:11:37 +0000 (Fri, 30 Mar 2012)
Log Message:
-----------
Initial import of 'DippyBird', a tool to perform bulk actions on Gerrit
changesets. Currently supports submitting (with approval +2, verify +1)
changesets, can eaisly extend to review, abandon, etc.
Added Paths:
-----------
trunk/tools/gerrit-dippybird/
trunk/tools/gerrit-dippybird/._dippy-bird.php
trunk/tools/gerrit-dippybird/dippy-bird.php
Added: trunk/tools/gerrit-dippybird/._dippy-bird.php
===================================================================
(Binary files differ)
Property changes on: trunk/tools/gerrit-dippybird/._dippy-bird.php
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: trunk/tools/gerrit-dippybird/dippy-bird.php
===================================================================
--- trunk/tools/gerrit-dippybird/dippy-bird.php (rev 0)
+++ trunk/tools/gerrit-dippybird/dippy-bird.php 2012-03-30 23:11:37 UTC (rev
114637)
@@ -0,0 +1,426 @@
+<?php
+
+$dippy_bird = new DippyBird();
+$dippy_bird->run();
+
+
+class DippyBird {
+ protected $configOpts = array(
+ 'port' => array(
+ 'required' => true,
+ 'value' => null,
+ ),
+ 'server' => array(
+ 'required' => true,
+ 'value' => null,
+ ),
+ 'username' => array(
+ 'required' => true,
+ 'value' => null,
+ ),
+ 'query' => array(
+ 'required' => true,
+ 'value' => null,
+ ),
+ 'action' => array(
+ 'required' => false,
+ 'value' => null,
+ ),
+ 'pretend' => array(
+ 'required' => false,
+ 'value' => false,
+ ),
+ 'verbose' => array(
+ 'required' => false,
+ 'value' => false,
+ ),
+ 'debug' => array(
+ 'required' => false,
+ 'value' => false,
+ ),
+ );
+
+ protected $validActions = array(
+ //'approve' => 'executeApprove',
+ //'verify' => 'executeVerify',
+ 'submit' => 'executeSubmit',
+ //'abandon' => 'executeAbandon',
+ );
+
+ public function __construct() {
+ // if a config file is present, load it
+ $config_file = dirname( __FILE__ ) . "/" . "config.ini";
+ if ( file_exists( $config_file ) ) {
+ $this->loadConfiguration( $config_file );
+ }
+ }
+
+ public function run() {
+ $this->handleOpts();
+ if ( !$this->isConfigSane() ) {
+ // bail and fail
+ $msg = "There is something wrong in your arguments or
configuration.";
+ $this->bail( 1, $msg );
+ }
+
+ // determine the 'action' to take
+ $action = $this->getConfigOpt( 'action' );
+ $action_method = $this->getActionMethod( $action );
+
+ // fetch the results of the query
+ $results = $this->executeQuery();
+
+ // execute the action to take on the query results
+ $this->{$action_method}( $results );
+
+ echo "Thanks for playing!" . PHP_EOL;
+ echo "<3," . PHP_EOL;
+ echo "Dippy bird" . PHP_EOL;
+ }
+
+ public function executeQuery() {
+ // config options we need
+ $opts = array( 'port', 'server', 'username', 'query' );
+ $config_opts = $this->getConfigOptsByArray( $opts );
+ $cmd = "ssh -p {$config_opts['port']}
{$config_opts['username']}@{$config_opts['server']} gerrit query
{$config_opts['query']} --format=JSON --current-patch-set";
+ if ( $this->getConfigOpt( 'verbose' ) ) {
+ echo "Executing query: " . $cmd . PHP_EOL;
+ }
+ $results = array();
+ exec( escapeshellcmd( $cmd ), $results, $status );
+ if ( $status === 0 ) {
+ if ( $this->getConfigOpt( 'debug' ) ) {
+ echo "Query results: " . print_r( $results,
true ) . PHP_EOL;
+ }
+ return $results;
+ } else {
+ $msg = "There was a problem executing your query." .
PHP_EOL;
+ $msg .= "Exiting with status: $status";
+ $this->bail( $status, $msg );
+ }
+ }
+
+ public function executeSubmit( $results ) {
+ // If there are less than two items in the array, there are no
changesets on which to operate
+ if ( count( $results ) < 2 ) {
+ // nothing to process
+ return;
+ }
+
+ // prepare to do... stuff
+ $submitted = 0;
+ $opts = array( 'port', 'server', 'username' );
+ $config_opts = $this->getConfigOptsByArray( $opts );
+
+ // get the patchset ids form the result set
+ $patchset_ids = self::extractPatchSetIds( $results );
+
+ // loop through patchsets and submit them one by one
+ foreach ( $patchset_ids as $patchset_id ) {
+ // prepare command to execute
+ $cmd = "ssh -p {$config_opts['port']}
{$config_opts['username']}@{$config_opts['server']} gerrit approve --verified 1
--code-review 2 --submit $patchset_id";
+
+ if ( $this->getConfigOpt( 'verbose' ) ) {
+ echo "Executing: " . $cmd . PHP_EOL;
+ }
+
+ // should we do this for reals?!
+ if ( !$this->getConfigOpt( 'pretend' ) ) {
+ exec( escapeshellcmd( $cmd ), $cmd_results,
$status );
+ if ( $status !== 0 ) {
+ $msg = "Problem executing submit" .
PHP_EOL;
+ $this->bail( 1, $msg );
+ }
+ }
+ $submitted++;
+ }
+ echo "$submitted changesets submitted." . PHP_EOL;
+ }
+
+ /**
+ * Extract patchset ids
+ * @param array JSON representations of gerrit changesets
+ * @return array
+ */
+ public static function extractPatchSetIds( $results ) {
+ $patchset_ids = array();
+ foreach ( $results as $result ) {
+ $patchset_id = self::extractPatchSetId( $result );
+ if ( !is_null( $patchset_id )) {
+ $patchset_ids[] = $patchset_id;
+ }
+ }
+ return $patchset_ids;
+ }
+
+ /**
+ * Extract patchset id
+ * @param string JSON representation of gerrit changeset
+ * @return mixed patchset id or null
+ */
+ public static function extractPatchSetId( $result ) {
+ $changeset = json_decode( $result, true );
+ if( isset( $changeset['currentPatchSet']['revision'] ) ) {
+ return $changeset['currentPatchSet']['revision'];
+ }
+ return null;
+ }
+
+ /**
+ * Set $this->configOpts by array of key -> value pairs
+ * @param array
+ */
+ public function setConfigByArray( array $config ) {
+ // don't bother if the array is empty
+ if ( empty( $config ) ) {
+ return;
+ }
+
+ // only set valid config opts
+ foreach ( $config as $key => $value ) {
+ if ( isset( $this->configOpts[ $key ] ) ) {
+ $this->configOpts[ $key ]['value'] = $value;
+ }
+ }
+ }
+
+ /**
+ * Load configuration options from an ini file
+ * @param string Path to configuration file
+ */
+ protected function loadConfiguration( $config_file ) {
+ $config = parse_ini_file( $config_file );
+
+ // do some option clean up....
+
+ $this->setConfigByArray( $config );
+ }
+
+ /**
+ * Handle runtime command line options
+ */
+ protected function handleOpts() {
+ $user_opts = getopt( $this->getShortOpts(),
$this->getLongOpts() );
+
+ // handle 'help' message
+ if ( isset( $user_opts['help'] ) || isset( $user_opts['h'] ) ) {
+ $this->bail();
+ }
+
+ $config = array();
+
+ foreach ( $user_opts as $key => $value ) {
+ switch ( $key ) {
+ case 'port':
+ case 'P':
+ $config['port'] = $value;
+ break;
+ case 'server':
+ case 's':
+ $config['server'] = $value;
+ break;
+ case 'username':
+ case 'u':
+ $config['username'] = $value;
+ break;
+ case 'query':
+ case 'q':
+ $config['query'] = $value;
+ break;
+ case 'action':
+ case 'a':
+ $config['action'] = $value;
+ break;
+ case 'pretend':
+ case 'p':
+ $config['pretend'] = true;
+ break;
+ case 'verbose':
+ case 'v':
+ $config['verbose'] = true;
+ break;
+ case 'debug':
+ case 'd':
+ // if debug, also set verbose to true
+ $config['verbose'] = true;
+ $config['debug'] = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ $this->setConfigByArray( $config );
+ }
+
+ /**
+ * Check sanity of configuration values
+ *
+ * If a value is required but unset, config is not sane.
+ */
+ protected function isConfigSane() {
+ foreach ( $this->configOpts as $opt => $info ) {
+ if ( $info['required'] === true && is_null(
$info['value'] ) ) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Get the 'long' options available
+ */
+ public function getLongOpts() {
+ $long_opts = array(
+ "port:",
+ "server:",
+ "username:",
+ "query:",
+ "action:",
+ "pretend",
+ "help",
+ "verbose",
+ "debug",
+ );
+ return $long_opts;
+ }
+
+ /**
+ * Get the 'short' options available
+ */
+ public function getShortOpts() {
+ $short_opts = "P:"; // port
+ $short_opts .= "s:"; // server
+ $short_opts .= "u:"; // username
+ $short_opts .= "q:"; // gerrit query
+ $short_opts .= "a:"; // action
+ $short_opts .= "p"; // pretend
+ $short_opts .= "h"; // help
+ $short_opts .= "v"; // verbose
+ $short_opts .= "d"; // debug
+ return $short_opts;
+ }
+
+ /**
+ * Fetch usage message
+ */
+ public function getUsage() {
+ $usage = <<<USAGE
+
+Purpose: Perform bulk actions on Gerrit changesets
+
+Description: Given a gerrit search query, perform a selected 'aciton'. Valid
+actions currently include:
+ submit: Verify, approve, and submit changeset
+
+Usage: php dippy-bird.php --username=<username> --server=<gerrit servername>
+ --port=<gerrit port> [--verbose] [--debug] [--help]
+ --action=<action> --query=<query>
+
+Required parameters:
+ --username, -u Username you use to log in to Gerrit
+ --server, -s Hostname of the Gerrit server
+ --port, -P Port where Gerrit is running
+ --query, -q Gerrit query (See docs: http://bit.ly/H9bYiq)
+ --action, -a Action to take after running query
+
+Optional options:
+ --pretend, -p Executes query but not action
+ --verbose, -v Run in 'verbose' mode
+ --debug, -d Run in 'debug' mode
+ --help, -h Display this help message
+
+Configuration options can also be set using the longoption names placed in
+a 'config.ini' file in the same directory as this script.
+
+USAGE;
+ return $usage;
+ }
+
+ /**
+ * Print usage message and die
+ * @param int Status code with which to exit
+ */
+ public function bail( $status = 0, $msg = null ) {
+ if ( !is_null( $msg ) ) {
+ echo $msg . PHP_EOL;
+ }
+ echo $this->getUsage();
+ echo PHP_EOL;
+ exit( intval( $status ) );
+ }
+
+ /**
+ * Fetch $this->configOpts
+ */
+ public function getConfigOpts() {
+ return $this->configOpts;
+ }
+
+ /**
+ * Fetch a specified configuration option
+ *
+ * @param $opt string The name of the option
+ * @param $verbose bool If true, returns full config opt array,
otherwise
+ * just returns the config opt's value
+ * @return mixed string|array|null Returns null if the config opt does
+ * not exist.
+ */
+ public function getConfigOpt( $opt, $verbose = false ) {
+ if ( isset( $this->configOpts[ $opt ] ) ) {
+ if ( $verbose === false ) {
+ return $this->configOpts[ $opt ]['value'];
+ } else {
+ return $this->configOpts[ $opt ];
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Fetch multiple config option values
+ * @param array Config option names to fetch
+ * @return array Option name => value
+ */
+ public function getConfigOptsByArray( array $opts ) {
+ $config_opts = array();
+ foreach ( $opts as $opt ) {
+ $config_opts[ $opt ] = $this->getConfigOpt( $opt );
+ }
+ return $config_opts;
+ }
+
+ /**
+ * Determine whether or not requested action is valid to take
+ *
+ * Valid actions are defined in $this->validActions
+ * @param string
+ * @return bool
+ */
+ public function isValidAction( $action ) {
+ if ( isset( $this->validActions[ $action ] ) ) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Fetch the method name corresponding to a specific 'action'
+ *
+ * If the action is not valid, fail and bail.
+ * @param string
+ * @return string
+ */
+ public function getActionMethod( $action ) {
+ if ( !$this->isValidAction( $action ) ) {
+ $msg = "Invalid action requested" . PHP_EOL;
+ $msg .= "Valid actions include:" . PHP_EOL;
+ foreach( $this->validActions as $action => $method ) {
+ $msg .= "\t$action" . PHP_EOL;
+ }
+ $this->bail( 1, $msg );
+ }
+ return $this->validActions[ $action ];
+ }
+
+}
\ No newline at end of file
_______________________________________________
MediaWiki-CVS mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs