/**
  * Transfers a gerrit patch to a github pull request.
  *
  * @param integer $patchId The gerrit patchset id
  */
 public function createPullRequestFromGerritCommand($patchId)
 {
     try {
         $this->gitHubService->authenticate();
     } catch (InvalidConfigurationException $e) {
         $this->outputLine('<error>It was not possible to authenticate with github.</error>');
         $this->outputLine('Please run <b>./flow github:setup</b> first');
     }
     $this->outputLine('Requesting Patch Details from gerrit.');
     $package = $this->gerritService->getPatchTargetPackage($patchId);
     $packageKey = $package->getPackageKey();
     $packagePath = $package->getPackagePath();
     $this->outputLine(sprintf('Determined <b>%s</b> as the target package key for this change.', $packageKey));
     $patchPathAndFileName = $this->gerritService->getPatchFromGerrit($patchId);
     $this->outputLine('Successfully fetched changeset from gerrit.');
     $this->outputLine(sprintf('The following changes will be applied to package <b>%s</b>', $packageKey));
     $this->output($this->executeGitCommand(sprintf('git apply --directory %s --check %s', $packageKey, $patchPathAndFileName), $packagePath));
     $this->output($this->executeGitCommand(sprintf('git apply --directory %s --stat %s', $packageKey, $patchPathAndFileName), $packagePath));
     if (!$this->output->askConfirmation("\nWould you like to apply this patch? (Y/n): ", TRUE)) {
         return;
     }
     $this->output($this->executeGitCommand(sprintf('git fetch upstream master'), $packagePath));
     $this->output($this->executeGitCommand(sprintf('git checkout -b %s upstream/master', $patchId), $packagePath));
     $this->output($this->executeGitCommand(sprintf('git am --directory %s %s', $packageKey, $patchPathAndFileName), $packagePath));
     $this->outputLine(sprintf('<success>Successfully Applied patch %s</success>', $patchId));
     if (!$this->output->askConfirmation("\nWould you like to push the change to your repository and create a pull request? (Y/n)", TRUE)) {
         return;
     }
     $remoteRepository = $this->getGitRemoteRepositoryOfDirectory($packagePath);
     $this->output($this->executeGitCommand(sprintf('git push origin %s', $patchId), $packagePath));
     $this->createPullRequest($remoteRepository, $patchId);
     $this->output($this->executeGitCommand(sprintf('git checkout master'), $packagePath));
 }
    /**
     * Transfers a Gerrit patch to a Github pull request.
     *
     * @param integer $patchId The Gerrit Change-ID
     * @return void
     */
    public function applyGerritChangeCommand($patchId)
    {
        $this->output->ask("Make sure your development collection is set up correctly and that the master branch is clean and synced with upstream master before continuing.\nAlso make sure <b>php-cs-fixer</b> is installed globally.\n\nPress any key to continue.");
        $this->outputLine('');
        $this->outputLine('If anything goes wrong, go to the development collection and checkout a clean master branch.');
        $this->outputLine('');
        $this->outputLine('Requesting patch details from Gerrit.');
        $package = $this->gerritService->getPatchTargetPackage($patchId);
        $packageKey = $package->getPackageKey();
        $packagePath = $package->getPackagePath();
        $collectionPath = dirname($packagePath);
        $this->outputLine(sprintf('Determined <b>%s</b> as the target package key for this change.', $packageKey));
        $commitDetails = $this->gerritService->getCommitDetails($patchId);
        $oldParentCommitId = $commitDetails['parents'][0]['commit'];
        $newParentCommitId = trim($this->executeCommand(sprintf('git log --grep=%s --pretty=format:%%H', $oldParentCommitId), $collectionPath));
        if (!$newParentCommitId) {
            $this->outputLine('<error>Unable to find old parent commit ID for change in development collection.</error>');
            return;
        }
        $this->outputLine(sprintf('<success>Found old parent commit ID for change in development collection.</success>', $packageKey));
        $this->outputLine('');
        $cleanRepository = trim($this->executeCommand('git status --porcelain', $collectionPath));
        if ($cleanRepository) {
            $this->outputLine(sprintf('<error>Development collection "%s" not clean.</error>', $collectionPath));
            return;
        }
        $this->outputLine('');
        $this->outputLine('Creating new branch for change.');
        $this->output($this->executeCommand('git checkout master', $collectionPath));
        $this->output($this->executeCommand('git pull', $collectionPath));
        $this->output($this->executeCommand(sprintf('git branch -f gerrit-%s', $patchId), $collectionPath));
        $this->output($this->executeCommand(sprintf('git checkout gerrit-%s', $patchId), $collectionPath));
        $this->output($this->executeCommand(sprintf('git reset --hard %s', $newParentCommitId), $collectionPath));
        $this->outputLine('<success>Successfully created new branch for change.</success>');
        $this->outputLine('');
        $this->outputLine('Fetching change from Gerrit.');
        $patchPathAndFileName = $this->gerritService->getPatchFromGerrit($patchId);
        $this->outputLine('<success>Successfully fetched change from Gerrit.</success>');
        $this->outputLine(sprintf('The following changes will be applied to package <b>%s</b>', $packageKey));
        $this->output($this->executeCommand(sprintf('git apply --directory %s --check %s', $packageKey, $patchPathAndFileName), $collectionPath));
        $this->output($this->executeCommand(sprintf('git apply --directory %s --stat %s', $packageKey, $patchPathAndFileName), $collectionPath));
        $this->outputLine('');
        $this->outputLine('Applying change in new branch.');
        $this->output($this->executeCommand(sprintf('git am --directory %s %s', $packageKey, $patchPathAndFileName), $collectionPath));
        $this->outputLine(sprintf('<success>Successfully applied patch %1$s in branch "gerrit-%1$s"</success>', $patchId));
        $this->outputLine('');
        $this->outputLine(sprintf('<b>Converting change to PSR-2 and updating license header</b>', $patchId));
        $modifiedFiles = array_filter(explode(PHP_EOL, $this->executeCommand('git diff HEAD~1 --name-only', $collectionPath)));
        $this->executeCommand('git reset --soft HEAD~1', $collectionPath);
        foreach ($modifiedFiles as $modifiedFile) {
            if (pathinfo($modifiedFile, PATHINFO_EXTENSION) === 'php') {
                $this->output($this->executeCommand(sprintf('php-cs-fixer fix --level=psr2 %s', $modifiedFile), $collectionPath, true));
                Tools::searchAndReplace('/\\/\\*{1}([\\s\\S]+?)(script belongs)([\\s\\S]+?)\\*\\//', '/*
 * This file is part of the ' . $packageKey . ' package.
 *
 * (c) Contributors of the Neos Project - www.neos.io
 *
 * This package is Open Source Software. For the full copyright and license
 * information, please view the LICENSE file which was distributed with this
 * source code.
 */', $collectionPath . DIRECTORY_SEPARATOR . $modifiedFile, true);
            }
        }
        $this->outputLine('');
        $this->outputLine(sprintf('<b>Stashing change, resetting branch top master branch tip and applying change</b>', $patchId));
        $this->executeCommand('git stash', $collectionPath);
        $this->executeCommand('git reset --hard master', $collectionPath);
        $stashApplyingOutput = trim($this->executeCommand('git stash pop', $collectionPath, true));
        $commitMessage = preg_replace('/\\n\\n\\n/', "\n", preg_replace('/(Releases|Change-Id):.+/', '', $commitDetails['message']));
        if (strpos($stashApplyingOutput, 'CONFLICT') !== -1) {
            $this->output('<error>' . $stashApplyingOutput . '</error>');
            $this->outputLine('');
            $this->outputLine('');
            $this->outputLine('<success>Change applied with <error>conflicts</error>.</success>');
            $this->outputLine('');
            $this->outputLine('<b>Next steps:</b>');
            $this->outputLine('');
            $this->outputLine(sprintf('<b>1. Go to "%s" where the branch "gerrit-%s" is checked out with the changes applied.</b>', $collectionPath, $patchId));
            $this->outputLine('');
            $this->outputLine('<b>2. Fix the conflicts and create new commit with the following commit message:</b>');
            $this->output($commitMessage);
            $this->outputLine('');
            $this->outputLine('<b>3. Push the new branch to your personal fork and create a new pull request from it.</b>');
        } else {
            $this->outputLine('');
            $this->outputLine('');
            $this->outputLine('<success>Change applied on master <b>without</b> conflicts.</success>');
            $this->outputLine('');
            $this->outputLine('<b>Next steps:</b>');
            $this->outputLine('');
            $this->outputLine(sprintf('<b>1. Go to "%s" where the branch "gerrit-%s" is checked out with the changes applied.</b>', $collectionPath, $patchId));
            $this->outputLine('');
            $this->outputLine('<b>2. Fix the conflicts and create new commit with the following commit message:</b>');
            $this->outputLine('');
            $this->outputLine('<b>3. Push the new branch to your personal fork and create a new pull request from it.</b>');
        }
    }