Skip to content

Instantly share code, notes, and snippets.

@kdambekalns
Created February 12, 2014 11:51

Revisions

  1. kdambekalns created this gist Feb 12, 2014.
    9 changes: 9 additions & 0 deletions README.rst
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,9 @@
    How to use
    ==========

    This script reads changes from the file gerrit.json. The description is just for the humans
    working with the file, the important bits are the project name and the numeric change id. If
    the change id is amended with a command and number that means "fetch that specific patch set"
    instread of the latest one.

    If you have gerrit.json ready just run php gerrit_update.php and watch the magic. :)
    21 changes: 21 additions & 0 deletions gerrit.json
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,21 @@
    {
    "TYPO3.Flow": {
    "[FEATURE] Provide request / response in exception dump": "25373",
    "[TASK] Improve security checks and related logging": "25462",
    "[FEATURE] Allow to cache Doctrine ORM query results": "25308"
    },
    "TYPO3.TYPO3CR": {
    "[FEATURE] Provide API for search engine": "24925,15",
    "[WIP][FEATURE] first-level cache in NodeDataRepository": "25402"
    },
    "TYPO3.Eel": {
    "[BUGFIX] Prevent race conditions in Eel Expression Cache": "26454",
    "[FEATURE] shuffle() operation": "25227,3"
    },
    "TYPO3.TypoScript": {
    "[WIP][TASK] Cache results of tsValue() calls": "25225"
    },
    "TYPO3.Neos": {
    "[WIP][FEATURE] adjustments to implementing a cache in NodeDataRepository": "25403"
    }
    }
    161 changes: 161 additions & 0 deletions gerrit_update.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,161 @@
    #!/usr/bin/php
    <?php

    error_reporting(E_ALL ^ E_STRICT);
    ini_set('display_errors', 1);

    define('FLOW_PATH_ROOT', __DIR__ . DIRECTORY_SEPARATOR);
    define('FLOW_PATH_PACKAGES', FLOW_PATH_ROOT . 'Packages' . DIRECTORY_SEPARATOR);

    class Gerrit {

    /**
    * @var array
    */
    static protected $colors = array(
    'green' => '0;32',
    'red' => '0;31',
    'yellow' => '0;33'
    );

    /**
    * This command checks for a gerrit.json in the current dir and fetches patches from gerrit
    *
    * This command will cherry-pick all reviews specified in gerrit.json
    *
    * @return void
    */
    static public function updateCommand() {
    $gerritFile = FLOW_PATH_ROOT . 'gerrit.json';
    $typeDirs = scandir(FLOW_PATH_PACKAGES);
    $packagePaths = array('BuildEssentials' => 'Build/BuildEssentials');
    foreach ($typeDirs as $typeDir) {
    if (is_dir(FLOW_PATH_PACKAGES . $typeDir) && substr($typeDir, 0, 1) !== '.') {
    $typeDir = FLOW_PATH_PACKAGES . $typeDir . '/';
    $packageDirs = scandir($typeDir);
    foreach ($packageDirs as $packageDir) {
    if (is_dir($typeDir . $packageDir) && substr($packageDir, 0, 1) !== '.') {
    $packagePaths[$packageDir] = $typeDir . $packageDir;
    }
    }
    }
    }

    if (file_exists($gerritFile)) {
    $packages = json_decode(@file_get_contents($gerritFile));
    if (!is_object($packages)) {
    echo self::colorize('Could not load gerrit.json! Check for Syntax errors', 'red');
    return;
    }
    foreach (get_object_vars($packages) as $package => $changes) {
    if (!isset($packagePaths[$package])) {
    echo self::colorize('The Package ' . $package . ' is not installed', 'red') . PHP_EOL;
    continue;
    }
    chdir($packagePaths[$package]);
    $changes = get_object_vars($changes);
    $gitLogOutput = self::executeShellCommand('git log -n30');
    foreach ($changes as $description => $changeId) {
    $patchSet = NULL;
    if (strpos($changeId, ',') !== FALSE) {
    list($changeId, $patchSet) = explode(',', $changeId);
    }
    $change = self::fetchChangeInformation($changeId);
    if ($change === FALSE) {
    echo self::colorize(sprintf('Could not fetch change information (%u)!', $changeId), 'red') . PHP_EOL;
    continue;
    }
    $header = $package . ': ' . $change->subject;
    echo self::colorize($header, 'green') . PHP_EOL;

    if ($change->status == 'MERGED') {
    echo self::colorize('This change has been merged upstream.', 'yellow') . PHP_EOL;
    } elseif ($change->status == 'ABANDONED') {
    echo self::colorize('This change has been abandoned!', 'red') . PHP_EOL;
    }
    $ref = $change->revisions->{$change->current_revision}->fetch->git->ref;
    if ($patchSet !== NULL) {
    $explodedRef = explode('/', $ref);
    array_pop($explodedRef);
    $explodedRef[] = $patchSet;
    $ref = implode('/', $explodedRef);
    }
    $command = 'git fetch --quiet git://review.typo3.org/' . $change->project . ' ' . $ref . '';
    $output = self::executeShellCommand($command);

    $changeIdLine = self::executeShellCommand('git show FETCH_HEAD | grep \'Change-Id\'');
    if (self::isAlreadyPicked($changeIdLine, $gitLogOutput)) {
    echo self::colorize('Already picked', 'yellow') . PHP_EOL;
    } else {
    echo $output;
    system('git cherry-pick -x --strategy=recursive -X theirs FETCH_HEAD');
    }

    echo PHP_EOL;
    }
    chdir(FLOW_PATH_ROOT);
    }
    }
    }

    /**
    * Checks if the change is already picked by looking for the Change-Id
    * line in the log.
    *
    * @param string $changeIdLine
    * @param string $gitLogOutput
    * @return boolean
    */
    static protected function isAlreadyPicked($changeIdLine, $gitLogOutput) {
    return stristr($gitLogOutput, trim($changeIdLine)) !== FALSE;
    }

    /**
    * @param string $command
    * @return string
    */
    static protected function executeShellCommand($command) {
    $output = '';
    $fp = popen($command, 'r');
    while (($line = fgets($fp)) !== FALSE) {
    $output .= $line;
    }
    pclose($fp);
    return trim($output);
    }

    /**
    * @param string $text
    * @param string $color Allowed values: green, red, yellow
    * @return string
    */
    static protected function colorize($text, $color) {
    return sprintf("\033[%sm%s\033[0m", self::$colors[$color], $text);
    }

    /**
    * @param integer $changeId The numeric change id, not the hash
    * @return mixed
    */
    static protected function fetchChangeInformation($changeId) {
    $output = @file_get_contents('https://review.typo3.org/changes/?q=' . intval($changeId) . '&o=CURRENT_REVISION');

    if ($output === FALSE) {
    return FALSE;
    }

    // Remove first line
    $output = substr($output, strpos($output, "\n") + 1);
    // trim []
    $output = ltrim($output, '[');
    $output = rtrim(rtrim($output), ']');

    $data = json_decode($output);
    return $data;
    }

    }

    Gerrit::updateCommand();

    ?>