diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index aea1adb006..115c47ff68 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -388,6 +388,7 @@ phutil_register_library_map(array( 'DifferentialLandingActionMenuEventListener' => 'applications/differential/landing/DifferentialLandingActionMenuEventListener.php', 'DifferentialLandingStrategy' => 'applications/differential/landing/DifferentialLandingStrategy.php', 'DifferentialLandingToHostedGit' => 'applications/differential/landing/DifferentialLandingToHostedGit.php', + 'DifferentialLandingToHostedMercurial' => 'applications/differential/landing/DifferentialLandingToHostedMercurial.php', 'DifferentialLinesFieldSpecification' => 'applications/differential/field/specification/DifferentialLinesFieldSpecification.php', 'DifferentialLintFieldSpecification' => 'applications/differential/field/specification/DifferentialLintFieldSpecification.php', 'DifferentialLintStatus' => 'applications/differential/constants/DifferentialLintStatus.php', @@ -2647,6 +2648,7 @@ phutil_register_library_map(array( 'DifferentialJIRAIssuesFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialLandingActionMenuEventListener' => 'PhabricatorEventListener', 'DifferentialLandingToHostedGit' => 'DifferentialLandingStrategy', + 'DifferentialLandingToHostedMercurial' => 'DifferentialLandingStrategy', 'DifferentialLinesFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialLintFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialLocalCommitsView' => 'AphrontView', diff --git a/src/applications/differential/DifferentialGetWorkingCopy.php b/src/applications/differential/DifferentialGetWorkingCopy.php index 01641261d2..6118aebe10 100644 --- a/src/applications/differential/DifferentialGetWorkingCopy.php +++ b/src/applications/differential/DifferentialGetWorkingCopy.php @@ -36,4 +36,32 @@ final class DifferentialGetWorkingCopy { return $workspace; } + /** + * Creates and/or cleans a workspace for the requested repo. + * + * return ArcanistMercurialAPI + */ + public static function getCleanMercurialWorkspace( + PhabricatorRepository $repo) { + + $origin_path = $repo->getLocalPath(); + + $path = rtrim($origin_path, '/'); + $path = $path . '__workspace'; + + if (!Filesystem::pathExists($path)) { + $repo->execxLocalCommand( + 'clone -- file://%s %s', + $origin_path, + $path); + } + + $workspace = new ArcanistMercurialAPI($path); + $workspace->execxLocal('pull'); + $workspace->execxLocal('update --clean default'); + $workspace->reloadWorkingCopy(); + + return $workspace; + } + } diff --git a/src/applications/differential/controller/DifferentialRevisionLandController.php b/src/applications/differential/controller/DifferentialRevisionLandController.php index 003c4900ac..fad8b48e07 100644 --- a/src/applications/differential/controller/DifferentialRevisionLandController.php +++ b/src/applications/differential/controller/DifferentialRevisionLandController.php @@ -68,7 +68,7 @@ final class DifferentialRevisionLandController extends DifferentialController { $prompt = hsprintf('%s

%s', pht( 'This will squash and rebase revision %s, and push it to '. - 'origin/master.', + 'the default / master branch.', $revision_id), pht('It is an experimental feature and may not work.')); diff --git a/src/applications/differential/landing/DifferentialLandingStrategy.php b/src/applications/differential/landing/DifferentialLandingStrategy.php index 46a0f74333..0c7efad5f0 100644 --- a/src/applications/differential/landing/DifferentialLandingStrategy.php +++ b/src/applications/differential/landing/DifferentialLandingStrategy.php @@ -35,7 +35,21 @@ abstract class DifferentialLandingStrategy { try { return DifferentialGetWorkingCopy::getCleanGitWorkspace($repository); } catch (Exception $e) { - throw new PhutilProxyException ( + throw new PhutilProxyException( + 'Failed to allocate a workspace', + $e); + } + } + + /** + * might break if repository is not Mercurial. + */ + protected function getMercurialWorkspace(PhabricatorRepository $repository) { + try { + return DifferentialGetWorkingCopy::getCleanMercurialWorkspace( + $repository); + } catch (Exception $e) { + throw new PhutilProxyException( 'Failed to allocate a workspace', $e); } diff --git a/src/applications/differential/landing/DifferentialLandingToHostedMercurial.php b/src/applications/differential/landing/DifferentialLandingToHostedMercurial.php new file mode 100644 index 0000000000..fd533aaf8b --- /dev/null +++ b/src/applications/differential/landing/DifferentialLandingToHostedMercurial.php @@ -0,0 +1,120 @@ +getUser(); + + $workspace = $this->getMercurialWorkspace($repository); + + try { + $this->commitRevisionToWorkspace( + $revision, + $workspace, + $viewer); + } catch (Exception $e) { + throw new PhutilProxyException( + 'Failed to commit patch', + $e); + } + + try { + $this->pushWorkspaceRepository( + $repository, + $workspace, + $viewer); + } catch (Exception $e) { + throw new PhutilProxyException( + 'Failed to push changes upstream', + $e); + } + } + + public function commitRevisionToWorkspace( + DifferentialRevision $revision, + ArcanistRepositoryAPI $workspace, + PhabricatorUser $user) { + + $diff_id = $revision->loadActiveDiff()->getID(); + + $call = new ConduitCall( + 'differential.getrawdiff', + array( + 'diffID' => $diff_id, + )); + + $call->setUser($user); + $raw_diff = $call->execute(); + + $future = $workspace->execFutureLocal('patch --no-commit -'); + $future->write($raw_diff); + $future->resolvex(); + + $workspace->reloadWorkingCopy(); + + $call = new ConduitCall( + 'differential.getcommitmessage', + array( + 'revision_id' => $revision->getID(), + )); + + $call->setUser($user); + $message = $call->execute(); + + $author = id(new PhabricatorUser())->loadOneWhere( + 'phid = %s', + $revision->getAuthorPHID()); + + $author_string = sprintf( + '%s <%s>', + $author->getRealName(), + $author->loadPrimaryEmailAddress()); + $author_date = $revision->getDateCreated(); + + $workspace->execxLocal( + 'commit --date=%s --user=%s '. + '--message=%s', + $author_date.' 0', + $author_string, + $message); + } + + + public function pushWorkspaceRepository( + PhabricatorRepository $repository, + ArcanistRepositoryAPI $workspace, + PhabricatorUser $user) { + + $workspace->execxLocal("push -b default"); + } + + public function createMenuItems( + PhabricatorUser $viewer, + DifferentialRevision $revision, + PhabricatorRepository $repository) { + + $vcs = $repository->getVersionControlSystem(); + if ($vcs !== PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL) { + return; + } + + if (!$repository->isHosted()) { + return; + } + + $can_push = PhabricatorPolicyFilter::hasCapability( + $viewer, + $repository, + DiffusionCapabilityPush::CAPABILITY); + + return $this->createActionView( + $revision, + pht('Land to Hosted Repository'), + !$can_push); + } +}