console-helpers /
svn-buddy
| 1 | <?php |
||||
| 2 | /** |
||||
| 3 | * This file is part of the SVN-Buddy library. |
||||
| 4 | * For the full copyright and license information, please view |
||||
| 5 | * the LICENSE file that was distributed with this source code. |
||||
| 6 | * |
||||
| 7 | * @copyright Alexander Obuhovich <[email protected]> |
||||
| 8 | * @link https://github.com/console-helpers/svn-buddy |
||||
| 9 | */ |
||||
| 10 | |||||
| 11 | namespace ConsoleHelpers\SVNBuddy\Command; |
||||
| 12 | |||||
| 13 | |||||
| 14 | use ConsoleHelpers\ConsoleKit\Exception\CommandException; |
||||
| 15 | use ConsoleHelpers\SVNBuddy\Config\AbstractConfigSetting; |
||||
| 16 | use ConsoleHelpers\SVNBuddy\Config\ArrayConfigSetting; |
||||
| 17 | use ConsoleHelpers\SVNBuddy\Config\ChoiceConfigSetting; |
||||
| 18 | use ConsoleHelpers\SVNBuddy\Config\StringConfigSetting; |
||||
| 19 | use ConsoleHelpers\SVNBuddy\Helper\OutputHelper; |
||||
| 20 | use ConsoleHelpers\SVNBuddy\MergeSourceDetector\AbstractMergeSourceDetector; |
||||
| 21 | use ConsoleHelpers\SVNBuddy\Repository\Connector\UrlResolver; |
||||
| 22 | use ConsoleHelpers\SVNBuddy\Repository\Parser\RevisionListParser; |
||||
| 23 | use ConsoleHelpers\SVNBuddy\Repository\WorkingCopyConflictTracker; |
||||
| 24 | use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; |
||||
| 25 | use Symfony\Component\Console\Helper\Table; |
||||
| 26 | use Symfony\Component\Console\Input\InputArgument; |
||||
| 27 | use Symfony\Component\Console\Input\InputInterface; |
||||
| 28 | use Symfony\Component\Console\Input\InputOption; |
||||
| 29 | use Symfony\Component\Console\Output\OutputInterface; |
||||
| 30 | |||||
| 31 | class MergeCommand extends AbstractCommand implements IAggregatorAwareCommand, IConfigAwareCommand |
||||
| 32 | { |
||||
| 33 | |||||
| 34 | const SETTING_MERGE_SOURCE_URL = 'merge.source-url'; |
||||
| 35 | |||||
| 36 | const SETTING_MERGE_RECENT_CONFLICTS = 'merge.recent-conflicts'; |
||||
| 37 | |||||
| 38 | const SETTING_MERGE_AUTO_COMMIT = 'merge.auto-commit'; |
||||
| 39 | |||||
| 40 | const REVISION_ALL = 'all'; |
||||
| 41 | |||||
| 42 | /** |
||||
| 43 | * Merge source detector. |
||||
| 44 | * |
||||
| 45 | * @var AbstractMergeSourceDetector |
||||
| 46 | */ |
||||
| 47 | private $_mergeSourceDetector; |
||||
| 48 | |||||
| 49 | /** |
||||
| 50 | * Revision list parser. |
||||
| 51 | * |
||||
| 52 | * @var RevisionListParser |
||||
| 53 | */ |
||||
| 54 | private $_revisionListParser; |
||||
| 55 | |||||
| 56 | /** |
||||
| 57 | * Usable revisions (either to be merged OR to be unmerged). |
||||
| 58 | * |
||||
| 59 | * @var array |
||||
| 60 | */ |
||||
| 61 | private $_usableRevisions = array(); |
||||
| 62 | |||||
| 63 | /** |
||||
| 64 | * Url resolver. |
||||
| 65 | * |
||||
| 66 | * @var UrlResolver |
||||
| 67 | */ |
||||
| 68 | private $_urlResolver; |
||||
| 69 | |||||
| 70 | /** |
||||
| 71 | * Working copy conflict tracker. |
||||
| 72 | * |
||||
| 73 | * @var WorkingCopyConflictTracker |
||||
| 74 | */ |
||||
| 75 | private $_workingCopyConflictTracker; |
||||
| 76 | |||||
| 77 | /** |
||||
| 78 | * Prepare dependencies. |
||||
| 79 | * |
||||
| 80 | * @return void |
||||
| 81 | */ |
||||
| 82 | protected function prepareDependencies() |
||||
| 83 | { |
||||
| 84 | parent::prepareDependencies(); |
||||
| 85 | |||||
| 86 | $container = $this->getContainer(); |
||||
| 87 | |||||
| 88 | $this->_mergeSourceDetector = $container['merge_source_detector']; |
||||
| 89 | $this->_revisionListParser = $container['revision_list_parser']; |
||||
| 90 | $this->_urlResolver = $container['repository_url_resolver']; |
||||
| 91 | $this->_workingCopyConflictTracker = $container['working_copy_conflict_tracker']; |
||||
| 92 | } |
||||
| 93 | |||||
| 94 | /** |
||||
| 95 | * {@inheritdoc} |
||||
| 96 | */ |
||||
| 97 | protected function configure() |
||||
| 98 | { |
||||
| 99 | $this |
||||
| 100 | ->setName('merge') |
||||
| 101 | ->setDescription('Merge changes from another project or ref within same project into a working copy') |
||||
| 102 | ->addArgument( |
||||
| 103 | 'path', |
||||
| 104 | InputArgument::OPTIONAL, |
||||
| 105 | 'Working copy path', |
||||
| 106 | '.' |
||||
| 107 | ) |
||||
| 108 | ->addOption( |
||||
| 109 | 'source-url', |
||||
| 110 | null, |
||||
| 111 | InputOption::VALUE_REQUIRED, |
||||
| 112 | 'Merge source url (absolute or relative) or ref name, e.g. <comment>branches/branch-name</comment>' |
||||
| 113 | ) |
||||
| 114 | ->addOption( |
||||
| 115 | 'revisions', |
||||
| 116 | 'r', |
||||
| 117 | InputOption::VALUE_REQUIRED, |
||||
| 118 | 'List of revision(-s) and/or revision range(-s) to merge, e.g. <comment>53324</comment>, <comment>1224-4433</comment> or <comment>all</comment>' |
||||
| 119 | ) |
||||
| 120 | ->addOption( |
||||
| 121 | 'exclude-revisions', |
||||
| 122 | null, |
||||
| 123 | InputOption::VALUE_REQUIRED, |
||||
| 124 | 'List of revision(-s) and/or revision range(-s) not to merge, e.g. <comment>53324</comment>, <comment>1224-4433</comment>' |
||||
| 125 | ) |
||||
| 126 | ->addOption( |
||||
| 127 | 'bugs', |
||||
| 128 | 'b', |
||||
| 129 | InputOption::VALUE_REQUIRED, |
||||
| 130 | 'List of bug(-s) to merge, e.g. <comment>JRA-1234</comment>, <comment>43644</comment>' |
||||
| 131 | ) |
||||
| 132 | ->addOption( |
||||
| 133 | 'exclude-bugs', |
||||
| 134 | null, |
||||
| 135 | InputOption::VALUE_REQUIRED, |
||||
| 136 | 'List of bug(-s) not to merge, e.g. <comment>JRA-1234</comment>, <comment>43644</comment>' |
||||
| 137 | ) |
||||
| 138 | ->addOption( |
||||
| 139 | 'merges', |
||||
| 140 | null, |
||||
| 141 | InputOption::VALUE_NONE, |
||||
| 142 | 'Show merge revisions only' |
||||
| 143 | ) |
||||
| 144 | ->addOption( |
||||
| 145 | 'no-merges', |
||||
| 146 | null, |
||||
| 147 | InputOption::VALUE_NONE, |
||||
| 148 | 'Hide merge revisions' |
||||
| 149 | ) |
||||
| 150 | ->addOption( |
||||
| 151 | 'with-full-message', |
||||
| 152 | 'f', |
||||
| 153 | InputOption::VALUE_NONE, |
||||
| 154 | 'Shows non-truncated commit messages' |
||||
| 155 | ) |
||||
| 156 | ->addOption( |
||||
| 157 | 'with-details', |
||||
| 158 | 'd', |
||||
| 159 | InputOption::VALUE_NONE, |
||||
| 160 | 'Shows detailed revision information, e.g. paths affected' |
||||
| 161 | ) |
||||
| 162 | ->addOption( |
||||
| 163 | 'with-summary', |
||||
| 164 | 's', |
||||
| 165 | InputOption::VALUE_NONE, |
||||
| 166 | 'Shows number of added/changed/removed paths in the revision' |
||||
| 167 | ) |
||||
| 168 | ->addOption( |
||||
| 169 | 'update-revision', |
||||
| 170 | null, |
||||
| 171 | InputOption::VALUE_REQUIRED, |
||||
| 172 | 'Update working copy to given revision before performing a merge' |
||||
| 173 | ) |
||||
| 174 | ->addOption( |
||||
| 175 | 'auto-commit', |
||||
| 176 | null, |
||||
| 177 | InputOption::VALUE_REQUIRED, |
||||
| 178 | 'Automatically perform commit on successful merge, e.g. <comment>yes</comment> or <comment>no</comment>' |
||||
| 179 | ) |
||||
| 180 | ->addOption( |
||||
| 181 | 'auto-deploy', |
||||
| 182 | null, |
||||
| 183 | InputOption::VALUE_REQUIRED, |
||||
| 184 | 'Automatically perform remote deployment on successful merge commit, e.g. <comment>yes</comment> or <comment>no</comment>' |
||||
| 185 | ) |
||||
| 186 | ->addOption( |
||||
| 187 | 'record-only', |
||||
| 188 | null, |
||||
| 189 | InputOption::VALUE_NONE, |
||||
| 190 | 'Mark revisions as merged without actually merging them' |
||||
| 191 | ) |
||||
| 192 | ->addOption( |
||||
| 193 | 'reverse', |
||||
| 194 | null, |
||||
| 195 | InputOption::VALUE_NONE, |
||||
| 196 | 'Rollback previously merged revisions' |
||||
| 197 | ) |
||||
| 198 | ->addOption( |
||||
| 199 | 'aggregate', |
||||
| 200 | 'a', |
||||
| 201 | InputOption::VALUE_NONE, |
||||
| 202 | 'Aggregate displayed revisions by bugs' |
||||
| 203 | ) |
||||
| 204 | ->addOption( |
||||
| 205 | 'preview', |
||||
| 206 | 'p', |
||||
| 207 | InputOption::VALUE_NONE, |
||||
| 208 | 'Preview revisions to be merged' |
||||
| 209 | ); |
||||
| 210 | |||||
| 211 | parent::configure(); |
||||
| 212 | } |
||||
| 213 | |||||
| 214 | /** |
||||
| 215 | * Return possible values for the named option |
||||
| 216 | * |
||||
| 217 | * @param string $optionName Option name. |
||||
| 218 | * @param CompletionContext $context Completion context. |
||||
| 219 | * |
||||
| 220 | * @return array |
||||
| 221 | */ |
||||
| 222 | public function completeOptionValues($optionName, CompletionContext $context) |
||||
| 223 | { |
||||
| 224 | $ret = parent::completeOptionValues($optionName, $context); |
||||
| 225 | |||||
| 226 | if ( $optionName === 'revisions' ) { |
||||
| 227 | return array('all'); |
||||
| 228 | } |
||||
| 229 | |||||
| 230 | if ( $optionName === 'source-url' ) { |
||||
| 231 | return $this->getAllRefs(); |
||||
| 232 | } |
||||
| 233 | |||||
| 234 | if ( $optionName === 'auto-commit' || $optionName === 'auto-deploy' ) { |
||||
| 235 | return array('yes', 'no'); |
||||
| 236 | } |
||||
| 237 | |||||
| 238 | return $ret; |
||||
| 239 | } |
||||
| 240 | |||||
| 241 | /** |
||||
| 242 | * {@inheritdoc} |
||||
| 243 | * |
||||
| 244 | * @throws CommandException When everything is merged. |
||||
| 245 | * @throws CommandException When manually specified revisions are already merged. |
||||
| 246 | * @throws CommandException When bugs from "--bugs" option are not found. |
||||
| 247 | */ |
||||
| 248 | protected function execute(InputInterface $input, OutputInterface $output) |
||||
| 249 | { |
||||
| 250 | $bugs = $this->getList($this->io->getOption('bugs')); |
||||
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||
| 251 | $revisions = $this->getList($this->io->getOption('revisions')); |
||||
| 252 | |||||
| 253 | $wc_path = $this->getWorkingCopyPath(); |
||||
| 254 | |||||
| 255 | $this->ensureLatestWorkingCopy($wc_path); |
||||
| 256 | |||||
| 257 | $source_url = $this->getSourceUrl($wc_path); |
||||
| 258 | $this->printSourceAndTarget($source_url, $wc_path); |
||||
| 259 | $this->_usableRevisions = $this->getUsableRevisions($source_url, $wc_path); |
||||
| 260 | |||||
| 261 | if ( ($bugs || $revisions) && !$this->_usableRevisions ) { |
||||
|
0 ignored issues
–
show
The expression
$revisions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
The expression
$bugs of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
The expression
$this->_usableRevisions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||||
| 262 | throw new CommandException(\sprintf( |
||||
| 263 | 'Nothing to %s.', |
||||
| 264 | $this->isReverseMerge() ? 'reverse-merge' : 'merge' |
||||
| 265 | )); |
||||
| 266 | } |
||||
| 267 | |||||
| 268 | $this->ensureWorkingCopyWithoutConflicts($source_url, $wc_path); |
||||
| 269 | |||||
| 270 | if ( $this->shouldUseAll($revisions) ) { |
||||
| 271 | $revisions = $this->filterMergeableRevisions($this->_usableRevisions, $source_url); |
||||
| 272 | } |
||||
| 273 | else { |
||||
| 274 | if ( $revisions ) { |
||||
|
0 ignored issues
–
show
The expression
$revisions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||||
| 275 | $revisions = $this->getDirectRevisions($revisions, $source_url); |
||||
| 276 | } |
||||
| 277 | |||||
| 278 | if ( $bugs ) { |
||||
|
0 ignored issues
–
show
The expression
$bugs of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||||
| 279 | $revisions_from_bugs = $this->getRevisionLog($source_url)->find('bugs', $bugs); |
||||
| 280 | |||||
| 281 | if ( !$revisions_from_bugs ) { |
||||
|
0 ignored issues
–
show
The expression
$revisions_from_bugs of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||||
| 282 | throw new CommandException('Specified bugs aren\'t mentioned in any of revisions'); |
||||
| 283 | } |
||||
| 284 | |||||
| 285 | $revisions = array_merge($revisions, $revisions_from_bugs); |
||||
| 286 | } |
||||
| 287 | |||||
| 288 | $revisions = $this->filterMergeableRevisions($revisions, $source_url); |
||||
| 289 | |||||
| 290 | if ( $revisions ) { |
||||
|
0 ignored issues
–
show
The expression
$revisions of type integer[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||||
| 291 | $revisions = array_intersect($revisions, $this->_usableRevisions); |
||||
| 292 | |||||
| 293 | // Auto-commit instead of failing. |
||||
| 294 | if ( !$revisions && $this->performCommit() ) { |
||||
|
0 ignored issues
–
show
The expression
$revisions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||||
| 295 | return; |
||||
| 296 | } |
||||
| 297 | |||||
| 298 | if ( !$revisions ) { |
||||
|
0 ignored issues
–
show
The expression
$revisions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||||
| 299 | throw new CommandException(\sprintf( |
||||
| 300 | 'Requested revisions are %s', |
||||
| 301 | $this->isReverseMerge() ? 'not yet merged' : 'already merged' |
||||
| 302 | )); |
||||
| 303 | } |
||||
| 304 | } |
||||
| 305 | } |
||||
| 306 | |||||
| 307 | if ( $revisions ) { |
||||
| 308 | if ( $this->io->getOption('preview') ) { |
||||
| 309 | // Display mergeable revisions according to user-specified filters. |
||||
| 310 | $this->printRevisions($source_url, $revisions); |
||||
| 311 | } |
||||
| 312 | else { |
||||
| 313 | // Perform merge using user-specified filters. |
||||
| 314 | $this->performMerge($source_url, $wc_path, $revisions); |
||||
| 315 | } |
||||
| 316 | } |
||||
| 317 | elseif ( $this->_usableRevisions ) { |
||||
|
0 ignored issues
–
show
The expression
$this->_usableRevisions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||||
| 318 | // Display all mergeable revisions, because user haven't specified any revisions for merging. |
||||
| 319 | $this->printRevisions($source_url, $this->_usableRevisions); |
||||
| 320 | } |
||||
| 321 | } |
||||
| 322 | |||||
| 323 | /** |
||||
| 324 | * Filters mergeable revision list. |
||||
| 325 | * |
||||
| 326 | * @param array $revisions Revisions. |
||||
| 327 | * @param string $source_url Source URL. |
||||
| 328 | * |
||||
| 329 | * @return integer[] |
||||
| 330 | * @throws CommandException When bugs from "--exclude-bugs" option are not found. |
||||
| 331 | */ |
||||
| 332 | protected function filterMergeableRevisions(array $revisions, $source_url) |
||||
| 333 | { |
||||
| 334 | $exclude_bugs = $this->getList($this->io->getOption('exclude-bugs')); |
||||
|
0 ignored issues
–
show
It seems like
$this->io->getOption('exclude-bugs') can also be of type string[]; however, parameter $string of ConsoleHelpers\SVNBuddy\...tractCommand::getList() does only seem to accept string, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 335 | $exclude_revisions = $this->getList($this->io->getOption('exclude-revisions')); |
||||
| 336 | |||||
| 337 | if ( $exclude_revisions ) { |
||||
|
0 ignored issues
–
show
The expression
$exclude_revisions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||||
| 338 | $revisions = array_diff( |
||||
| 339 | $revisions, |
||||
| 340 | $this->getDirectRevisions($exclude_revisions, $source_url) |
||||
| 341 | ); |
||||
| 342 | } |
||||
| 343 | |||||
| 344 | if ( $exclude_bugs ) { |
||||
|
0 ignored issues
–
show
The expression
$exclude_bugs of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||||
| 345 | $exclude_revisions_from_bugs = $this->getRevisionLog($source_url)->find('bugs', $exclude_bugs); |
||||
| 346 | |||||
| 347 | if ( !$exclude_revisions_from_bugs ) { |
||||
|
0 ignored issues
–
show
The expression
$exclude_revisions_from_bugs of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||||
| 348 | throw new CommandException('Specified exclude-bugs aren\'t mentioned in any of revisions'); |
||||
| 349 | } |
||||
| 350 | |||||
| 351 | $revisions = array_diff($revisions, $exclude_revisions_from_bugs); |
||||
| 352 | } |
||||
| 353 | |||||
| 354 | if ( $this->io->getOption('merges') ) { |
||||
| 355 | $revisions = array_intersect($revisions, $this->getRevisionLog($source_url)->find('merges', 'all_merges')); |
||||
| 356 | } |
||||
| 357 | elseif ( $this->io->getOption('no-merges') ) { |
||||
| 358 | $revisions = array_diff($revisions, $this->getRevisionLog($source_url)->find('merges', 'all_merges')); |
||||
| 359 | } |
||||
| 360 | |||||
| 361 | return $revisions; |
||||
| 362 | } |
||||
| 363 | |||||
| 364 | /** |
||||
| 365 | * Determines if all usable revisions should be processed. |
||||
| 366 | * |
||||
| 367 | * @param array $revisions Revisions. |
||||
| 368 | * |
||||
| 369 | * @return boolean |
||||
| 370 | */ |
||||
| 371 | protected function shouldUseAll(array $revisions) |
||||
| 372 | { |
||||
| 373 | return $revisions === array(self::REVISION_ALL); |
||||
| 374 | } |
||||
| 375 | |||||
| 376 | /** |
||||
| 377 | * Ensures, that working copy is up to date. |
||||
| 378 | * |
||||
| 379 | * @param string $wc_path Working copy path. |
||||
| 380 | * |
||||
| 381 | * @return void |
||||
| 382 | */ |
||||
| 383 | protected function ensureLatestWorkingCopy($wc_path) |
||||
| 384 | { |
||||
| 385 | $this->io->write(' * Working Copy Status ... '); |
||||
| 386 | $update_revision = $this->io->getOption('update-revision'); |
||||
| 387 | |||||
| 388 | if ( $this->repositoryConnector->getWorkingCopyMissing($wc_path) ) { |
||||
| 389 | $this->io->writeln('<error>Locally deleted files found</error>'); |
||||
| 390 | $this->updateWorkingCopy($wc_path, $update_revision); |
||||
| 391 | |||||
| 392 | return; |
||||
| 393 | } |
||||
| 394 | |||||
| 395 | $working_copy_revisions = $this->repositoryConnector->getWorkingCopyRevisions($wc_path); |
||||
| 396 | |||||
| 397 | if ( count($working_copy_revisions) > 1 ) { |
||||
| 398 | $this->io->writeln( |
||||
| 399 | '<error>Mixed revisions: ' . implode(', ', $working_copy_revisions) . '</error>' |
||||
| 400 | ); |
||||
| 401 | $this->updateWorkingCopy($wc_path, $update_revision); |
||||
| 402 | |||||
| 403 | return; |
||||
| 404 | } |
||||
| 405 | |||||
| 406 | $update_revision = $this->getWorkingCopyUpdateRevision($wc_path); |
||||
| 407 | |||||
| 408 | if ( isset($update_revision) ) { |
||||
| 409 | $this->io->writeln('<error>Not at ' . $update_revision . ' revision</error>'); |
||||
| 410 | $this->updateWorkingCopy($wc_path, $update_revision); |
||||
| 411 | |||||
| 412 | return; |
||||
| 413 | } |
||||
| 414 | |||||
| 415 | $this->io->writeln('<info>Up to date</info>'); |
||||
| 416 | } |
||||
| 417 | |||||
| 418 | /** |
||||
| 419 | * Returns revision, that working copy needs to be updated to. |
||||
| 420 | * |
||||
| 421 | * @param string $wc_path Working copy path. |
||||
| 422 | * |
||||
| 423 | * @return integer|null |
||||
| 424 | */ |
||||
| 425 | protected function getWorkingCopyUpdateRevision($wc_path) |
||||
| 426 | { |
||||
| 427 | $update_revision = $this->io->getOption('update-revision'); |
||||
| 428 | $actual_revision = $this->repositoryConnector->getLastRevision($wc_path); |
||||
| 429 | |||||
| 430 | if ( isset($update_revision) ) { |
||||
| 431 | if ( is_numeric($update_revision) ) { |
||||
| 432 | return (int)$update_revision === (int)$actual_revision ? null : $update_revision; |
||||
|
0 ignored issues
–
show
|
|||||
| 433 | } |
||||
| 434 | |||||
| 435 | return $update_revision; |
||||
|
0 ignored issues
–
show
|
|||||
| 436 | } |
||||
| 437 | |||||
| 438 | $repository_revision = $this->repositoryConnector->getLastRevision( |
||||
| 439 | $this->repositoryConnector->getWorkingCopyUrl($wc_path) |
||||
| 440 | ); |
||||
| 441 | |||||
| 442 | return $repository_revision > $actual_revision ? $repository_revision : null; |
||||
| 443 | } |
||||
| 444 | |||||
| 445 | /** |
||||
| 446 | * Updates working copy. |
||||
| 447 | * |
||||
| 448 | * @param string $wc_path Working copy path. |
||||
| 449 | * @param mixed|null $revision Revision. |
||||
| 450 | * |
||||
| 451 | * @return void |
||||
| 452 | */ |
||||
| 453 | protected function updateWorkingCopy($wc_path, $revision = null) |
||||
| 454 | { |
||||
| 455 | $arguments = array('path' => $wc_path, '--ignore-externals' => true); |
||||
| 456 | |||||
| 457 | if ( isset($revision) ) { |
||||
| 458 | $arguments['--revision'] = $revision; |
||||
| 459 | } |
||||
| 460 | |||||
| 461 | $this->runOtherCommand('update', $arguments); |
||||
| 462 | } |
||||
| 463 | |||||
| 464 | /** |
||||
| 465 | * Returns source url for merge. |
||||
| 466 | * |
||||
| 467 | * @param string $wc_path Working copy path. |
||||
| 468 | * |
||||
| 469 | * @return string |
||||
| 470 | * @throws CommandException When source path is invalid. |
||||
| 471 | */ |
||||
| 472 | protected function getSourceUrl($wc_path) |
||||
| 473 | { |
||||
| 474 | $source_url = $this->io->getOption('source-url'); |
||||
| 475 | |||||
| 476 | if ( $source_url === null ) { |
||||
| 477 | $source_url = $this->getSetting(self::SETTING_MERGE_SOURCE_URL); |
||||
| 478 | } |
||||
| 479 | elseif ( !$this->repositoryConnector->isUrl($source_url) ) { |
||||
|
0 ignored issues
–
show
It seems like
$source_url can also be of type string[]; however, parameter $path of ConsoleHelpers\SVNBuddy\...ctor\Connector::isUrl() does only seem to accept string, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 480 | $wc_url = $this->repositoryConnector->getWorkingCopyUrl($wc_path); |
||||
| 481 | $source_url = $this->_urlResolver->resolve($wc_url, $source_url); |
||||
|
0 ignored issues
–
show
It seems like
$source_url can also be of type string[]; however, parameter $url_to_resolve of ConsoleHelpers\SVNBuddy\...\UrlResolver::resolve() does only seem to accept string, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 482 | } |
||||
| 483 | |||||
| 484 | if ( !$source_url ) { |
||||
| 485 | $wc_url = $this->repositoryConnector->getWorkingCopyUrl($wc_path); |
||||
| 486 | $source_url = $this->_mergeSourceDetector->detect($wc_url); |
||||
| 487 | |||||
| 488 | if ( $source_url ) { |
||||
| 489 | $this->setSetting(self::SETTING_MERGE_SOURCE_URL, $source_url); |
||||
| 490 | } |
||||
| 491 | } |
||||
| 492 | |||||
| 493 | if ( !$source_url ) { |
||||
| 494 | $wc_url = $this->repositoryConnector->getWorkingCopyUrl($wc_path); |
||||
| 495 | $error_msg = 'Unable to guess "--source-url" option value. Please specify it manually.' . PHP_EOL; |
||||
| 496 | $error_msg .= 'Working Copy URL: ' . $wc_url . '.'; |
||||
| 497 | throw new CommandException($error_msg); |
||||
| 498 | } |
||||
| 499 | |||||
| 500 | return $source_url; |
||||
| 501 | } |
||||
| 502 | |||||
| 503 | /** |
||||
| 504 | * Prints information about merge source & target. |
||||
| 505 | * |
||||
| 506 | * @param string $source_url Merge source: url. |
||||
| 507 | * @param string $wc_path Merge target: working copy path. |
||||
| 508 | * |
||||
| 509 | * @return void |
||||
| 510 | */ |
||||
| 511 | protected function printSourceAndTarget($source_url, $wc_path) |
||||
| 512 | { |
||||
| 513 | $relative_source_url = $this->repositoryConnector->getRelativePath($source_url); |
||||
| 514 | $relative_target_url = $this->repositoryConnector->getRelativePath($wc_path); |
||||
| 515 | |||||
| 516 | $this->io->writeln(' * Merge Source ... <info>' . $relative_source_url . '</info>'); |
||||
| 517 | $this->io->writeln(' * Merge Target ... <info>' . $relative_target_url . '</info>'); |
||||
| 518 | } |
||||
| 519 | |||||
| 520 | /** |
||||
| 521 | * Ensures, that there are some usable revisions. |
||||
| 522 | * |
||||
| 523 | * @param string $source_url Merge source: url. |
||||
| 524 | * @param string $wc_path Merge target: working copy path. |
||||
| 525 | * |
||||
| 526 | * @return array |
||||
| 527 | */ |
||||
| 528 | protected function getUsableRevisions($source_url, $wc_path) |
||||
| 529 | { |
||||
| 530 | // Avoid missing revision query progress bar overwriting following output. |
||||
| 531 | $revision_log = $this->getRevisionLog($source_url); |
||||
| 532 | |||||
| 533 | $this->io->write(sprintf( |
||||
| 534 | ' * Upcoming %s Status (no filters) ... ', |
||||
| 535 | $this->isReverseMerge() ? 'Reverse-merge' : 'Merge' |
||||
| 536 | )); |
||||
| 537 | $usable_revisions = $this->calculateUsableRevisions($source_url, $wc_path); |
||||
| 538 | |||||
| 539 | if ( $usable_revisions ) { |
||||
|
0 ignored issues
–
show
The expression
$usable_revisions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||||
| 540 | $usable_bugs = $revision_log->getBugsFromRevisions($usable_revisions); |
||||
| 541 | $error_msg = '<error>%d revision(-s) or %d bug(-s) %s</error>'; |
||||
| 542 | $this->io->writeln(sprintf( |
||||
| 543 | $error_msg, |
||||
| 544 | count($usable_revisions), |
||||
| 545 | count($usable_bugs), |
||||
| 546 | $this->isReverseMerge() ? 'merged' : 'not merged' |
||||
| 547 | )); |
||||
| 548 | } |
||||
| 549 | else { |
||||
| 550 | $this->io->writeln('<info>Up to date</info>'); |
||||
| 551 | } |
||||
| 552 | |||||
| 553 | return $usable_revisions; |
||||
| 554 | } |
||||
| 555 | |||||
| 556 | /** |
||||
| 557 | * Returns usable revisions. |
||||
| 558 | * |
||||
| 559 | * @param string $source_url Merge source: url. |
||||
| 560 | * @param string $wc_path Merge target: working copy path. |
||||
| 561 | * |
||||
| 562 | * @return array |
||||
| 563 | */ |
||||
| 564 | protected function calculateUsableRevisions($source_url, $wc_path) |
||||
| 565 | { |
||||
| 566 | $source_url = $this->repositoryConnector->removeCredentials($source_url); |
||||
| 567 | |||||
| 568 | $command = $this->repositoryConnector->getCommand( |
||||
| 569 | 'mergeinfo', |
||||
| 570 | array( |
||||
| 571 | '--show-revs', |
||||
| 572 | $this->isReverseMerge() ? 'merged' : 'eligible', |
||||
| 573 | $source_url, |
||||
| 574 | $wc_path, |
||||
| 575 | ) |
||||
| 576 | ); |
||||
| 577 | |||||
| 578 | $merge_info = $this->repositoryConnector->getProperty('svn:mergeinfo', $wc_path); |
||||
| 579 | |||||
| 580 | $cache_invalidator = array( |
||||
| 581 | 'source:' . $this->repositoryConnector->getLastRevision($source_url), |
||||
| 582 | 'merged_hash:' . crc32($merge_info), |
||||
| 583 | ); |
||||
| 584 | $command->setCacheInvalidator(implode(';', $cache_invalidator)); |
||||
| 585 | |||||
| 586 | $merge_info = $command->run(); |
||||
| 587 | $merge_info = explode(PHP_EOL, $merge_info); |
||||
| 588 | |||||
| 589 | foreach ( $merge_info as $index => $revision ) { |
||||
| 590 | $merge_info[$index] = ltrim($revision, 'r'); |
||||
| 591 | } |
||||
| 592 | |||||
| 593 | return array_filter($merge_info); |
||||
| 594 | } |
||||
| 595 | |||||
| 596 | /** |
||||
| 597 | * Parses information from "svn:mergeinfo" property. |
||||
| 598 | * |
||||
| 599 | * @param string $source_path Merge source: path in repository. |
||||
| 600 | * @param string $wc_path Merge target: working copy path. |
||||
| 601 | * |
||||
| 602 | * @return array |
||||
| 603 | */ |
||||
| 604 | protected function getMergedRevisions($source_path, $wc_path) |
||||
| 605 | { |
||||
| 606 | $merge_info = $this->repositoryConnector->getProperty('svn:mergeinfo', $wc_path); |
||||
| 607 | $merge_info = array_filter(explode("\n", $merge_info)); |
||||
| 608 | |||||
| 609 | foreach ( $merge_info as $merge_info_line ) { |
||||
| 610 | list($path, $revisions) = explode(':', $merge_info_line, 2); |
||||
| 611 | |||||
| 612 | if ( $path === $source_path ) { |
||||
| 613 | return $this->_revisionListParser->expandRanges(explode(',', $revisions)); |
||||
| 614 | } |
||||
| 615 | } |
||||
| 616 | |||||
| 617 | return array(); |
||||
| 618 | } |
||||
| 619 | |||||
| 620 | /** |
||||
| 621 | * Validates revisions to actually exist. |
||||
| 622 | * |
||||
| 623 | * @param array $revisions Revisions. |
||||
| 624 | * @param string $repository_url Repository url. |
||||
| 625 | * |
||||
| 626 | * @return array |
||||
| 627 | * @throws CommandException When revision doesn't exist. |
||||
| 628 | */ |
||||
| 629 | protected function getDirectRevisions(array $revisions, $repository_url) |
||||
| 630 | { |
||||
| 631 | $revision_log = $this->getRevisionLog($repository_url); |
||||
| 632 | |||||
| 633 | try { |
||||
| 634 | $revisions = $this->_revisionListParser->expandRanges($revisions); |
||||
| 635 | $revision_log->getRevisionsData('summary', $revisions); |
||||
| 636 | } |
||||
| 637 | catch ( \InvalidArgumentException $e ) { |
||||
| 638 | throw new CommandException($e->getMessage()); |
||||
| 639 | } |
||||
| 640 | |||||
| 641 | return $revisions; |
||||
| 642 | } |
||||
| 643 | |||||
| 644 | /** |
||||
| 645 | * Performs merge. |
||||
| 646 | * |
||||
| 647 | * @param string $source_url Merge source: url. |
||||
| 648 | * @param string $wc_path Merge target: working copy path. |
||||
| 649 | * @param array $revisions Revisions to merge. |
||||
| 650 | * |
||||
| 651 | * @return void |
||||
| 652 | */ |
||||
| 653 | protected function performMerge($source_url, $wc_path, array $revisions) |
||||
| 654 | { |
||||
| 655 | if ( $this->isReverseMerge() ) { |
||||
| 656 | rsort($revisions, SORT_NUMERIC); |
||||
| 657 | } |
||||
| 658 | else { |
||||
| 659 | sort($revisions, SORT_NUMERIC); |
||||
| 660 | } |
||||
| 661 | |||||
| 662 | $revision_count = count($revisions); |
||||
| 663 | |||||
| 664 | $used_revision_count = 0; |
||||
| 665 | $used_revisions = $this->repositoryConnector->getMergedRevisionChanges($wc_path, !$this->isReverseMerge()); |
||||
| 666 | |||||
| 667 | if ( $used_revisions ) { |
||||
| 668 | $used_revisions = call_user_func_array('array_merge', $used_revisions); |
||||
| 669 | $used_revision_count = count($used_revisions); |
||||
| 670 | $revision_count += $used_revision_count; |
||||
| 671 | } |
||||
| 672 | |||||
| 673 | $revision_log = $this->getRevisionLog($source_url); |
||||
| 674 | $revisions_data = $revision_log->getRevisionsData('summary', $revisions); |
||||
| 675 | |||||
| 676 | if ( strpos($this->accentStyle, 'options') !== false ) { |
||||
| 677 | $title_accent_style = $this->accentStyle . ',underscore'; |
||||
| 678 | } |
||||
| 679 | else { |
||||
| 680 | $title_accent_style = $this->accentStyle . ';options=underscore'; |
||||
| 681 | } |
||||
| 682 | |||||
| 683 | $revision_title_mask = $revision_log->getRevisionURLBuilder()->getMask($title_accent_style); |
||||
| 684 | |||||
| 685 | // Added " revision" text, when URL wasn't detected. |
||||
| 686 | if ( strpos($revision_title_mask, '://') === false ) { |
||||
| 687 | $revision_title_mask .= ' revision'; |
||||
| 688 | } |
||||
| 689 | |||||
| 690 | $merge_command_arguments = $this->getMergeCommandArguments($source_url, $wc_path); |
||||
| 691 | |||||
| 692 | foreach ( $revisions as $index => $revision ) { |
||||
| 693 | $command_arguments = str_replace('{revision}', $revision, $merge_command_arguments); |
||||
| 694 | $command = $this->repositoryConnector->getCommand('merge', $command_arguments); |
||||
| 695 | |||||
| 696 | $progress_bar = $this->createMergeProgressBar($used_revision_count + $index + 1, $revision_count); |
||||
| 697 | |||||
| 698 | // 1. Add revision link with a progress bar. |
||||
| 699 | $merge_heading = PHP_EOL . '<' . $this->accentStyle . '>'; |
||||
| 700 | $merge_heading .= '--- $1 ' . \str_replace('{revision}', $revision, $revision_title_mask); |
||||
| 701 | $merge_heading .= " into '$2' " . $progress_bar . ':</>'; |
||||
| 702 | |||||
| 703 | // 2. Add a commit message. |
||||
| 704 | $commit_message = trim($revisions_data[$revision]['msg']); |
||||
| 705 | $commit_message = wordwrap($commit_message, 68); // FIXME: Not UTF-8 safe solution. |
||||
| 706 | $merge_heading .= PHP_EOL . $commit_message; |
||||
| 707 | $merge_heading .= PHP_EOL; |
||||
| 708 | $merge_heading .= PHP_EOL . '<' . $this->accentStyle . '>Changed Paths:</>'; |
||||
| 709 | |||||
| 710 | $command->runLive(array( |
||||
| 711 | $wc_path => '.', |
||||
| 712 | '/--- (Merging|Reverse-merging) r' . $revision . " into '([^']*)':/" => $merge_heading, |
||||
| 713 | )); |
||||
| 714 | |||||
| 715 | $this->_usableRevisions = array_diff($this->_usableRevisions, array($revision)); |
||||
| 716 | $this->ensureWorkingCopyWithoutConflicts($source_url, $wc_path, $revision); |
||||
| 717 | } |
||||
| 718 | |||||
| 719 | $this->performCommit(); |
||||
| 720 | } |
||||
| 721 | |||||
| 722 | /** |
||||
| 723 | * Returns merge command arguments. |
||||
| 724 | * |
||||
| 725 | * @param string $source_url Merge source: url. |
||||
| 726 | * @param string $wc_path Merge target: working copy path. |
||||
| 727 | * |
||||
| 728 | * @return array |
||||
| 729 | */ |
||||
| 730 | protected function getMergeCommandArguments($source_url, $wc_path) |
||||
| 731 | { |
||||
| 732 | $ret = array( |
||||
| 733 | '-c', |
||||
| 734 | $this->isReverseMerge() ? '-{revision}' : '{revision}', |
||||
| 735 | ); |
||||
| 736 | |||||
| 737 | if ( $this->io->getOption('record-only') ) { |
||||
| 738 | $ret[] = '--record-only'; |
||||
| 739 | } |
||||
| 740 | |||||
| 741 | $ret[] = $source_url; |
||||
| 742 | $ret[] = $wc_path; |
||||
| 743 | |||||
| 744 | return $ret; |
||||
| 745 | } |
||||
| 746 | |||||
| 747 | /** |
||||
| 748 | * Create merge progress bar. |
||||
| 749 | * |
||||
| 750 | * @param integer $current Current. |
||||
| 751 | * @param integer $total Total. |
||||
| 752 | * |
||||
| 753 | * @return string |
||||
| 754 | */ |
||||
| 755 | protected function createMergeProgressBar($current, $total) |
||||
| 756 | { |
||||
| 757 | $total_length = 28; |
||||
| 758 | $percent_used = floor(($current / $total) * 100); |
||||
| 759 | $length_used = floor(($total_length * $percent_used) / 100); |
||||
| 760 | $length_free = $total_length - $length_used; |
||||
| 761 | |||||
| 762 | $ret = $length_used > 0 ? str_repeat('=', $length_used - 1) : ''; |
||||
|
0 ignored issues
–
show
$length_used - 1 of type double is incompatible with the type integer expected by parameter $times of str_repeat().
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 763 | $ret .= '>' . str_repeat('-', $length_free); |
||||
| 764 | |||||
| 765 | return '[' . $ret . '] ' . $percent_used . '% (' . $current . ' of ' . $total . ')'; |
||||
| 766 | } |
||||
| 767 | |||||
| 768 | /** |
||||
| 769 | * Ensures, that there are no unresolved conflicts in working copy. |
||||
| 770 | * |
||||
| 771 | * @param string $source_url Source url. |
||||
| 772 | * @param string $wc_path Working copy path. |
||||
| 773 | * @param integer $largest_suggested_revision Largest revision, that is suggested in error message. |
||||
| 774 | * |
||||
| 775 | * @return void |
||||
| 776 | * @throws CommandException When merge conflicts detected. |
||||
| 777 | */ |
||||
| 778 | protected function ensureWorkingCopyWithoutConflicts($source_url, $wc_path, $largest_suggested_revision = null) |
||||
| 779 | { |
||||
| 780 | $this->io->write(' * Previous Merge Status ... '); |
||||
| 781 | |||||
| 782 | $conflicts = $this->_workingCopyConflictTracker->getNewConflicts($wc_path); |
||||
| 783 | |||||
| 784 | if ( !$conflicts ) { |
||||
| 785 | $this->io->writeln('<info>Successful</info>'); |
||||
| 786 | |||||
| 787 | return; |
||||
| 788 | } |
||||
| 789 | |||||
| 790 | $this->_workingCopyConflictTracker->add($wc_path); |
||||
| 791 | $this->io->writeln('<error>' . count($conflicts) . ' conflict(-s)</error>'); |
||||
| 792 | |||||
| 793 | $table = new Table($this->io->getOutput()); |
||||
| 794 | |||||
| 795 | if ( $largest_suggested_revision ) { |
||||
|
0 ignored issues
–
show
The expression
$largest_suggested_revision of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For 0 == false // true
0 == null // true
123 == false // false
123 == null // false
// It is often better to use strict comparison
0 === false // false
0 === null // false
Loading history...
|
|||||
| 796 | $table->setHeaders(array( |
||||
| 797 | 'Path', |
||||
| 798 | 'Associated Revisions (before ' . $largest_suggested_revision . ')', |
||||
| 799 | )); |
||||
| 800 | } |
||||
| 801 | else { |
||||
| 802 | $table->setHeaders(array( |
||||
| 803 | 'Path', |
||||
| 804 | 'Associated Revisions', |
||||
| 805 | )); |
||||
| 806 | } |
||||
| 807 | |||||
| 808 | $revision_log = $this->getRevisionLog($source_url); |
||||
| 809 | $source_path = $this->repositoryConnector->getRelativePath($source_url) . '/'; |
||||
| 810 | |||||
| 811 | /** @var OutputHelper $output_helper */ |
||||
| 812 | $output_helper = $this->getHelper('output'); |
||||
| 813 | |||||
| 814 | foreach ( $conflicts as $conflict_path ) { |
||||
| 815 | $path_revisions = $revision_log->find('paths', $source_path . $conflict_path); |
||||
| 816 | $path_revisions = array_intersect($this->_usableRevisions, $path_revisions); |
||||
| 817 | |||||
| 818 | if ( $path_revisions && isset($largest_suggested_revision) ) { |
||||
|
0 ignored issues
–
show
The expression
$path_revisions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||||
| 819 | $path_revisions = $this->limitRevisions($path_revisions, $largest_suggested_revision); |
||||
| 820 | } |
||||
| 821 | |||||
| 822 | $table->addRow(array( |
||||
| 823 | $conflict_path, |
||||
| 824 | $path_revisions ? $output_helper->formatArray($path_revisions, 4) : '-', |
||||
| 825 | )); |
||||
| 826 | } |
||||
| 827 | |||||
| 828 | $table->render(); |
||||
| 829 | |||||
| 830 | throw new CommandException('Working copy contains unresolved merge conflicts.'); |
||||
| 831 | } |
||||
| 832 | |||||
| 833 | /** |
||||
| 834 | * Returns revisions not larger, then given one. |
||||
| 835 | * |
||||
| 836 | * @param array $revisions Revisions. |
||||
| 837 | * @param integer $max_revision Maximal revision. |
||||
| 838 | * |
||||
| 839 | * @return array |
||||
| 840 | */ |
||||
| 841 | protected function limitRevisions(array $revisions, $max_revision) |
||||
| 842 | { |
||||
| 843 | $ret = array(); |
||||
| 844 | |||||
| 845 | foreach ( $revisions as $revision ) { |
||||
| 846 | if ( $revision < $max_revision ) { |
||||
| 847 | $ret[] = $revision; |
||||
| 848 | } |
||||
| 849 | } |
||||
| 850 | |||||
| 851 | return $ret; |
||||
| 852 | } |
||||
| 853 | |||||
| 854 | /** |
||||
| 855 | * Performs commit unless user doesn't want it. |
||||
| 856 | * |
||||
| 857 | * @return boolean |
||||
| 858 | */ |
||||
| 859 | protected function performCommit() |
||||
| 860 | { |
||||
| 861 | $auto_commit = $this->io->getOption('auto-commit'); |
||||
| 862 | |||||
| 863 | if ( $auto_commit !== null ) { |
||||
| 864 | $auto_commit = $auto_commit === 'yes'; |
||||
| 865 | } |
||||
| 866 | else { |
||||
| 867 | $auto_commit = (boolean)$this->getSetting(self::SETTING_MERGE_AUTO_COMMIT); |
||||
| 868 | } |
||||
| 869 | |||||
| 870 | if ( $auto_commit ) { |
||||
| 871 | $auto_deploy = $this->io->getOption('auto-deploy'); |
||||
| 872 | |||||
| 873 | $commit_arguments = array( |
||||
| 874 | 'path' => $this->io->getArgument('path'), |
||||
| 875 | ); |
||||
| 876 | |||||
| 877 | if ( $auto_deploy !== null ) { |
||||
| 878 | $commit_arguments['--auto-deploy'] = $auto_deploy; |
||||
| 879 | } |
||||
| 880 | |||||
| 881 | $this->io->writeln(array('', 'Commencing automatic commit after merge ...')); |
||||
| 882 | $this->runOtherCommand('commit', $commit_arguments); |
||||
| 883 | } |
||||
| 884 | |||||
| 885 | return $auto_commit; |
||||
| 886 | } |
||||
| 887 | |||||
| 888 | /** |
||||
| 889 | * Prints revisions. |
||||
| 890 | * |
||||
| 891 | * @param string $source_url Merge source: url. |
||||
| 892 | * @param array $revisions Revisions. |
||||
| 893 | * |
||||
| 894 | * @return void |
||||
| 895 | */ |
||||
| 896 | protected function printRevisions($source_url, array $revisions) |
||||
| 897 | { |
||||
| 898 | $this->runOtherCommand('log', array( |
||||
| 899 | 'path' => $source_url, |
||||
| 900 | '--revisions' => implode(',', $revisions), |
||||
| 901 | '--merges' => $this->io->getOption('merges'), |
||||
| 902 | '--no-merges' => $this->io->getOption('no-merges'), |
||||
| 903 | '--with-full-message' => $this->io->getOption('with-full-message'), |
||||
| 904 | '--with-details' => $this->io->getOption('with-details'), |
||||
| 905 | '--with-summary' => $this->io->getOption('with-summary'), |
||||
| 906 | '--aggregate' => $this->io->getOption('aggregate'), |
||||
| 907 | '--with-merge-oracle' => true, |
||||
| 908 | )); |
||||
| 909 | } |
||||
| 910 | |||||
| 911 | /** |
||||
| 912 | * Returns list of config settings. |
||||
| 913 | * |
||||
| 914 | * @return AbstractConfigSetting[] |
||||
| 915 | */ |
||||
| 916 | public function getConfigSettings() |
||||
| 917 | { |
||||
| 918 | return array( |
||||
| 919 | new StringConfigSetting(self::SETTING_MERGE_SOURCE_URL, ''), |
||||
| 920 | new ArrayConfigSetting(self::SETTING_MERGE_RECENT_CONFLICTS, array()), |
||||
| 921 | new ChoiceConfigSetting( |
||||
| 922 | self::SETTING_MERGE_AUTO_COMMIT, |
||||
| 923 | array(1 => 'Yes', 0 => 'No'), |
||||
| 924 | 1 |
||||
| 925 | ), |
||||
| 926 | ); |
||||
| 927 | } |
||||
| 928 | |||||
| 929 | /** |
||||
| 930 | * Returns option names, that makes sense to use in aggregation mode. |
||||
| 931 | * |
||||
| 932 | * @return array |
||||
| 933 | */ |
||||
| 934 | public function getAggregatedOptions() |
||||
| 935 | { |
||||
| 936 | return array('with-full-message', 'with-details', 'with-summary'); |
||||
| 937 | } |
||||
| 938 | |||||
| 939 | /** |
||||
| 940 | * Determines if merge should be done in opposite direction (unmerge). |
||||
| 941 | * |
||||
| 942 | * @return boolean |
||||
| 943 | */ |
||||
| 944 | protected function isReverseMerge() |
||||
| 945 | { |
||||
| 946 | return $this->io->getOption('reverse'); |
||||
|
0 ignored issues
–
show
|
|||||
| 947 | } |
||||
| 948 | |||||
| 949 | } |
||||
| 950 |