@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fix git "origin" remote in more circumstances

Summary:
Fixes T4041. We currently detect when "origin" is incorrect, but can do better:

- When "origin" is missing, we can add it. This happens for Git 1.7.1 -- see T4041.
- When "origin" is wrong, we can fix it automatically if we control the repository.

We only need to fail when origin exists, is wrong, and we aren't in charge of the repository.

Test Plan: Ran `bin/repository discover X` on a repository with a good origin, no origin, a bad-but-under-control origin, and a bad-out-of-control origin. Got the right behavior in all cases.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran, champo

Maniphest Tasks: T4041

Differential Revision: https://secure.phabricator.com/D7614

+105 -45
+87 -22
src/applications/repository/daemon/PhabricatorRepositoryPullLocalDaemon.php
··· 535 535 PhabricatorRepository $repository) { 536 536 537 537 if (!$repository->isHosted()) { 538 - list($remotes) = $repository->execxLocalCommand( 539 - 'remote show -n origin'); 540 - 541 - $matches = null; 542 - if (!preg_match('/^\s*Fetch URL:\s*(.*?)\s*$/m', $remotes, $matches)) { 543 - throw new Exception( 544 - "Expected 'Fetch URL' in 'git remote show -n origin'."); 545 - } 546 - 547 - self::executeGitVerifySameOrigin( 548 - $matches[1], 549 - $repository->getRemoteURI(), 550 - $repository->getLocalPath()); 538 + $this->verifyOrigin($repository); 551 539 } 552 540 553 541 $refs = id(new DiffusionLowLevelGitRefQuery()) ··· 691 679 692 680 693 681 /** 682 + * Verify that the "origin" remote exists, and points at the correct URI. 683 + * 684 + * This catches or corrects some types of misconfiguration, and also repairs 685 + * an issue where Git 1.7.1 does not create an "origin" for `--bare` clones. 686 + * See T4041. 687 + * 688 + * @param PhabricatorRepository Repository to verify. 689 + * @return void 690 + */ 691 + private function verifyOrigin(PhabricatorRepository $repository) { 692 + list($remotes) = $repository->execxLocalCommand( 693 + 'remote show -n origin'); 694 + 695 + $matches = null; 696 + if (!preg_match('/^\s*Fetch URL:\s*(.*?)\s*$/m', $remotes, $matches)) { 697 + throw new Exception( 698 + "Expected 'Fetch URL' in 'git remote show -n origin'."); 699 + } 700 + 701 + $remote_uri = $matches[1]; 702 + $expect_remote = $repository->getRemoteURI(); 703 + 704 + if ($remote_uri == "origin") { 705 + // If a remote does not exist, git pretends it does and prints out a 706 + // made up remote where the URI is the same as the remote name. This is 707 + // definitely not correct. 708 + 709 + // Possibly, we should use `git remote --verbose` instead, which does not 710 + // suffer from this problem (but is a little more complicated to parse). 711 + $valid = false; 712 + $exists = false; 713 + } else { 714 + $valid = self::isSameGitOrigin($remote_uri, $expect_remote); 715 + $exists = true; 716 + } 717 + 718 + if (!$valid) { 719 + if (!$exists) { 720 + // If there's no "origin" remote, just create it regardless of how 721 + // strongly we own the working copy. There is almost no conceivable 722 + // scenario in which this could do damage. 723 + $this->log( 724 + pht( 725 + 'Remote "origin" does not exist. Creating "origin", with '. 726 + 'URI "%s".', 727 + $expect_remote)); 728 + $repository->execxLocalCommand( 729 + 'remote add origin %s', 730 + $expect_remote); 731 + 732 + // NOTE: This doesn't fetch the origin (it just creates it), so we won't 733 + // know about origin branches until the next "pull" happens. That's fine 734 + // for our purposes, but might impact things in the future. 735 + } else { 736 + if ($repository->canDestroyWorkingCopy()) { 737 + // Bad remote, but we can try to repair it. 738 + $this->log( 739 + pht( 740 + 'Remote "origin" exists, but is pointed at the wrong URI, "%s". '. 741 + 'Resetting origin URI to "%s.', 742 + $remote_uri, 743 + $expect_remote)); 744 + $repository->execxLocalCommand( 745 + 'remote set-url origin %s', 746 + $expect_remote); 747 + } else { 748 + // Bad remote and we aren't comfortable repairing it. 749 + $message = pht( 750 + 'Working copy at "%s" has a mismatched origin URI, "%s". '. 751 + 'The expected origin URI is "%s". Fix your configuration, or '. 752 + 'set the remote URI correctly. To avoid breaking anything, '. 753 + 'Phabricator will not automatically fix this.', 754 + $repository->getLocalPath(), 755 + $remote_uri, 756 + $expect_remote); 757 + throw new Exception($message); 758 + } 759 + } 760 + } 761 + } 762 + 763 + 764 + 765 + /** 694 766 * @task git 695 767 */ 696 - public static function executeGitVerifySameOrigin($remote, $expect, $where) { 768 + public static function isSameGitOrigin($remote, $expect) { 697 769 $remote_path = self::getPathFromGitURI($remote); 698 770 $expect_path = self::getPathFromGitURI($expect); 699 771 700 772 $remote_match = self::executeGitNormalizePath($remote_path); 701 773 $expect_match = self::executeGitNormalizePath($expect_path); 702 774 703 - if ($remote_match != $expect_match) { 704 - throw new Exception( 705 - "Working copy at '{$where}' has a mismatched origin URL. It has ". 706 - "origin URL '{$remote}' (with remote path '{$remote_path}'), but the ". 707 - "configured URL '{$expect}' (with remote path '{$expect_path}') is ". 708 - "expected. Refusing to proceed because this may indicate that the ". 709 - "working copy is actually some other repository."); 710 - } 775 + return ($remote_match == $expect_match); 711 776 } 712 777 713 778 private static function getPathFromGitURI($raw_uri) {
+2 -12
src/applications/repository/engine/PhabricatorRepositoryPullEngine.php
··· 231 231 } 232 232 } 233 233 234 - if ($err && $this->canDestroyWorkingCopy($path)) { 234 + if ($err && $repository->canDestroyWorkingCopy()) { 235 235 phlog("Repository working copy at '{$path}' failed sanity check; ". 236 236 "destroying and re-cloning. {$message}"); 237 237 Filesystem::remove($path); ··· 256 256 $future->setCWD($path); 257 257 list($err, $stdout, $stderr) = $future->resolve(); 258 258 259 - if ($err && !$retry && $this->canDestroyWorkingCopy($path)) { 259 + if ($err && !$retry && $repository->canDestroyWorkingCopy()) { 260 260 $retry = true; 261 261 // Fix remote origin url if it doesn't match our configuration 262 262 $origin_url = $repository->execLocalCommand( ··· 355 355 356 356 $path = rtrim($repository->getLocalPath(), '/'); 357 357 execx('svnadmin create -- %s', $path); 358 - } 359 - 360 - 361 - /* -( Internals )---------------------------------------------------------- */ 362 - 363 - 364 - private function canDestroyWorkingCopy($path) { 365 - $default_path = PhabricatorEnv::getEnvConfig( 366 - 'repository.default-local-path'); 367 - return Filesystem::isDescendant($path, $default_path); 368 358 } 369 359 370 360 }
+4 -11
src/applications/repository/engine/__tests__/PhabricatorWorkingCopyDiscoveryTestCase.php
··· 97 97 foreach ($cases as $case) { 98 98 list($remote, $config, $expect, $message) = $case; 99 99 100 - $ex = null; 101 - try { 102 - PhabricatorRepositoryPullLocalDaemon::executeGitverifySameOrigin( 100 + $this->assertEqual( 101 + $expect, 102 + PhabricatorRepositoryPullLocalDaemon::isSameGitOrigin( 103 103 $remote, 104 104 $config, 105 - '(a test case)'); 106 - } catch (Exception $exception) { 107 - $ex = $exception; 108 - } 109 - 110 - $this->assertEqual( 111 - $expect, 112 - !$ex, 105 + '(a test case)'), 113 106 "Verification that '{$remote}' and '{$config}' are the same origin ". 114 107 "had a different outcome than expected: {$message}"); 115 108 }
+12
src/applications/repository/storage/PhabricatorRepository.php
··· 898 898 } 899 899 } 900 900 901 + public function canDestroyWorkingCopy() { 902 + if ($this->isHosted()) { 903 + // Never destroy hosted working copies. 904 + return false; 905 + } 906 + 907 + $default_path = PhabricatorEnv::getEnvConfig( 908 + 'repository.default-local-path'); 909 + return Filesystem::isDescendant($this->getLocalPath(), $default_path); 910 + } 911 + 912 + 901 913 public function writeStatusMessage( 902 914 $status_type, 903 915 $status_code,