mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-19 13:22:42 +01:00
If the stars align, make "Land Revision" kind of work
Summary: Ref T182. If 35 other things are configured completely correctly, make it remotely possible that this button may do something approximating the thing that the user wanted. This primarily fleshes out the idea that "operations" (like landing, merging or cherry-picking) can have some beahavior, and when we run an operation we do whatever that behavior is instead of just running `git show`. Broadly, this isn't too terrible because Drydock seems like it actually works properly for the most part (???!?!). Test Plan: {F876431} Reviewers: chad Reviewed By: chad Maniphest Tasks: T182 Differential Revision: https://secure.phabricator.com/D14270
This commit is contained in:
parent
b4af57ec51
commit
43bee4562c
7 changed files with 159 additions and 10 deletions
|
@ -10,6 +10,7 @@ final class DifferentialRevisionOperationController
|
|||
$revision = id(new DifferentialRevisionQuery())
|
||||
->withIDs(array($id))
|
||||
->setViewer($viewer)
|
||||
->needActiveDiffs(true)
|
||||
->executeOne();
|
||||
if (!$revision) {
|
||||
return new Aphront404Response();
|
||||
|
@ -58,13 +59,20 @@ final class DifferentialRevisionOperationController
|
|||
}
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
// NOTE: The operation is locked to the current active diff, so if the
|
||||
// revision is updated before the operation applies nothing sneaky
|
||||
// occurs.
|
||||
|
||||
$diff = $revision->getActiveDiff();
|
||||
|
||||
$op = new DrydockLandRepositoryOperation();
|
||||
|
||||
$operation = DrydockRepositoryOperation::initializeNewOperation($op)
|
||||
->setAuthorPHID($viewer->getPHID())
|
||||
->setObjectPHID($revision->getPHID())
|
||||
->setRepositoryPHID($repository->getPHID())
|
||||
->setRepositoryTarget('branch:master');
|
||||
->setRepositoryTarget('branch:master')
|
||||
->setProperty('differential.diffPHID', $diff->getPHID());
|
||||
|
||||
$operation->save();
|
||||
$operation->scheduleUpdate();
|
||||
|
|
|
@ -447,12 +447,8 @@ final class DifferentialDiff
|
|||
$results['repository.vcs'] = $repo->getVersionControlSystem();
|
||||
$results['repository.uri'] = $repo->getPublicCloneURI();
|
||||
|
||||
// TODO: We're just hoping to get lucky. Instead, `arc` should store
|
||||
// where it sent changes and we should only provide staging details
|
||||
// if we reasonably believe they are accurate.
|
||||
$staging_ref = 'refs/tags/phabricator/diff/'.$this->getID();
|
||||
$results['repository.staging.uri'] = $repo->getStagingURI();
|
||||
$results['repository.staging.ref'] = $staging_ref;
|
||||
$results['repository.staging.ref'] = $this->getStagingRef();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -480,6 +476,13 @@ final class DifferentialDiff
|
|||
);
|
||||
}
|
||||
|
||||
public function getStagingRef() {
|
||||
// TODO: We're just hoping to get lucky. Instead, `arc` should store
|
||||
// where it sent changes and we should only provide staging details
|
||||
// if we reasonably believe they are accurate.
|
||||
return 'refs/tags/phabricator/diff/'.$this->getID();
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
|
||||
|
||||
|
|
|
@ -5,4 +5,94 @@ final class DrydockLandRepositoryOperation
|
|||
|
||||
const OPCONST = 'land';
|
||||
|
||||
public function applyOperation(
|
||||
DrydockRepositoryOperation $operation,
|
||||
DrydockInterface $interface) {
|
||||
$viewer = $this->getViewer();
|
||||
$repository = $operation->getRepository();
|
||||
|
||||
$cmd = array();
|
||||
$arg = array();
|
||||
|
||||
$object = $operation->getObject();
|
||||
if ($object instanceof DifferentialRevision) {
|
||||
$revision = $object;
|
||||
|
||||
$diff_phid = $operation->getProperty('differential.diffPHID');
|
||||
|
||||
$diff = id(new DifferentialDiffQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($diff_phid))
|
||||
->executeOne();
|
||||
if (!$diff) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Unable to load diff "%s".',
|
||||
$diff_phid));
|
||||
}
|
||||
|
||||
$diff_revid = $diff->getRevisionID();
|
||||
$revision_id = $revision->getID();
|
||||
if ($diff_revid != $revision_id) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Diff ("%s") has wrong revision ID ("%s", expected "%s").',
|
||||
$diff_phid,
|
||||
$diff_revid,
|
||||
$revision_id));
|
||||
}
|
||||
|
||||
$cmd[] = 'git fetch --no-tags -- %s +%s:%s';
|
||||
$arg[] = $repository->getStagingURI();
|
||||
$arg[] = $diff->getStagingRef();
|
||||
$arg[] = $diff->getStagingRef();
|
||||
|
||||
$merge_src = $diff->getStagingRef();
|
||||
} else {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Invalid or unknown object ("%s") for land operation, expected '.
|
||||
'Differential Revision.',
|
||||
$operation->getObjectPHID()));
|
||||
}
|
||||
|
||||
$target = $operation->getRepositoryTarget();
|
||||
list($type, $name) = explode(':', $target, 2);
|
||||
switch ($type) {
|
||||
case 'branch':
|
||||
$push_dst = 'refs/heads/'.$name;
|
||||
$merge_dst = 'refs/remotes/origin/'.$name;
|
||||
break;
|
||||
default:
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Unknown repository operation target type "%s" (in target "%s").',
|
||||
$type,
|
||||
$target));
|
||||
}
|
||||
|
||||
$cmd[] = 'git checkout %s';
|
||||
$arg[] = $merge_dst;
|
||||
|
||||
$cmd[] = 'git merge --no-stat --squash --ff-only -- %s';
|
||||
$arg[] = $merge_src;
|
||||
|
||||
$cmd[] = 'git -c user.name=%s -c user.email=%s commit --author %s -m %s';
|
||||
$arg[] = 'autocommitter';
|
||||
$arg[] = 'autocommitter@example.com';
|
||||
$arg[] = 'autoauthor <autoauthor@example.com>';
|
||||
$arg[] = pht('(Automerge!)');
|
||||
|
||||
$cmd[] = 'git push origin -- %s:%s';
|
||||
$arg[] = 'HEAD';
|
||||
$arg[] = $push_dst;
|
||||
|
||||
$cmd = implode(' && ', $cmd);
|
||||
$argv = array_merge(array($cmd), $arg);
|
||||
|
||||
$result = call_user_func_array(
|
||||
array($interface, 'execx'),
|
||||
$argv);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,21 @@
|
|||
|
||||
abstract class DrydockRepositoryOperationType extends Phobject {
|
||||
|
||||
private $viewer;
|
||||
|
||||
abstract public function applyOperation(
|
||||
DrydockRepositoryOperation $operation,
|
||||
DrydockInterface $interface);
|
||||
|
||||
final public function setViewer(PhabricatorUser $viewer) {
|
||||
$this->viewer = $viewer;
|
||||
return $this;
|
||||
}
|
||||
|
||||
final public function getViewer() {
|
||||
return $this->viewer;
|
||||
}
|
||||
|
||||
final public function getOperationConstant() {
|
||||
return $this->getPhobjectClassConstant('OPCONST', 32);
|
||||
}
|
||||
|
|
|
@ -42,6 +42,19 @@ final class DrydockRepositoryOperationQuery extends DrydockQuery {
|
|||
}
|
||||
|
||||
protected function willFilterPage(array $operations) {
|
||||
$implementations = DrydockRepositoryOperationType::getAllOperationTypes();
|
||||
|
||||
foreach ($operations as $key => $operation) {
|
||||
$impl = idx($implementations, $operation->getOperationType());
|
||||
if (!$impl) {
|
||||
$this->didRejectResult($operation);
|
||||
unset($operations[$key]);
|
||||
continue;
|
||||
}
|
||||
$impl = clone $impl;
|
||||
$operation->attachImplementation($impl);
|
||||
}
|
||||
|
||||
$repository_phids = mpull($operations, 'getRepositoryPHID');
|
||||
if ($repository_phids) {
|
||||
$repositories = id(new PhabricatorRepositoryQuery())
|
||||
|
@ -75,7 +88,7 @@ final class DrydockRepositoryOperationQuery extends DrydockQuery {
|
|||
->setParentQuery($this)
|
||||
->withPHIDs($object_phids)
|
||||
->execute();
|
||||
$objects = mpull($objects, 'getPHID');
|
||||
$objects = mpull($objects, null, 'getPHID');
|
||||
} else {
|
||||
$objects = array();
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ final class DrydockRepositoryOperation extends DrydockDAO
|
|||
|
||||
private $repository = self::ATTACHABLE;
|
||||
private $object = self::ATTACHABLE;
|
||||
private $implementation = self::ATTACHABLE;
|
||||
|
||||
public static function initializeNewOperation(
|
||||
DrydockRepositoryOperationType $op) {
|
||||
|
@ -77,6 +78,15 @@ final class DrydockRepositoryOperation extends DrydockDAO
|
|||
return $this->assertAttached($this->object);
|
||||
}
|
||||
|
||||
public function attachImplementation(DrydockRepositoryOperationType $impl) {
|
||||
$this->implementation = $impl;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getImplementation() {
|
||||
return $this->implementation;
|
||||
}
|
||||
|
||||
public function getProperty($key, $default = null) {
|
||||
return idx($this->properties, $key, $default);
|
||||
}
|
||||
|
@ -120,6 +130,12 @@ final class DrydockRepositoryOperation extends DrydockDAO
|
|||
));
|
||||
}
|
||||
|
||||
public function applyOperation(DrydockInterface $interface) {
|
||||
return $this->getImplementation()->applyOperation(
|
||||
$this,
|
||||
$interface);
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||
|
||||
|
|
|
@ -25,6 +25,8 @@ final class DrydockRepositoryOperationUpdateWorker
|
|||
|
||||
|
||||
private function handleUpdate(DrydockRepositoryOperation $operation) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$operation_state = $operation->getOperationState();
|
||||
|
||||
switch ($operation_state) {
|
||||
|
@ -59,9 +61,11 @@ final class DrydockRepositoryOperationUpdateWorker
|
|||
// No matter what happens here, destroy the lease away once we're done.
|
||||
$lease->releaseOnDestruction(true);
|
||||
|
||||
// TODO: Some day, do useful things instead of running `git show`.
|
||||
list($stdout) = $interface->execx('git show');
|
||||
phlog($stdout);
|
||||
$operation->getImplementation()
|
||||
->setViewer($viewer);
|
||||
|
||||
$operation->applyOperation($interface);
|
||||
|
||||
} catch (PhabricatorWorkerYieldException $ex) {
|
||||
throw $ex;
|
||||
} catch (Exception $ex) {
|
||||
|
|
Loading…
Reference in a new issue