Changeset View
Changeset View
Standalone View
Standalone View
src/land/engine/ArcanistLandEngine.php
Show First 20 Lines • Show All 829 Lines • ▼ Show 20 Lines | final protected function loadRevisionRefs(array $commit_map) { | ||||
$workflow->loadHardpoints( | $workflow->loadHardpoints( | ||||
$state_refs, | $state_refs, | ||||
ArcanistWorkingCopyStateRef::HARDPOINT_REVISIONREFS); | ArcanistWorkingCopyStateRef::HARDPOINT_REVISIONREFS); | ||||
foreach ($commit_map as $commit) { | foreach ($commit_map as $commit) { | ||||
$hash = $commit->getHash(); | $hash = $commit->getHash(); | ||||
$state_ref = $state_refs[$hash]; | $state_ref = $state_refs[$hash]; | ||||
$revision_refs = $state_ref->getRevisionRefs(); | $revision_refs = $state_ref->getRevisionRefs(); | ||||
$commit->setRelatedRevisionRefs($revision_refs); | |||||
} | |||||
// For commits which have exactly one related revision, select it now. | |||||
// If we have several possible revisions but one of them matches the | foreach ($commit_map as $commit) { | ||||
// "--revision" argument, just select it. This is relatively safe and | $revision_refs = $commit->getRelatedRevisionRefs(); | ||||
// reasonable and doesn't need a warning. | |||||
if (count($revision_refs) !== 1) { | |||||
continue; | |||||
} | |||||
$revision_ref = head($revision_refs); | |||||
$commit->setExplicitRevisionRef($revision_ref); | |||||
} | |||||
// If we have a "--revision", select that revision for any commits with | |||||
// no known related revisions. | |||||
// Also select that revision for any commits which have several possible | |||||
// revisions including that revision. This is relatively safe and | |||||
// reasonable and doesn't require a warning. | |||||
if ($force_ref) { | if ($force_ref) { | ||||
if (count($revision_refs) > 1) { | $force_phid = $force_ref->getPHID(); | ||||
foreach ($revision_refs as $revision_ref) { | foreach ($commit_map as $commit) { | ||||
if ($revision_ref->getPHID() === $force_ref->getPHID()) { | if ($commit->getExplicitRevisionRef()) { | ||||
$revision_refs = array($revision_ref); | continue; | ||||
break; | } | ||||
$revision_refs = $commit->getRelatedRevisionRefs(); | |||||
if ($revision_refs) { | |||||
$revision_refs = mpull($revision_refs, null, 'getPHID'); | |||||
if (!isset($revision_refs[$force_phid])) { | |||||
continue; | |||||
} | } | ||||
} | } | ||||
$commit->setExplicitRevisionRef($force_ref); | |||||
} | } | ||||
} | } | ||||
if (count($revision_refs) === 1) { | // If we have a "--revision", identify any commits which it is not yet | ||||
$revision_ref = head($revision_refs); | // selected for. These are commits which are not associated with the | ||||
$commit->setExplicitRevisionRef($revision_ref); | // identified revision but are associated with one or more other revisions. | ||||
if ($force_ref) { | |||||
$force_phid = $force_ref->getPHID(); | |||||
$confirm_force = array(); | |||||
foreach ($commit_map as $key => $commit) { | |||||
$revision_ref = $commit->getExplicitRevisionRef(); | |||||
if (!$revision_ref) { | |||||
continue; | continue; | ||||
} | } | ||||
if (!$revision_refs) { | if ($revision_ref->getPHID() === $force_phid) { | ||||
continue; | continue; | ||||
} | } | ||||
// TODO: If we have several refs but all but one are abandoned or closed | $confirm_force[] = $commit; | ||||
// or authored by someone else, we could guess what you mean. | } | ||||
if ($confirm_force) { | |||||
// TODO: Make this more clear. | |||||
// TODO: Show all the commits. | |||||
throw new PhutilArgumentUsageException( | |||||
pht( | |||||
'TODO: You are forcing a revision, but commits are associated '. | |||||
'with some other revision. Are you REALLY sure you want to land '. | |||||
'ALL these commits wiht a different unrelated revision???')); | |||||
} | |||||
foreach ($confirm_force as $commit) { | |||||
$commit->setExplicitRevisionRef($force_ref); | |||||
} | |||||
} | |||||
// Finally, raise an error if we're left with ambiguous revisions. This | |||||
// happens when we have no "--revision" and some commits in the range | |||||
// that are associated with more than one revision. | |||||
$ambiguous = array(); | |||||
foreach ($commit_map as $commit) { | |||||
if ($commit->getExplicitRevisionRef()) { | |||||
continue; | |||||
} | |||||
if (!$commit->getRelatedRevisionRefs()) { | |||||
continue; | |||||
} | |||||
$ambiguous[] = $commit; | |||||
} | |||||
if ($ambiguous) { | |||||
foreach ($ambiguous as $commit) { | |||||
$symbols = $commit->getIndirectSymbols(); | $symbols = $commit->getIndirectSymbols(); | ||||
$raw_symbols = mpull($symbols, 'getSymbol'); | $raw_symbols = mpull($symbols, 'getSymbol'); | ||||
$symbol_list = implode(', ', $raw_symbols); | $symbol_list = implode(', ', $raw_symbols); | ||||
$display_hash = $this->getDisplayHash($hash); | $display_hash = $this->getDisplayHash($hash); | ||||
$revision_refs = $commit->getRelatedRevisionRefs(); | |||||
// TODO: Include "use 'arc look --type commit abc' to figure out why" | // TODO: Include "use 'arc look --type commit abc' to figure out why" | ||||
// once that works? | // once that works? | ||||
// TODO: We could print all the ambiguous commits. | |||||
// TODO: Suggest "--pick" as a remedy once it exists? | |||||
echo tsprintf( | echo tsprintf( | ||||
"\n%!\n%W\n\n", | "\n%!\n%W\n\n", | ||||
pht('AMBIGUOUS REVISION'), | pht('AMBIGUOUS REVISION'), | ||||
pht( | pht( | ||||
'The revision associated with commit "%s" (an ancestor of: %s) '. | 'The revision associated with commit "%s" (an ancestor of: %s) '. | ||||
'is ambiguous. These %s revision(s) are associated with the commit:', | 'is ambiguous. These %s revision(s) are associated with the '. | ||||
'commit:', | |||||
$display_hash, | $display_hash, | ||||
implode(', ', $raw_symbols), | implode(', ', $raw_symbols), | ||||
phutil_count($revision_refs))); | phutil_count($revision_refs))); | ||||
foreach ($revision_refs as $revision_ref) { | foreach ($revision_refs as $revision_ref) { | ||||
echo tsprintf( | echo tsprintf( | ||||
'%s', | '%s', | ||||
$revision_ref->newDisplayRef()); | $revision_ref->newDisplayRef()); | ||||
} | } | ||||
echo tsprintf("\n"); | echo tsprintf("\n"); | ||||
throw new PhutilArgumentUsageException( | throw new PhutilArgumentUsageException( | ||||
pht( | pht( | ||||
'Revision for commit "%s" is ambiguous. Use "--revision" to force '. | 'Revision for commit "%s" is ambiguous. Use "--revision" to force '. | ||||
'selection of a particular revision.', | 'selection of a particular revision.', | ||||
$display_hash)); | $display_hash)); | ||||
} | } | ||||
if ($force_ref) { | |||||
$phid_map = array(); | |||||
foreach ($commit_map as $commit) { | |||||
$explicit_ref = $commit->getExplicitRevisionRef(); | |||||
if ($explicit_ref) { | |||||
$revision_phid = $explicit_ref->getPHID(); | |||||
$phid_map[$revision_phid] = $revision_phid; | |||||
} | |||||
} | |||||
$force_phid = $force_ref->getPHID(); | |||||
// If none of the commits have a revision, forcing the revision is | |||||
// reasonable and we don't need to confirm it. | |||||
// If some of the commits have a revision, but it's the same as the | |||||
// revision we're forcing, forcing the revision is also reasonable. | |||||
// Discard the revision we're trying to force, then check if there's | |||||
// anything left. If some of the commits have a different revision, | |||||
// make sure the user is really doing what they expect. | |||||
unset($phid_map[$force_phid]); | |||||
if ($phid_map) { | |||||
// TODO: Make this more clear. | |||||
throw new PhutilArgumentUsageException( | |||||
pht( | |||||
'TODO: You are forcing a revision, but commits are associated '. | |||||
'with some other revision. Are you REALLY sure you want to land '. | |||||
'ALL these commits wiht a different unrelated revision???')); | |||||
} | } | ||||
foreach ($commit_map as $commit) { | // NOTE: We may exit this method with commits that are still unassociated. | ||||
$commit->setExplicitRevisionRef($force_ref); | // These will be handled later by the "implicit commits" mechanism. | ||||
} | |||||
} | |||||
} | } | ||||
final protected function getDisplayHash($hash) { | final protected function getDisplayHash($hash) { | ||||
// TODO: This should be on the API object. | // TODO: This should be on the API object. | ||||
return substr($hash, 0, 12); | return substr($hash, 0, 12); | ||||
} | } | ||||
final protected function confirmCommits( | final protected function confirmCommits( | ||||
▲ Show 20 Lines • Show All 547 Lines • Show Last 20 Lines |