From 8d64bbe0659ad7e459ce22f57d27b7461258a403 Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Sun, 14 Apr 2013 18:47:12 -0700 Subject: [PATCH] givi - Misc improvements: * When outputting commands, display repo name instead of relative path * Add --repos option * Add hidden "push" action * Add disabled "merge-forward" action. (This was previously drafted but ultimately went with tools/scripts/merge-forward.) --- bin/givi | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 114 insertions(+), 9 deletions(-) diff --git a/bin/givi b/bin/givi index b18d9b1f4b..b99b60029a 100755 --- a/bin/givi +++ b/bin/givi @@ -69,6 +69,11 @@ class Givi { */ protected $rebase = FALSE; + /** + * @var string, the word 'all' or comma-delimited list of repo names + */ + protected $repoFilter = 'all'; + /** * @var array ($repoName => $relPath) */ @@ -120,6 +125,8 @@ class Givi { return $this->returnError("Root appears to be invalid -- missing too many repos. Try --root=\n"); } + $this->repos = $this->filterRepos($this->repoFilter, $this->repos); + // Run the action switch ($this->action) { case 'checkout': @@ -137,6 +144,12 @@ class Givi { case 'resume': call_user_func_array(array($this, 'doResume'), $this->arguments); break; + //case 'merge-forward': + // call_user_func_array(array($this, 'doMergeForward'), $this->arguments); + // break; + case 'push': + call_user_func_array(array($this, 'doPush'), $this->arguments); + break; case 'help': case '': $this->doHelp(); @@ -172,6 +185,9 @@ class Givi { elseif (preg_match('/^--root=(.*)/', $arg, $matches)) { $this->civiRoot = $matches[1]; } + elseif (preg_match('/^--repos=(.*)/', $arg, $matches)) { + $this->repoFilter = $matches[1]; + } elseif (preg_match('/^--(core|packages|joomla|drupal|wordpress)=(.*)/', $arg, $matches)) { $this->branches[$matches[1]] = $matches[2]; } @@ -203,17 +219,22 @@ class Givi { echo " $program [options] status\n"; echo " $program [options] begin [--core=|--drupal=|...] \n"; echo " $program [options] resume [--rebase] [--core=|--drupal=|...] \n"; + #echo " $program [options] merge-forward \n"; + #echo " $program [options] push [:]\n"; echo "Actions:\n"; echo " checkout: Checkout same branch name on all repos\n"; echo " fetch: Fetch remote changes on all repos\n"; echo " status: Display status on all repos\n"; echo " begin: Begin work on a new branch on some repo (and use base-branch for all others)\n"; echo " resume: Resume work on an existing branch on some repo (and use base-branch for all others)\n"; + #echo " merge-forward: On each repo, merge changes from maintenance branch to development branch\n"; + #echo " push: On each repo, push a branch to a remote (Note: only intended for use with merge-forward)\n"; echo "Common options:\n"; echo " --dry-run: Don't do anything; only print commands that would be run\n"; echo " --d6: Specify that Drupal branches should use 6.x-* prefixes\n"; echo " --d7: Specify that Drupal branches should use 7.x-* prefixes (default)\n"; echo " --fetch: Fetch the latest code before creating, updating, or checking-out anything\n"; + echo " --repos=X: Restrict operations to the listed repos (comma-delimited list) (default: all)"; echo " --root=X: Specify CiviCRM root directory (default: .)\n"; echo "Special options:\n"; echo " --core=X: Specify the branch to use on the core repository\n"; @@ -242,14 +263,14 @@ class Givi { foreach ($this->repos as $repo => $relPath) { $filteredBranch = $this->filterBranchName($repo, $branches[$repo]); - $this->run($relPath, 'git', 'checkout', $filteredBranch); + $this->run($repo, $relPath, 'git', 'checkout', $filteredBranch); } return TRUE; } function doStatusAll() { foreach ($this->repos as $repo => $relPath) { - $this->run($relPath, 'git', 'status'); + $this->run($repo, $relPath, 'git', 'status'); } return TRUE; } @@ -271,10 +292,10 @@ class Givi { $filteredBaseBranch = $this->filterBranchName($repo, $baseBranch); if ($filteredBranch == $filteredBaseBranch) { - $this->run($relPath, 'git', 'checkout', $filteredBranch); + $this->run($repo, $relPath, 'git', 'checkout', $filteredBranch); } else { - $this->run($relPath, 'git', 'checkout', '-b', $filteredBranch, $filteredBaseBranch); + $this->run($repo, $relPath, 'git', 'checkout', '-b', $filteredBranch, $filteredBaseBranch); } } } @@ -295,14 +316,72 @@ class Givi { $filteredBranch = $this->filterBranchName($repo, $branches[$repo]); $filteredBaseBranch = $this->filterBranchName($repo, $baseBranch); - $this->run($relPath, 'git', 'checkout', $filteredBranch); + $this->run($repo, $relPath, 'git', 'checkout', $filteredBranch); if ($filteredBranch != $filteredBaseBranch && $this->rebase) { list ($baseRemoteRepo, $baseRemoteBranch) = $this->parseBranchRepo($filteredBaseBranch); - $this->run($relPath, 'git', 'pull', '--rebase', $baseRemoteRepo, $baseRemoteBranch); + $this->run($repo, $relPath, 'git', 'pull', '--rebase', $baseRemoteRepo, $baseRemoteBranch); } } } + /* + + If we want merge-forward changes to be subject to PR process, then this + should useful. Currently using a simpler process based on + toosl/scripts/merge-forward + + function doMergeForward($maintBranch, $devBranch) { + if (!$maintBranch) { + return $this->returnError("Missing \n"); + } + if (!$devBranch) { + return $this->returnError("Missing \n"); + } + list ($maintBranchRepo, $maintBranchName) = $this->parseBranchRepo($maintBranch); + list ($devBranchRepo, $devBranchName) = $this->parseBranchRepo($devBranch); + + $newBranchRepo = $devBranchRepo; + $newBranchName = $maintBranchName . '-' . $devBranchName . '-' . date('Y-m-d-H-i-s'); + + if ($this->fetch) { + $this->doFetchAll(); + } + + foreach ($this->repos as $repo => $relPath) { + $filteredMaintBranch = $this->filterBranchName($repo, $maintBranch); + $filteredDevBranch = $this->filterBranchName($repo, $devBranch); + $filteredNewBranchName = $this->filterBranchName($repo, $newBranchName); + + $this->run($repo, $relPath, 'git', 'checkout', '-b', $filteredNewBranchName, $filteredDevBranch); + $this->run($repo, $relPath, 'git', 'merge', $filteredMaintBranch); + } + } + */ + + function doPush($newBranchRepo, $newBranchNames) { + if (!$newBranchRepo) { + return $this->returnError("Missing \n"); + } + if (!$newBranchNames) { + return $this->returnError("Missing [:]\n"); + } + if (FALSE !== strpos($newBranchNames, ':')) { + list ($newBranchFromName,$newBranchToName) = explode(':', $newBranchNames); + foreach ($this->repos as $repo => $relPath) { + $filteredFromName = $this->filterBranchName($repo, $newBranchFromName); + $filteredToName = $this->filterBranchName($repo, $newBranchToName); + + $this->run($repo, $relPath, 'git', 'push', $newBranchRepo, $filteredFromName . ':' . $filteredToName); + } + } else { + foreach ($this->repos as $repo => $relPath) { + $filteredName = $this->filterBranchName($repo, $newBranchNames); + $this->run($repo, $relPath, 'git', 'push', $newBranchRepo, $filteredName); + } + } + + } + /** * Given a ref name, determine the repo and branch * @@ -333,16 +412,17 @@ class Givi { * @param string $command * @return string */ - function run($runDir, $command) { + function run($repoName, $runDir, $command) { $this->dirStack->push($runDir); $args = func_get_args(); array_shift($args); array_shift($args); + array_shift($args); foreach ($args as $arg) { $command .= ' ' . escapeshellarg($arg); } - printf("\nRUN [%s]: %s\n", $runDir, $command); + printf("\n\n\nRUN [%s]: %s\n", $repoName, $command); if ($this->dryRun) { $r = NULL; } else { @@ -355,7 +435,7 @@ class Givi { function doFetchAll() { foreach ($this->repos as $repo => $relPath) { - $this->run($relPath, 'git', 'fetch', '--all'); + $this->run($repo, $relPath, 'git', 'fetch', '--all'); } } @@ -374,6 +454,9 @@ class Givi { } function filterBranchName($repoName, $branchName) { + if ($branchName == '') { + return ''; + } if ($repoName == 'drupal') { $parts = explode('/', $branchName); $last = $this->drupalVersion . '.x-' . array_pop($parts); @@ -383,6 +466,28 @@ class Givi { return $branchName; } + /** + * @param string $filter e.g. "all" or "repo1,repo2" + * @param array $repos ($repoName => $repoDir) + * @return array ($repoName => $repoDir) + */ + function filterRepos($filter, $repos) { + if ($filter == 'all') { + return $repos; + } + + $inclRepos = explode(',', $filter); + $unknowns = array_diff($inclRepos, array_keys($repos)); + if (!empty($unknowns)) { + throw new Exception("Unknown Repos: " . implode(',', $unknowns)); + } + $unwanted = array_diff(array_keys($repos), $inclRepos); + foreach ($unwanted as $repo) { + unset($repos[$repo]); + } + return $repos; + } + function returnError($message) { echo "ERROR: ", $message, "\n"; $this->doHelp(); -- 2.25.1