mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-31 17:08:22 +01:00
Use TransactionEditor when closing revisions in response to commits
Summary: Ref T2222. When we discover a commit associated with a revision, close it using modern transactions. Test Plan: {F123848} Reviewers: btrahan Reviewed By: btrahan CC: aran Maniphest Tasks: T2222 Differential Revision: https://secure.phabricator.com/D8441
This commit is contained in:
parent
458a28eed3
commit
b04f706c0a
3 changed files with 134 additions and 55 deletions
|
@ -4,6 +4,26 @@ final class DifferentialTransactionEditor
|
||||||
extends PhabricatorApplicationTransactionEditor {
|
extends PhabricatorApplicationTransactionEditor {
|
||||||
|
|
||||||
private $heraldEmailPHIDs;
|
private $heraldEmailPHIDs;
|
||||||
|
private $changedPriorToCommitURI;
|
||||||
|
private $isCloseByCommit;
|
||||||
|
|
||||||
|
public function setIsCloseByCommit($is_close_by_commit) {
|
||||||
|
$this->isCloseByCommit = $is_close_by_commit;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIsCloseByCommit() {
|
||||||
|
return $this->isCloseByCommit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setChangedPriorToCommitURI($uri) {
|
||||||
|
$this->changedPriorToCommitURI = $uri;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getChangedPriorToCommitURI() {
|
||||||
|
return $this->changedPriorToCommitURI;
|
||||||
|
}
|
||||||
|
|
||||||
public function getTransactionTypes() {
|
public function getTransactionTypes() {
|
||||||
$types = parent::getTransactionTypes();
|
$types = parent::getTransactionTypes();
|
||||||
|
@ -158,7 +178,9 @@ final class DifferentialTransactionEditor
|
||||||
case PhabricatorTransactions::TYPE_EDGE:
|
case PhabricatorTransactions::TYPE_EDGE:
|
||||||
return;
|
return;
|
||||||
case DifferentialTransaction::TYPE_UPDATE:
|
case DifferentialTransaction::TYPE_UPDATE:
|
||||||
|
if (!$this->getIsCloseByCommit()) {
|
||||||
$object->setStatus($status_review);
|
$object->setStatus($status_review);
|
||||||
|
}
|
||||||
// TODO: Update the `diffPHID` once we add that.
|
// TODO: Update the `diffPHID` once we add that.
|
||||||
return;
|
return;
|
||||||
case DifferentialTransaction::TYPE_ACTION:
|
case DifferentialTransaction::TYPE_ACTION:
|
||||||
|
@ -209,6 +231,12 @@ final class DifferentialTransactionEditor
|
||||||
$results = parent::expandTransaction($object, $xaction);
|
$results = parent::expandTransaction($object, $xaction);
|
||||||
switch ($xaction->getTransactionType()) {
|
switch ($xaction->getTransactionType()) {
|
||||||
case DifferentialTransaction::TYPE_UPDATE:
|
case DifferentialTransaction::TYPE_UPDATE:
|
||||||
|
if ($this->getIsCloseByCommit()) {
|
||||||
|
// Don't bother with any of this if this update is a side effect of
|
||||||
|
// commit detection.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
$new_accept = DifferentialReviewerStatus::STATUS_ACCEPTED;
|
$new_accept = DifferentialReviewerStatus::STATUS_ACCEPTED;
|
||||||
$new_reject = DifferentialReviewerStatus::STATUS_REJECTED;
|
$new_reject = DifferentialReviewerStatus::STATUS_REJECTED;
|
||||||
$old_accept = DifferentialReviewerStatus::STATUS_ACCEPTED_OLDER;
|
$old_accept = DifferentialReviewerStatus::STATUS_ACCEPTED_OLDER;
|
||||||
|
@ -784,9 +812,11 @@ final class DifferentialTransactionEditor
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DifferentialAction::ACTION_CLOSE:
|
case DifferentialAction::ACTION_CLOSE:
|
||||||
|
// We force revisions closed when we discover a corresponding commit.
|
||||||
|
// In this case, revisions are allowed to transition to closed from
|
||||||
|
// any state. This is an automated action taken by the daemons.
|
||||||
|
|
||||||
// TODO: Permit the daemons to take this action in all cases.
|
if (!$this->getIsCloseByCommit()) {
|
||||||
|
|
||||||
if (!$actor_is_author && !$always_allow_close) {
|
if (!$actor_is_author && !$always_allow_close) {
|
||||||
return pht(
|
return pht(
|
||||||
"You can not close this revision because you do not own it. To ".
|
"You can not close this revision because you do not own it. To ".
|
||||||
|
@ -798,6 +828,7 @@ final class DifferentialTransactionEditor
|
||||||
"You can not close this revision because it has not been ".
|
"You can not close this revision because it has not been ".
|
||||||
"accepted. You can only close accepted revisions.");
|
"accepted. You can only close accepted revisions.");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -909,6 +940,13 @@ final class DifferentialTransactionEditor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$changed_uri = $this->getChangedPriorToCommitURI();
|
||||||
|
if ($changed_uri) {
|
||||||
|
$body->addTextSection(
|
||||||
|
pht('CHANGED PRIOR TO COMMIT'),
|
||||||
|
$changed_uri);
|
||||||
|
}
|
||||||
|
|
||||||
if ($inlines) {
|
if ($inlines) {
|
||||||
$body->addTextSection(
|
$body->addTextSection(
|
||||||
pht('INLINE COMMENTS'),
|
pht('INLINE COMMENTS'),
|
||||||
|
@ -1099,9 +1137,11 @@ final class DifferentialTransactionEditor
|
||||||
foreach ($xactions as $xaction) {
|
foreach ($xactions as $xaction) {
|
||||||
switch ($xaction->getTransactionType()) {
|
switch ($xaction->getTransactionType()) {
|
||||||
case DifferentialTransaction::TYPE_UPDATE:
|
case DifferentialTransaction::TYPE_UPDATE:
|
||||||
|
if (!$this->getIsCloseByCommit()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return parent::shouldApplyHeraldRules($object, $xactions);
|
return parent::shouldApplyHeraldRules($object, $xactions);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ final class PhabricatorContentSource {
|
||||||
const SOURCE_CONSOLE = 'console';
|
const SOURCE_CONSOLE = 'console';
|
||||||
const SOURCE_HERALD = 'herald';
|
const SOURCE_HERALD = 'herald';
|
||||||
const SOURCE_LEGACY = 'legacy';
|
const SOURCE_LEGACY = 'legacy';
|
||||||
|
const SOURCE_DAEMON = 'daemon';
|
||||||
|
|
||||||
private $source;
|
private $source;
|
||||||
private $params = array();
|
private $params = array();
|
||||||
|
@ -72,6 +73,7 @@ final class PhabricatorContentSource {
|
||||||
self::SOURCE_CONSOLE => pht('Console'),
|
self::SOURCE_CONSOLE => pht('Console'),
|
||||||
self::SOURCE_LEGACY => pht('Legacy'),
|
self::SOURCE_LEGACY => pht('Legacy'),
|
||||||
self::SOURCE_HERALD => pht('Herald'),
|
self::SOURCE_HERALD => pht('Herald'),
|
||||||
|
self::SOURCE_DAEMON => pht('Daemons'),
|
||||||
self::SOURCE_UNKNOWN => pht('Old World'),
|
self::SOURCE_UNKNOWN => pht('Old World'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,16 +78,18 @@ abstract class PhabricatorRepositoryCommitMessageParserWorker
|
||||||
$should_autoclose = $repository->shouldAutocloseCommit($commit, $data);
|
$should_autoclose = $repository->shouldAutocloseCommit($commit, $data);
|
||||||
|
|
||||||
if ($revision_id) {
|
if ($revision_id) {
|
||||||
$lock = PhabricatorGlobalLock::newLock(get_class($this).':'.$revision_id);
|
|
||||||
$lock->lock(5 * 60);
|
|
||||||
|
|
||||||
// TODO: Check if a more restrictive viewer could be set here
|
// TODO: Check if a more restrictive viewer could be set here
|
||||||
$revision = id(new DifferentialRevisionQuery())
|
$revision_query = id(new DifferentialRevisionQuery())
|
||||||
->withIDs(array($revision_id))
|
->withIDs(array($revision_id))
|
||||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||||
->needRelationships(true)
|
|
||||||
->needReviewerStatus(true)
|
->needReviewerStatus(true)
|
||||||
->executeOne();
|
->needActiveDiffs(true);
|
||||||
|
|
||||||
|
// TODO: Remove this once we swap to new CustomFields. This is only
|
||||||
|
// required by the old FieldSpecifications, lower on in this worker.
|
||||||
|
$revision_query->needRelationships(true);
|
||||||
|
|
||||||
|
$revision = $revision_query->executeOne();
|
||||||
|
|
||||||
if ($revision) {
|
if ($revision) {
|
||||||
$commit_drev = PhabricatorEdgeConfig::TYPE_COMMIT_HAS_DREV;
|
$commit_drev = PhabricatorEdgeConfig::TYPE_COMMIT_HAS_DREV;
|
||||||
|
@ -112,29 +114,10 @@ abstract class PhabricatorRepositoryCommitMessageParserWorker
|
||||||
$committer_phid,
|
$committer_phid,
|
||||||
$author_phid,
|
$author_phid,
|
||||||
$revision->getAuthorPHID());
|
$revision->getAuthorPHID());
|
||||||
|
|
||||||
$actor = id(new PhabricatorUser())
|
$actor = id(new PhabricatorUser())
|
||||||
->loadOneWhere('phid = %s', $actor_phid);
|
->loadOneWhere('phid = %s', $actor_phid);
|
||||||
|
|
||||||
$diff = $this->attachToRevision($revision, $actor_phid);
|
|
||||||
|
|
||||||
$editor = new DifferentialCommentEditor(
|
|
||||||
$revision,
|
|
||||||
DifferentialAction::ACTION_CLOSE);
|
|
||||||
$editor->setActor($actor);
|
|
||||||
$editor->setIsDaemonWorkflow(true);
|
|
||||||
|
|
||||||
$vs_diff = $this->loadChangedByCommit($diff);
|
|
||||||
if ($vs_diff) {
|
|
||||||
$data->setCommitDetail('vsDiff', $vs_diff->getID());
|
|
||||||
|
|
||||||
$changed_by_commit = PhabricatorEnv::getProductionURI(
|
|
||||||
'/D'.$revision->getID().
|
|
||||||
'?vs='.$vs_diff->getID().
|
|
||||||
'&id='.$diff->getID().
|
|
||||||
'#toc');
|
|
||||||
$editor->setChangedByCommit($changed_by_commit);
|
|
||||||
}
|
|
||||||
|
|
||||||
$commit_name = $repository->formatCommitName(
|
$commit_name = $repository->formatCommitName(
|
||||||
$commit->getCommitIdentifier());
|
$commit->getCommitIdentifier());
|
||||||
|
|
||||||
|
@ -148,24 +131,77 @@ abstract class PhabricatorRepositoryCommitMessageParserWorker
|
||||||
$data->getAuthorName(),
|
$data->getAuthorName(),
|
||||||
$actor);
|
$actor);
|
||||||
|
|
||||||
$info = array();
|
|
||||||
$info[] = "authored by {$author_name}";
|
|
||||||
if ($committer_name && ($committer_name != $author_name)) {
|
if ($committer_name && ($committer_name != $author_name)) {
|
||||||
$info[] = "committed by {$committer_name}";
|
$message = pht(
|
||||||
}
|
'Closed by commit %s (authored by %s, committed by %s).',
|
||||||
$info = implode(', ', $info);
|
$commit_name,
|
||||||
|
$author_name,
|
||||||
$editor
|
$committer_name);
|
||||||
->setMessage("Closed by commit {$commit_name} ({$info}).")
|
} else {
|
||||||
->save();
|
$message = pht(
|
||||||
|
'Closed by commit %s (authored by %s).',
|
||||||
|
$commit_name,
|
||||||
|
$author_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$diff = $this->generateFinalDiff($revision, $actor_phid);
|
||||||
|
|
||||||
|
$vs_diff = $this->loadChangedByCommit($revision, $diff);
|
||||||
|
$changed_uri = null;
|
||||||
|
if ($vs_diff) {
|
||||||
|
$data->setCommitDetail('vsDiff', $vs_diff->getID());
|
||||||
|
|
||||||
|
$changed_uri = PhabricatorEnv::getProductionURI(
|
||||||
|
'/D'.$revision->getID().
|
||||||
|
'?vs='.$vs_diff->getID().
|
||||||
|
'&id='.$diff->getID().
|
||||||
|
'#toc');
|
||||||
}
|
}
|
||||||
|
|
||||||
$lock->unlock();
|
$xactions = array();
|
||||||
|
|
||||||
|
$xactions[] = id(new DifferentialTransaction())
|
||||||
|
->setTransactionType(DifferentialTransaction::TYPE_ACTION)
|
||||||
|
->setNewValue(DifferentialAction::ACTION_CLOSE);
|
||||||
|
|
||||||
|
$xactions[] = id(new DifferentialTransaction())
|
||||||
|
->setTransactionType(DifferentialTransaction::TYPE_UPDATE)
|
||||||
|
->setIgnoreOnNoEffect(true)
|
||||||
|
->setNewValue($diff->getPHID());
|
||||||
|
|
||||||
|
$xactions[] = id(new DifferentialTransaction())
|
||||||
|
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
|
||||||
|
->setIgnoreOnNoEffect(true)
|
||||||
|
->attachComment(
|
||||||
|
id(new DifferentialTransactionComment())
|
||||||
|
->setContent($message));
|
||||||
|
|
||||||
|
$content_source = PhabricatorContentSource::newForSource(
|
||||||
|
PhabricatorContentSource::SOURCE_DAEMON,
|
||||||
|
array());
|
||||||
|
|
||||||
|
$editor = id(new DifferentialTransactionEditor())
|
||||||
|
->setActor($actor)
|
||||||
|
->setContinueOnMissingFields(true)
|
||||||
|
->setContentSource($content_source)
|
||||||
|
->setChangedPriorToCommitURI($changed_uri)
|
||||||
|
->setIsCloseByCommit(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$editor->applyTransactions($revision, $xactions);
|
||||||
|
} catch (PhabricatorApplicationTransactionNoEffectException $ex) {
|
||||||
|
// NOTE: We've marked transactions other than the CLOSE transaction
|
||||||
|
// as ignored when they don't have an effect, so this means that we
|
||||||
|
// lost a race to close the revision. That's perfectly fine, we can
|
||||||
|
// just continue normally.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($should_autoclose) {
|
if ($should_autoclose) {
|
||||||
|
// TODO: When this is moved to CustomFields, remove the additional
|
||||||
|
// call above in query construction.
|
||||||
$fields = DifferentialFieldSelector::newSelector()
|
$fields = DifferentialFieldSelector::newSelector()
|
||||||
->getFieldSpecifications();
|
->getFieldSpecifications();
|
||||||
foreach ($fields as $key => $field) {
|
foreach ($fields as $key => $field) {
|
||||||
|
@ -200,7 +236,7 @@ abstract class PhabricatorRepositoryCommitMessageParserWorker
|
||||||
return '@'.$handle->getName();
|
return '@'.$handle->getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function attachToRevision(
|
private function generateFinalDiff(
|
||||||
DifferentialRevision $revision,
|
DifferentialRevision $revision,
|
||||||
$actor_phid) {
|
$actor_phid) {
|
||||||
|
|
||||||
|
@ -232,7 +268,7 @@ abstract class PhabricatorRepositoryCommitMessageParserWorker
|
||||||
}
|
}
|
||||||
|
|
||||||
$diff = DifferentialDiff::newFromRawChanges($changes)
|
$diff = DifferentialDiff::newFromRawChanges($changes)
|
||||||
->setRevisionID($revision->getID())
|
->setRepositoryPHID($this->repository->getPHID())
|
||||||
->setAuthorPHID($actor_phid)
|
->setAuthorPHID($actor_phid)
|
||||||
->setCreationMethod('commit')
|
->setCreationMethod('commit')
|
||||||
->setSourceControlSystem($this->repository->getVersionControlSystem())
|
->setSourceControlSystem($this->repository->getVersionControlSystem())
|
||||||
|
@ -265,18 +301,19 @@ abstract class PhabricatorRepositoryCommitMessageParserWorker
|
||||||
|
|
||||||
// TODO: Attach binary files.
|
// TODO: Attach binary files.
|
||||||
|
|
||||||
$revision->setLineCount($diff->getLineCount());
|
|
||||||
|
|
||||||
return $diff->save();
|
return $diff->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function loadChangedByCommit(DifferentialDiff $diff) {
|
private function loadChangedByCommit(
|
||||||
|
DifferentialRevision $revision,
|
||||||
|
DifferentialDiff $diff) {
|
||||||
|
|
||||||
$repository = $this->repository;
|
$repository = $this->repository;
|
||||||
|
|
||||||
$vs_changesets = array();
|
$vs_changesets = array();
|
||||||
$vs_diff = id(new DifferentialDiff())->loadOneWhere(
|
$vs_diff = id(new DifferentialDiff())->loadOneWhere(
|
||||||
'revisionID = %d AND creationMethod != %s ORDER BY id DESC LIMIT 1',
|
'revisionID = %d AND creationMethod != %s ORDER BY id DESC LIMIT 1',
|
||||||
$diff->getRevisionID(),
|
$revision->getID(),
|
||||||
'commit');
|
'commit');
|
||||||
foreach ($vs_diff->loadChangesets() as $changeset) {
|
foreach ($vs_diff->loadChangesets() as $changeset) {
|
||||||
$path = $changeset->getAbsoluteRepositoryPath($repository, $vs_diff);
|
$path = $changeset->getAbsoluteRepositoryPath($repository, $vs_diff);
|
||||||
|
|
Loading…
Add table
Reference in a new issue