From e8ff1fcc82a34c2cb58ddc1647648711af46ad31 Mon Sep 17 00:00:00 2001 From: Oliver Davies Date: Wed, 27 May 2020 17:56:15 +0100 Subject: [PATCH] git: Don't push if the merge failed Add support for two different run types: - Command: executes the command silently and returns whether or not there was an error. This is used to check if the merge was successful. - Query: executes the command and returns the output. This is used for retrieving the tip commits of the branch. --- bin/git-close-pull-request | 84 +++++++++++++++++++++++++++++++++----- 1 file changed, 74 insertions(+), 10 deletions(-) diff --git a/bin/git-close-pull-request b/bin/git-close-pull-request index 1ebb71f..aae6f7c 100755 --- a/bin/git-close-pull-request +++ b/bin/git-close-pull-request @@ -26,12 +26,21 @@ class ClosesPullRequests private const CI_PENDING = 'pending'; private const CI_SUCCESS = 'success'; + private const RUN_TYPE_COMMAND = 'command'; + private const RUN_TYPE_QUERY = 'query'; + public function __construct() { - $this->localBranch = exec('git rev-parse --abbrev-ref HEAD'); + $this->localBranch = $this->run( + 'git rev-parse --abbrev-ref HEAD', + self::RUN_TYPE_QUERY + ); $this->targetBranch = $this->getTargetBranchFromArgs(); - $this->remoteBranch = exec('git rev-parse --abbrev-ref --symbolic-full-name @{u}'); + $this->remoteBranch = $this->run( + 'git rev-parse --abbrev-ref --symbolic-full-name @{u}', + self::RUN_TYPE_QUERY + ); $this->remoteBranch = str_replace('origin/', '', $this->remoteBranch); } @@ -77,7 +86,8 @@ class ClosesPullRequests { print 'Fetching origin to confirm local and remote in sync...' . PHP_EOL; - exec("git fetch origin"); + + $this->run('git fetch origin', self::RUN_TYPE_COMMAND); } private function ensureTargetBranchInSync(): void @@ -121,13 +131,20 @@ class ClosesPullRequests private function tipCommitOfBranch(string $branchName): string { - return exec(sprintf('git rev-parse %s', $branchName)); + return $this->run( + sprintf('git rev-parse %s', $branchName), + self::RUN_TYPE_QUERY + ); } private function checkoutTargetBranch(): void { - print sprintf('Checking out %s...' . PHP_EOL, $this->targetBranch); - exec(sprintf('git checkout %s', $this->targetBranch)); + echo sprintf('Checking out %s...' . PHP_EOL, $this->targetBranch); + + $this->run( + sprintf('git checkout %s', $this->targetBranch), + self::RUN_TYPE_COMMAND + ); } private function mergeLocalBranch(): void @@ -138,25 +155,46 @@ class ClosesPullRequests $this->targetBranch ); - exec(sprintf('git merge --ff-only %s', $this->localBranch)); + $mergeCommand = sprintf('git merge --ff-only %s', $this->localBranch); + if (!$this->run($mergeCommand, self::RUN_TYPE_COMMAND)) { + // Switch back to the previous branch. + $this->run('git checkout -', self::RUN_TYPE_COMMAND); + + die(sprintf( + 'Branch %s is not fast-forwardable.', + $this->localBranch + )); + } } public function pushTargetBranch(): void { print(sprintf('Pushing updated %s branch...', $this->targetBranch)); - exec(sprintf('git push origin %s', $this->targetBranch)); + + $this->run( + sprintf('git push origin %s', $this->targetBranch), + self::RUN_TYPE_COMMAND + ); } public function deleteRemoteBranch(): void { echo 'Deleting remote branch...' . PHP_EOL; - exec(sprintf('git push origin :%s', $this->remoteBranch)); + + $this->run( + sprintf('git push origin :%s', $this->remoteBranch), + self::RUN_TYPE_COMMAND + ); } public function deleteLocalBranch(): void { echo 'Deleting local branch...' . PHP_EOL; - exec(sprintf('git branch -d %s', $this->localBranch)); + + $this->run( + sprintf('git branch -d %s', $this->localBranch), + self::RUN_TYPE_COMMAND + ); } private function getArg(string $shortOpts, array $longOpts = []): ?string @@ -167,6 +205,32 @@ class ClosesPullRequests return current($values); } + + /** + * Run the command. + * + * @return bool|string + * If the type is 'command', the method will return if there were any + * errors when running the command based on its return code. + * + * If the type is 'query', then the output of the command will be returned + * as a string. + */ + private function run(string $command, string $type) + { + switch ($type) { + case self::RUN_TYPE_COMMAND: + // Perform the command, hiding the original output and return + // whether or not there were errors. + @exec("$command", $output, $return); + + return $return == 0; + + case self::RUN_TYPE_QUERY: + // Perform the command and return the output. + return exec($command, $output); + } + } } (new ClosesPullRequests())->__invoke();