mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-26 16:52:41 +01:00
Remove old "Landing Strategy" code
Summary: Fixes T12869. This is a very old, pre-Drydock chunk of code from D7486 and some followups. It does three things: - "Land to Hosted Git": Obsoleted by Drydock, has been commented out in HEAD for a very long time with no complaints. Disabled by D8719 in 2014. - "Land to Hosted Mercurial": Could be obsoleted by Drydock with a fairly small amount of work, but currently has no replacement. Unclear if this sees any real use. Not actually disabled at HEAD. - "Land to GitHub": Use GitHub OAuth credentials to land to GitHub. This is sort of theoretically useful and has no analog today. Disabled by D13022 in 2015. This stuff was largely disabled a long time ago and we haven't seen users hitting issues with it. This could all be moved to an extension today if anyone still relies on it. Test Plan: Grepped for removed classes, browsed Differential. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12869 Differential Revision: https://secure.phabricator.com/D18150
This commit is contained in:
parent
58df1b7d3b
commit
219ae8b6c9
8 changed files with 0 additions and 764 deletions
|
@ -453,13 +453,10 @@ phutil_register_library_map(array(
|
|||
'DifferentialGetRevisionCommentsConduitAPIMethod' => 'applications/differential/conduit/DifferentialGetRevisionCommentsConduitAPIMethod.php',
|
||||
'DifferentialGetRevisionConduitAPIMethod' => 'applications/differential/conduit/DifferentialGetRevisionConduitAPIMethod.php',
|
||||
'DifferentialGetWorkingCopy' => 'applications/differential/DifferentialGetWorkingCopy.php',
|
||||
'DifferentialGitHubLandingStrategy' => 'applications/differential/landing/DifferentialGitHubLandingStrategy.php',
|
||||
'DifferentialGitSVNIDCommitMessageField' => 'applications/differential/field/DifferentialGitSVNIDCommitMessageField.php',
|
||||
'DifferentialHarbormasterField' => 'applications/differential/customfield/DifferentialHarbormasterField.php',
|
||||
'DifferentialHiddenComment' => 'applications/differential/storage/DifferentialHiddenComment.php',
|
||||
'DifferentialHostField' => 'applications/differential/customfield/DifferentialHostField.php',
|
||||
'DifferentialHostedGitLandingStrategy' => 'applications/differential/landing/DifferentialHostedGitLandingStrategy.php',
|
||||
'DifferentialHostedMercurialLandingStrategy' => 'applications/differential/landing/DifferentialHostedMercurialLandingStrategy.php',
|
||||
'DifferentialHovercardEngineExtension' => 'applications/differential/engineextension/DifferentialHovercardEngineExtension.php',
|
||||
'DifferentialHunk' => 'applications/differential/storage/DifferentialHunk.php',
|
||||
'DifferentialHunkParser' => 'applications/differential/parser/DifferentialHunkParser.php',
|
||||
|
@ -472,8 +469,6 @@ phutil_register_library_map(array(
|
|||
'DifferentialInlineCommentQuery' => 'applications/differential/query/DifferentialInlineCommentQuery.php',
|
||||
'DifferentialJIRAIssuesCommitMessageField' => 'applications/differential/field/DifferentialJIRAIssuesCommitMessageField.php',
|
||||
'DifferentialJIRAIssuesField' => 'applications/differential/customfield/DifferentialJIRAIssuesField.php',
|
||||
'DifferentialLandingActionMenuEventListener' => 'applications/differential/landing/DifferentialLandingActionMenuEventListener.php',
|
||||
'DifferentialLandingStrategy' => 'applications/differential/landing/DifferentialLandingStrategy.php',
|
||||
'DifferentialLegacyHunk' => 'applications/differential/storage/DifferentialLegacyHunk.php',
|
||||
'DifferentialLineAdjustmentMap' => 'applications/differential/parser/DifferentialLineAdjustmentMap.php',
|
||||
'DifferentialLintField' => 'applications/differential/customfield/DifferentialLintField.php',
|
||||
|
@ -548,7 +543,6 @@ phutil_register_library_map(array(
|
|||
'DifferentialRevisionHeraldFieldGroup' => 'applications/differential/herald/DifferentialRevisionHeraldFieldGroup.php',
|
||||
'DifferentialRevisionIDCommitMessageField' => 'applications/differential/field/DifferentialRevisionIDCommitMessageField.php',
|
||||
'DifferentialRevisionInlinesController' => 'applications/differential/controller/DifferentialRevisionInlinesController.php',
|
||||
'DifferentialRevisionLandController' => 'applications/differential/controller/DifferentialRevisionLandController.php',
|
||||
'DifferentialRevisionListController' => 'applications/differential/controller/DifferentialRevisionListController.php',
|
||||
'DifferentialRevisionListView' => 'applications/differential/view/DifferentialRevisionListView.php',
|
||||
'DifferentialRevisionMailReceiver' => 'applications/differential/mail/DifferentialRevisionMailReceiver.php',
|
||||
|
@ -5411,13 +5405,10 @@ phutil_register_library_map(array(
|
|||
'DifferentialGetRevisionCommentsConduitAPIMethod' => 'DifferentialConduitAPIMethod',
|
||||
'DifferentialGetRevisionConduitAPIMethod' => 'DifferentialConduitAPIMethod',
|
||||
'DifferentialGetWorkingCopy' => 'Phobject',
|
||||
'DifferentialGitHubLandingStrategy' => 'DifferentialLandingStrategy',
|
||||
'DifferentialGitSVNIDCommitMessageField' => 'DifferentialCommitMessageField',
|
||||
'DifferentialHarbormasterField' => 'DifferentialCustomField',
|
||||
'DifferentialHiddenComment' => 'DifferentialDAO',
|
||||
'DifferentialHostField' => 'DifferentialCustomField',
|
||||
'DifferentialHostedGitLandingStrategy' => 'DifferentialLandingStrategy',
|
||||
'DifferentialHostedMercurialLandingStrategy' => 'DifferentialLandingStrategy',
|
||||
'DifferentialHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension',
|
||||
'DifferentialHunk' => array(
|
||||
'DifferentialDAO',
|
||||
|
@ -5436,8 +5427,6 @@ phutil_register_library_map(array(
|
|||
'DifferentialInlineCommentQuery' => 'PhabricatorOffsetPagedQuery',
|
||||
'DifferentialJIRAIssuesCommitMessageField' => 'DifferentialCommitMessageCustomField',
|
||||
'DifferentialJIRAIssuesField' => 'DifferentialStoredCustomField',
|
||||
'DifferentialLandingActionMenuEventListener' => 'PhabricatorEventListener',
|
||||
'DifferentialLandingStrategy' => 'Phobject',
|
||||
'DifferentialLegacyHunk' => 'DifferentialHunk',
|
||||
'DifferentialLineAdjustmentMap' => 'Phobject',
|
||||
'DifferentialLintField' => 'DifferentialHarbormasterField',
|
||||
|
@ -5529,7 +5518,6 @@ phutil_register_library_map(array(
|
|||
'DifferentialRevisionHeraldFieldGroup' => 'HeraldFieldGroup',
|
||||
'DifferentialRevisionIDCommitMessageField' => 'DifferentialCommitMessageField',
|
||||
'DifferentialRevisionInlinesController' => 'DifferentialController',
|
||||
'DifferentialRevisionLandController' => 'DifferentialController',
|
||||
'DifferentialRevisionListController' => 'DifferentialController',
|
||||
'DifferentialRevisionListView' => 'AphrontView',
|
||||
'DifferentialRevisionMailReceiver' => 'PhabricatorObjectMailReceiver',
|
||||
|
|
|
@ -41,12 +41,6 @@ final class PhabricatorDifferentialApplication extends PhabricatorApplication {
|
|||
return "\xE2\x9A\x99";
|
||||
}
|
||||
|
||||
public function getEventListeners() {
|
||||
return array(
|
||||
new DifferentialLandingActionMenuEventListener(),
|
||||
);
|
||||
}
|
||||
|
||||
public function getOverview() {
|
||||
return pht(
|
||||
'Differential is a **code review application** which allows '.
|
||||
|
@ -69,8 +63,6 @@ final class PhabricatorDifferentialApplication extends PhabricatorApplication {
|
|||
=> 'DifferentialRevisionEditController',
|
||||
$this->getEditRoutePattern('attach/(?P<diffID>[^/]+)/to/')
|
||||
=> 'DifferentialRevisionEditController',
|
||||
'land/(?:(?P<id>[1-9]\d*))/(?P<strategy>[^/]+)/'
|
||||
=> 'DifferentialRevisionLandController',
|
||||
'closedetails/(?P<phid>[^/]+)/'
|
||||
=> 'DifferentialRevisionCloseDetailsController',
|
||||
'update/(?P<revisionID>[1-9]\d*)/'
|
||||
|
|
|
@ -1,157 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class DifferentialRevisionLandController extends DifferentialController {
|
||||
|
||||
private $pushStrategy;
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $this->getViewer();
|
||||
$revision_id = $request->getURIData('id');
|
||||
$strategy_class = $request->getURIData('strategy');
|
||||
|
||||
$revision = id(new DifferentialRevisionQuery())
|
||||
->withIDs(array($revision_id))
|
||||
->setViewer($viewer)
|
||||
->executeOne();
|
||||
if (!$revision) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
if (is_subclass_of($strategy_class, 'DifferentialLandingStrategy')) {
|
||||
$this->pushStrategy = newv($strategy_class, array());
|
||||
} else {
|
||||
throw new Exception(
|
||||
pht(
|
||||
"Strategy type must be a valid class name and must subclass ".
|
||||
"%s. '%s' is not a subclass of %s",
|
||||
'DifferentialLandingStrategy',
|
||||
$strategy_class,
|
||||
'DifferentialLandingStrategy'));
|
||||
}
|
||||
|
||||
if ($request->isDialogFormPost()) {
|
||||
$response = null;
|
||||
$text = '';
|
||||
try {
|
||||
$response = $this->attemptLand($revision, $request);
|
||||
$title = pht('Success!');
|
||||
$text = pht('Revision was successfully landed.');
|
||||
} catch (Exception $ex) {
|
||||
$title = pht('Failed to land revision');
|
||||
if ($ex instanceof PhutilProxyException) {
|
||||
$text = hsprintf(
|
||||
'%s:<br><pre>%s</pre>',
|
||||
$ex->getMessage(),
|
||||
$ex->getPreviousException()->getMessage());
|
||||
} else {
|
||||
$text = phutil_tag('pre', array(), $ex->getMessage());
|
||||
}
|
||||
$text = id(new PHUIInfoView())
|
||||
->appendChild($text);
|
||||
}
|
||||
|
||||
if ($response instanceof AphrontDialogView) {
|
||||
$dialog = $response;
|
||||
} else {
|
||||
$dialog = id(new AphrontDialogView())
|
||||
->setUser($viewer)
|
||||
->setTitle($title)
|
||||
->appendChild(phutil_tag('p', array(), $text))
|
||||
->addCancelButton('/D'.$revision_id, pht('Done'));
|
||||
}
|
||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||
}
|
||||
|
||||
$is_disabled = $this->pushStrategy->isActionDisabled(
|
||||
$viewer,
|
||||
$revision,
|
||||
$revision->getRepository());
|
||||
if ($is_disabled) {
|
||||
if (is_string($is_disabled)) {
|
||||
$explain = $is_disabled;
|
||||
} else {
|
||||
$explain = pht('This action is not currently enabled.');
|
||||
}
|
||||
$dialog = id(new AphrontDialogView())
|
||||
->setUser($viewer)
|
||||
->setTitle(pht("Can't land revision"))
|
||||
->appendChild($explain)
|
||||
->addCancelButton('/D'.$revision_id);
|
||||
|
||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||
}
|
||||
|
||||
|
||||
$prompt = hsprintf('%s<br><br>%s',
|
||||
pht(
|
||||
'This will squash and rebase revision %s, and push it to '.
|
||||
'the default / master branch.',
|
||||
$revision_id),
|
||||
pht('It is an experimental feature and may not work.'));
|
||||
|
||||
$dialog = id(new AphrontDialogView())
|
||||
->setUser($viewer)
|
||||
->setTitle(pht('Land Revision %s?', $revision_id))
|
||||
->appendChild($prompt)
|
||||
->setSubmitURI($request->getRequestURI())
|
||||
->addSubmitButton(pht('Land it!'))
|
||||
->addCancelButton('/D'.$revision_id);
|
||||
|
||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||
}
|
||||
|
||||
private function attemptLand($revision, $request) {
|
||||
$status = $revision->getStatus();
|
||||
if ($status != ArcanistDifferentialRevisionStatus::ACCEPTED) {
|
||||
throw new Exception(pht('Only Accepted revisions can be landed.'));
|
||||
}
|
||||
|
||||
$repository = $revision->getRepository();
|
||||
|
||||
if ($repository === null) {
|
||||
throw new Exception(pht('Revision is not attached to a repository.'));
|
||||
}
|
||||
|
||||
$can_push = PhabricatorPolicyFilter::hasCapability(
|
||||
$request->getUser(),
|
||||
$repository,
|
||||
DiffusionPushCapability::CAPABILITY);
|
||||
|
||||
if (!$can_push) {
|
||||
throw new Exception(
|
||||
pht('You do not have permission to push to this repository.'));
|
||||
}
|
||||
|
||||
$lock = $this->lockRepository($repository);
|
||||
|
||||
try {
|
||||
$response = $this->pushStrategy->processLandRequest(
|
||||
$request,
|
||||
$revision,
|
||||
$repository);
|
||||
} catch (Exception $e) {
|
||||
$lock->unlock();
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$lock->unlock();
|
||||
|
||||
$looksoon = new ConduitCall(
|
||||
'diffusion.looksoon',
|
||||
array(
|
||||
'repositories' => array($repository->getPHID()),
|
||||
));
|
||||
$looksoon->setUser($request->getUser());
|
||||
$looksoon->execute();
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function lockRepository($repository) {
|
||||
$lock_name = __CLASS__.':'.($repository->getPHID());
|
||||
$lock = PhabricatorGlobalLock::newLock($lock_name);
|
||||
$lock->lock();
|
||||
return $lock;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,186 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class DifferentialGitHubLandingStrategy
|
||||
extends DifferentialLandingStrategy {
|
||||
|
||||
private $account;
|
||||
private $provider;
|
||||
|
||||
public function processLandRequest(
|
||||
AphrontRequest $request,
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorRepository $repository) {
|
||||
|
||||
$viewer = $request->getUser();
|
||||
$this->init($viewer, $repository);
|
||||
|
||||
$workspace = $this->getGitWorkspace($repository);
|
||||
|
||||
try {
|
||||
id(new DifferentialHostedGitLandingStrategy())
|
||||
->commitRevisionToWorkspace($revision, $workspace, $viewer);
|
||||
} catch (Exception $e) {
|
||||
throw new PhutilProxyException(pht('Failed to commit patch.'), $e);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->pushWorkspaceRepository($repository, $workspace);
|
||||
} catch (Exception $e) {
|
||||
// If it's a permission problem, we know more than git.
|
||||
$dialog = $this->verifyRemotePermissions($viewer, $revision, $repository);
|
||||
if ($dialog) {
|
||||
return $dialog;
|
||||
}
|
||||
|
||||
// Else, throw what git said.
|
||||
throw new PhutilProxyException(
|
||||
pht('Failed to push changes upstream.'),
|
||||
$e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns PhabricatorActionView or an array of PhabricatorActionView or null.
|
||||
*/
|
||||
public function createMenuItem(
|
||||
PhabricatorUser $viewer,
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorRepository $repository) {
|
||||
|
||||
// TODO: This temporarily disables this action, because it doesn't work
|
||||
// and is confusing to users. If you want to use it, comment out this line
|
||||
// for now and we'll provide real support eventually.
|
||||
return;
|
||||
|
||||
$vcs = $repository->getVersionControlSystem();
|
||||
if ($vcs !== PhabricatorRepositoryType::REPOSITORY_TYPE_GIT) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($repository->isHosted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// These throw when failing.
|
||||
$this->init($viewer, $repository);
|
||||
$this->findGitHubRepo($repository);
|
||||
} catch (Exception $e) {
|
||||
return;
|
||||
}
|
||||
|
||||
return $this->createActionView($revision, pht('Land to GitHub'))
|
||||
->setIcon('fa-cloud-upload');
|
||||
}
|
||||
|
||||
public function pushWorkspaceRepository(
|
||||
PhabricatorRepository $repository,
|
||||
ArcanistRepositoryAPI $workspace) {
|
||||
|
||||
$token = $this->getAccessToken();
|
||||
|
||||
$github_repo = $this->findGitHubRepo($repository);
|
||||
|
||||
$remote = urisprintf(
|
||||
'https://%s:x-oauth-basic@%s/%s.git',
|
||||
$token,
|
||||
$this->provider->getProviderDomain(),
|
||||
$github_repo);
|
||||
|
||||
$workspace->execxLocal(
|
||||
'push %P HEAD:master',
|
||||
new PhutilOpaqueEnvelope($remote));
|
||||
}
|
||||
|
||||
private function init($viewer, $repository) {
|
||||
$repo_uri = $repository->getRemoteURIObject();
|
||||
$repo_domain = $repo_uri->getDomain();
|
||||
|
||||
$this->account = id(new PhabricatorExternalAccountQuery())
|
||||
->setViewer($viewer)
|
||||
->withUserPHIDs(array($viewer->getPHID()))
|
||||
->withAccountTypes(array('github'))
|
||||
->withAccountDomains(array($repo_domain))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
|
||||
if (!$this->account) {
|
||||
throw new Exception(
|
||||
pht('No matching GitHub account found for %s.', $repo_domain));
|
||||
}
|
||||
|
||||
$this->provider = PhabricatorAuthProvider::getEnabledProviderByKey(
|
||||
$this->account->getProviderKey());
|
||||
if (!$this->provider) {
|
||||
throw new Exception(
|
||||
pht('GitHub provider for %s is not enabled.', $repo_domain));
|
||||
}
|
||||
}
|
||||
|
||||
private function findGitHubRepo(PhabricatorRepository $repository) {
|
||||
$repo_uri = $repository->getRemoteURIObject();
|
||||
|
||||
$repo_path = $repo_uri->getPath();
|
||||
|
||||
if (substr($repo_path, -4) == '.git') {
|
||||
$repo_path = substr($repo_path, 0, -4);
|
||||
}
|
||||
$repo_path = ltrim($repo_path, '/');
|
||||
|
||||
return $repo_path;
|
||||
}
|
||||
|
||||
private function getAccessToken() {
|
||||
return $this->provider->getOAuthAccessToken($this->account);
|
||||
}
|
||||
|
||||
private function verifyRemotePermissions($viewer, $revision, $repository) {
|
||||
$github_user = $this->account->getUsername();
|
||||
$github_repo = $this->findGitHubRepo($repository);
|
||||
|
||||
$uri = urisprintf(
|
||||
'https://api.github.com/repos/%s/collaborators/%s',
|
||||
$github_repo,
|
||||
$github_user);
|
||||
|
||||
$uri = new PhutilURI($uri);
|
||||
$uri->setQueryParam('access_token', $this->getAccessToken());
|
||||
list($status, $body, $headers) = id(new HTTPSFuture($uri))->resolve();
|
||||
|
||||
// Likely status codes:
|
||||
// 204 No Content: Has permissions. Token might be too weak.
|
||||
// 404 Not Found: Not a collaborator.
|
||||
// 401 Unauthorized: Token is bad/revoked.
|
||||
|
||||
$no_permission = ($status->getStatusCode() == 404);
|
||||
|
||||
if ($no_permission) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
"You don't have permission to push to this repository. ".
|
||||
"Push permissions for this repository are managed on GitHub."));
|
||||
}
|
||||
|
||||
$scopes = BaseHTTPFuture::getHeader($headers, 'X-OAuth-Scopes');
|
||||
if (strpos($scopes, 'public_repo') === false) {
|
||||
$provider_key = $this->provider->getProviderKey();
|
||||
$refresh_token_uri = new PhutilURI("/auth/refresh/{$provider_key}/");
|
||||
$refresh_token_uri->setQueryParam('scope', 'public_repo');
|
||||
|
||||
return id(new AphrontDialogView())
|
||||
->setUser($viewer)
|
||||
->setTitle(pht('Stronger token needed'))
|
||||
->appendChild(pht(
|
||||
'In order to complete this action, you need a '.
|
||||
'stronger GitHub token.'))
|
||||
->setSubmitURI($refresh_token_uri)
|
||||
->addCancelButton('/D'.$revision->getId())
|
||||
->setDisableWorkflowOnSubmit(true)
|
||||
->addSubmitButton(pht('Refresh Account Link'));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,127 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class DifferentialHostedGitLandingStrategy
|
||||
extends DifferentialLandingStrategy {
|
||||
|
||||
public function processLandRequest(
|
||||
AphrontRequest $request,
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorRepository $repository) {
|
||||
|
||||
$viewer = $request->getUser();
|
||||
$workspace = $this->getGitWorkspace($repository);
|
||||
|
||||
try {
|
||||
$this->commitRevisionToWorkspace($revision, $workspace, $viewer);
|
||||
} catch (Exception $e) {
|
||||
throw new PhutilProxyException(
|
||||
pht('Failed to commit patch.'),
|
||||
$e);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->pushWorkspaceRepository($repository, $workspace, $viewer);
|
||||
} catch (Exception $e) {
|
||||
throw new PhutilProxyException(
|
||||
pht('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();
|
||||
|
||||
$missing_binary =
|
||||
"\nindex "
|
||||
."0000000000000000000000000000000000000000.."
|
||||
."0000000000000000000000000000000000000000\n";
|
||||
if (strpos($raw_diff, $missing_binary) !== false) {
|
||||
throw new Exception(pht('Patch is missing content for a binary file'));
|
||||
}
|
||||
|
||||
$future = $workspace->execFutureLocal('apply --index -');
|
||||
$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(
|
||||
'-c user.name=%s -c user.email=%s '.
|
||||
'commit --date=%s --author=%s '.
|
||||
'--message=%s',
|
||||
// -c will set the 'committer'
|
||||
$user->getRealName(),
|
||||
$user->loadPrimaryEmailAddress(),
|
||||
$author_date,
|
||||
$author_string,
|
||||
$message);
|
||||
}
|
||||
|
||||
public function pushWorkspaceRepository(
|
||||
PhabricatorRepository $repository,
|
||||
ArcanistRepositoryAPI $workspace,
|
||||
PhabricatorUser $user) {
|
||||
|
||||
$workspace->execxLocal('push origin HEAD:master');
|
||||
}
|
||||
|
||||
public function createMenuItem(
|
||||
PhabricatorUser $viewer,
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorRepository $repository) {
|
||||
|
||||
$vcs = $repository->getVersionControlSystem();
|
||||
if ($vcs !== PhabricatorRepositoryType::REPOSITORY_TYPE_GIT) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$repository->isHosted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$repository->isWorkingCopyBare()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: This temporarily disables this action, because it doesn't work
|
||||
// and is confusing to users. If you want to use it, comment out this line
|
||||
// for now and we'll provide real support eventually.
|
||||
return;
|
||||
|
||||
return $this->createActionView(
|
||||
$revision,
|
||||
pht('Land to Hosted Repository'));
|
||||
}
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class DifferentialHostedMercurialLandingStrategy
|
||||
extends DifferentialLandingStrategy {
|
||||
|
||||
public function processLandRequest(
|
||||
AphrontRequest $request,
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorRepository $repository) {
|
||||
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$workspace = $this->getMercurialWorkspace($repository);
|
||||
|
||||
try {
|
||||
$this->commitRevisionToWorkspace($revision, $workspace, $viewer);
|
||||
} catch (Exception $e) {
|
||||
throw new PhutilProxyException(pht('Failed to commit patch.'), $e);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->pushWorkspaceRepository($repository, $workspace, $viewer);
|
||||
} catch (Exception $e) {
|
||||
throw new PhutilProxyException(
|
||||
pht('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 createMenuItem(
|
||||
PhabricatorUser $viewer,
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorRepository $repository) {
|
||||
|
||||
$vcs = $repository->getVersionControlSystem();
|
||||
if ($vcs !== PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$repository->isHosted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
return $this->createActionView(
|
||||
$revision,
|
||||
pht('Land to Hosted Repository'));
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This class adds a "Land this" button to revision view.
|
||||
*/
|
||||
final class DifferentialLandingActionMenuEventListener
|
||||
extends PhabricatorEventListener {
|
||||
|
||||
public function register() {
|
||||
$this->listen(PhabricatorEventType::TYPE_UI_DIDRENDERACTIONS);
|
||||
}
|
||||
|
||||
public function handleEvent(PhutilEvent $event) {
|
||||
switch ($event->getType()) {
|
||||
case PhabricatorEventType::TYPE_UI_DIDRENDERACTIONS:
|
||||
$this->handleActionsEvent($event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private function handleActionsEvent(PhutilEvent $event) {
|
||||
$object = $event->getValue('object');
|
||||
if ($object instanceof DifferentialRevision) {
|
||||
$this->renderRevisionAction($event);
|
||||
}
|
||||
}
|
||||
|
||||
private function renderRevisionAction(PhutilEvent $event) {
|
||||
$viewer = $event->getUser();
|
||||
|
||||
if (!$this->canUseApplication($viewer)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$revision = $event->getValue('object');
|
||||
|
||||
$repository = $revision->getRepository();
|
||||
if ($repository === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($repository->canPerformAutomation()) {
|
||||
$revision_id = $revision->getID();
|
||||
|
||||
$op = new DrydockLandRepositoryOperation();
|
||||
$barrier = $op->getBarrierToLanding($viewer, $revision);
|
||||
|
||||
if ($barrier) {
|
||||
$can_land = false;
|
||||
} else {
|
||||
$can_land = true;
|
||||
}
|
||||
|
||||
$action = id(new PhabricatorActionView())
|
||||
->setName(pht('Land Revision'))
|
||||
->setIcon('fa-fighter-jet')
|
||||
->setHref("/differential/revision/operation/{$revision_id}/")
|
||||
->setWorkflow(true)
|
||||
->setDisabled(!$can_land);
|
||||
|
||||
|
||||
$this->addActionMenuItems($event, $action);
|
||||
}
|
||||
|
||||
$strategies = id(new PhutilClassMapQuery())
|
||||
->setAncestorClass('DifferentialLandingStrategy')
|
||||
->execute();
|
||||
|
||||
foreach ($strategies as $strategy) {
|
||||
$action = $strategy->createMenuItem($viewer, $revision, $repository);
|
||||
if ($action == null) {
|
||||
continue;
|
||||
}
|
||||
if ($strategy->isActionDisabled($viewer, $revision, $repository)) {
|
||||
$action->setDisabled(true);
|
||||
}
|
||||
$this->addActionMenuItems($event, $action);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
<?php
|
||||
|
||||
abstract class DifferentialLandingStrategy extends Phobject {
|
||||
|
||||
abstract public function processLandRequest(
|
||||
AphrontRequest $request,
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorRepository $repository);
|
||||
|
||||
/**
|
||||
* @return PhabricatorActionView or null.
|
||||
*/
|
||||
abstract public function createMenuItem(
|
||||
PhabricatorUser $viewer,
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorRepository $repository);
|
||||
|
||||
/**
|
||||
* @return PhabricatorActionView which can be attached to the revision view.
|
||||
*/
|
||||
protected function createActionView($revision, $name) {
|
||||
$strategy = get_class($this);
|
||||
$revision_id = $revision->getId();
|
||||
return id(new PhabricatorActionView())
|
||||
->setRenderAsForm(true)
|
||||
->setWorkflow(true)
|
||||
->setName($name)
|
||||
->setHref("/differential/revision/land/{$revision_id}/{$strategy}/");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this action should be disabled, and explain why.
|
||||
*
|
||||
* By default, this method checks for push permissions, and for the
|
||||
* revision being Accepted.
|
||||
*
|
||||
* @return False for "not disabled"; human-readable text explaining why, if
|
||||
* it is disabled.
|
||||
*/
|
||||
public function isActionDisabled(
|
||||
PhabricatorUser $viewer,
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorRepository $repository) {
|
||||
|
||||
$status = $revision->getStatus();
|
||||
if ($status != ArcanistDifferentialRevisionStatus::ACCEPTED) {
|
||||
return pht('Only Accepted revisions can be landed.');
|
||||
}
|
||||
|
||||
if (!PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$repository,
|
||||
DiffusionPushCapability::CAPABILITY)) {
|
||||
return pht('You do not have permissions to push to this repository.');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Might break if repository is not Git.
|
||||
*/
|
||||
protected function getGitWorkspace(PhabricatorRepository $repository) {
|
||||
try {
|
||||
return DifferentialGetWorkingCopy::getCleanGitWorkspace($repository);
|
||||
} catch (Exception $e) {
|
||||
throw new PhutilProxyException(
|
||||
pht('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(
|
||||
pht('Failed to allocate a workspace.'),
|
||||
$e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue