Changeset View
Changeset View
Standalone View
Standalone View
src/applications/diffusion/engine/DiffusionCommitHookEngine.php
Show First 20 Lines • Show All 121 Lines • ▼ Show 20 Lines | /* -( Hook Execution )----------------------------------------------------- */ | ||||
public function execute() { | public function execute() { | ||||
$ref_updates = $this->findRefUpdates(); | $ref_updates = $this->findRefUpdates(); | ||||
$all_updates = $ref_updates; | $all_updates = $ref_updates; | ||||
$caught = null; | $caught = null; | ||||
try { | try { | ||||
if ($this->isPushForReview($all_updates)) { | |||||
$diff = $this->generateDiffForReview($all_updates); | |||||
// TODO: Enrich this diff on many dimensions; these are required | |||||
// to save the object. | |||||
$diff->setLintStatus(DifferentialLintStatus::LINT_NONE); | |||||
$diff->setUnitStatus(DifferentialUnitStatus::UNIT_NONE); | |||||
$diff->save(); | |||||
$diff_uri = PhabricatorEnv::getProductionURI( | |||||
'/differential/diff/'.$diff->getID().'/'); | |||||
$console = PhutilConsole::getConsole(); | |||||
$console->writeErr( | |||||
"\n%s\n\n", | |||||
pht( | |||||
"Success! Created a new diff fom your changes:\n\n %s\n\n". | |||||
EddieGP: "fom": typo | |||||
"Since this was a push for review, your changes will not be\n". | |||||
"applied to the remote. This push will now be rejected.", | |||||
$diff_uri)); | |||||
// TODO: It would be nice to make Git think this push worked, but | |||||
// this is just an ease-of-use issue. For now, return an error to | |||||
// reject the changes. | |||||
return 77; | |||||
} | |||||
try { | try { | ||||
$this->rejectDangerousChanges($ref_updates); | $this->rejectDangerousChanges($ref_updates); | ||||
} catch (DiffusionCommitHookRejectException $ex) { | } catch (DiffusionCommitHookRejectException $ex) { | ||||
// If we're rejecting dangerous changes, flag everything that we've | // If we're rejecting dangerous changes, flag everything that we've | ||||
// seen as rejected so it's clear that none of it was accepted. | // seen as rejected so it's clear that none of it was accepted. | ||||
$this->rejectCode = PhabricatorRepositoryPushLog::REJECT_DANGEROUS; | $this->rejectCode = PhabricatorRepositoryPushLog::REJECT_DANGEROUS; | ||||
throw $ex; | throw $ex; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 109 Lines • ▼ Show 20 Lines | switch ($type) { | ||||
return $this->findMercurialContentUpdates($ref_updates); | return $this->findMercurialContentUpdates($ref_updates); | ||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: | case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: | ||||
return $this->findSubversionContentUpdates($ref_updates); | return $this->findSubversionContentUpdates($ref_updates); | ||||
default: | default: | ||||
throw new Exception(pht('Unsupported repository type "%s"!', $type)); | throw new Exception(pht('Unsupported repository type "%s"!', $type)); | ||||
} | } | ||||
} | } | ||||
private function isPushForReview(array $ref_updates) { | |||||
assert_instances_of($ref_updates, 'PhabricatorRepositoryPushLog'); | |||||
$type = $this->getRepository()->getVersionControlSystem(); | |||||
switch ($type) { | |||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: | |||||
return $this->isGitPushForReview($ref_updates); | |||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: | |||||
return false; | |||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: | |||||
return false; | |||||
default: | |||||
throw new Exception(pht('Unsupported repository type "%s"!', $type)); | |||||
} | |||||
} | |||||
private function generateDiffForReview(array $ref_updates) { | |||||
assert_instances_of($ref_updates, 'PhabricatorRepositoryPushLog'); | |||||
$update = head($ref_updates); | |||||
$type = $this->getRepository()->getVersionControlSystem(); | |||||
switch ($type) { | |||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: | |||||
return $this->generateGitDiffForReview($update); | |||||
default: | |||||
throw new Exception(pht('Unsupported repository type "%s"!', $type)); | |||||
} | |||||
} | |||||
/* -( Herald )------------------------------------------------------------- */ | /* -( Herald )------------------------------------------------------------- */ | ||||
private function applyHeraldRefRules( | private function applyHeraldRefRules( | ||||
array $ref_updates, | array $ref_updates, | ||||
array $all_updates) { | array $all_updates) { | ||||
$this->applyHeraldRules( | $this->applyHeraldRules( | ||||
$ref_updates, | $ref_updates, | ||||
▲ Show 20 Lines • Show All 313 Lines • ▼ Show 20 Lines | foreach (Futures($futures)->limit(8) as $key => $future) { | ||||
->setRefNew($commit) | ->setRefNew($commit) | ||||
->setChangeFlags(PhabricatorRepositoryPushLog::CHANGEFLAG_ADD); | ->setChangeFlags(PhabricatorRepositoryPushLog::CHANGEFLAG_ADD); | ||||
} | } | ||||
} | } | ||||
return $content_updates; | return $content_updates; | ||||
} | } | ||||
private function isGitPushForReview(array $ref_updates) { | |||||
foreach ($ref_updates as $update) { | |||||
$name = $update->getRefName(); | |||||
if (preg_match('(^review(?:/|\z))', $name)) { | |||||
if (count($ref_updates) !== 1) { | |||||
throw new DiffusionCommitHookRejectException( | |||||
pht( | |||||
'This push updates several branches, including a virtual branch '. | |||||
'which triggers code review (%s). When pushing changes for '. | |||||
'review, you must push to ONLY the virtual review branch.', | |||||
$name)); | |||||
} | |||||
$update = head($ref_updates); | |||||
$type_branch = PhabricatorRepositoryPushLog::REFTYPE_BRANCH; | |||||
if ($update->getRefType() != $type_branch) { | |||||
throw new DiffusionCommitHookRejectException( | |||||
pht( | |||||
'This push updates a virtual ref (%s), but does not push a '. | |||||
'branch to it. Virtual ref names are reserved and can only be '. | |||||
'used for branches.', | |||||
$name)); | |||||
} | |||||
$flags = $update->getChangeFlags(); | |||||
$flag_add = PhabricatorRepositoryPushLog::CHANGEFLAG_ADD; | |||||
$flag_delete = PhabricatorRepositoryPushLog::CHANGEFLAG_DELETE; | |||||
if ($flags & $flag_delete) { | |||||
// This is deleting a virtual branch, so let it through as a normal | |||||
// push. Most likely, this is cleaning up a mistake where a virtual | |||||
// branch was somehow made concrete. | |||||
return false; | |||||
} | |||||
if ($flags !== PhabricatorRepositoryPushLog::CHANGEFLAG_ADD) { | |||||
throw new DiffusionCommitHookRejectException( | |||||
pht( | |||||
'This push updates a virtual branch (%s). Pushes to virtual '. | |||||
'branches must create them, but this push does not. Usually, '. | |||||
'this means someone has accidentally created a real branch '. | |||||
'with this name. Verify the offending branch is safe to '. | |||||
'delete, remove it, and then try pushing again.', | |||||
$name)); | |||||
} | |||||
return true; | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
private function generateGitDiffForReview(PhabricatorRepositoryPushLog $ref) { | |||||
$old = $ref->getMergeBase(); | |||||
$new = $ref->getRefNew(); | |||||
// TODO: Duplication with arc. | |||||
$options = array( | |||||
// NOTE: This is not in `arc`. | |||||
'--binary', | |||||
'--no-ext-diff', | |||||
'--no-textconv', | |||||
'--no-color', | |||||
'--src-prefix=a/', | |||||
'--dst-prefix=b/', | |||||
'-U32767', | |||||
'-M', | |||||
'-C', | |||||
); | |||||
list($diff) = $this->getRepository()->execxLocalCommand( | |||||
'diff %Ls %s --', | |||||
$options, | |||||
$old.'..'.$new); | |||||
$changes = id(new ArcanistDiffParser())->parseDiff($diff); | |||||
return DifferentialDiff::newFromRawChanges($changes); | |||||
20after4Unsubmitted Not Done Inline ActionsThis applies cleanly to a recent version of stable, however, there is the bug mentioned above by @liudangyi. But that one is easy enough to resolve: return DifferentialDiff::newFromRawChanges($this->getViewer(), $changes); I wonder if there is a way to maintain this as some sort of extension if the upstream is not interested in merging it? 20after4: This applies cleanly to a recent version of stable, however, there is the bug mentioned above… | |||||
} | |||||
/* -( Custom )------------------------------------------------------------- */ | /* -( Custom )------------------------------------------------------------- */ | ||||
private function applyCustomHooks(array $updates) { | private function applyCustomHooks(array $updates) { | ||||
$args = $this->getOriginalArgv(); | $args = $this->getOriginalArgv(); | ||||
$stdin = $this->getStdin(); | $stdin = $this->getStdin(); | ||||
$console = PhutilConsole::getConsole(); | $console = PhutilConsole::getConsole(); | ||||
$env = array( | $env = array( | ||||
▲ Show 20 Lines • Show All 593 Lines • Show Last 20 Lines |
"fom": typo