1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-27 01:02:42 +01:00

Make "Land Revision" show merge conflicts more clearly

Summary:
Ref T182. We just show "an error happened" right now. Improve this behavior.

This error handling chain is a bit ad-hoc for now but we can formalize it as we hit other cases.

Test Plan:
{F910247}

{F910248}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T182

Differential Revision: https://secure.phabricator.com/D14343
This commit is contained in:
epriestley 2015-10-26 20:11:21 +00:00 committed by epriestley
parent 2326d5f8d0
commit 0b24a6e200
4 changed files with 153 additions and 10 deletions

View file

@ -3,6 +3,8 @@
final class DrydockWorkingCopyBlueprintImplementation
extends DrydockBlueprintImplementation {
const PHASE_SQUASHMERGE = 'squashmerge';
public function isEnabled() {
return true;
}
@ -288,7 +290,7 @@ final class DrydockWorkingCopyBlueprintImplementation
$merges = idx($spec, 'merges');
if ($merges) {
foreach ($merges as $merge) {
$this->applyMerge($interface, $merge);
$this->applyMerge($lease, $interface, $merge);
}
}
@ -416,6 +418,7 @@ final class DrydockWorkingCopyBlueprintImplementation
}
private function applyMerge(
DrydockLease $lease,
DrydockCommandInterface $interface,
array $merge) {
@ -428,15 +431,48 @@ final class DrydockWorkingCopyBlueprintImplementation
$src_ref,
$src_ref);
try {
$interface->execx(
'git merge --no-stat --squash --ff-only -- %s',
$command = csprintf(
'git merge --no-stat --squash --ff-only -- %R',
$src_ref);
try {
$interface->execx('%C', $command);
} catch (CommandException $ex) {
// TODO: Specifically note this as a merge conflict.
$this->setWorkingCopyVCSErrorFromCommandException(
$lease,
self::PHASE_SQUASHMERGE,
$command,
$ex);
throw $ex;
}
}
protected function setWorkingCopyVCSErrorFromCommandException(
DrydockLease $lease,
$phase,
$command,
CommandException $ex) {
$error = array(
'phase' => $phase,
'command' => (string)$command,
'raw' => (string)$ex->getCommand(),
'err' => $ex->getError(),
'stdout' => $ex->getStdout(),
'stderr' => $ex->getStderr(),
);
$lease->setAttribute('workingcopy.vcs.error', $error);
}
public function getWorkingCopyVCSError(DrydockLease $lease) {
$error = $lease->getAttribute('workingcopy.vcs.error');
if (!$error) {
return null;
} else {
return $error;
}
}
}

View file

@ -175,6 +175,14 @@ final class DrydockRepositoryOperation extends DrydockDAO
return $this->getProperty('exec.leasePHID');
}
public function setWorkingCopyVCSError(array $error) {
return $this->setProperty('exec.workingcopy.error', $error);
}
public function getWorkingCopyVCSError() {
return $this->getProperty('exec.workingcopy.error');
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */

View file

@ -73,12 +73,104 @@ final class DrydockRepositoryOperationStatusView
if ($state != DrydockRepositoryOperation::STATE_FAIL) {
$item->addAttribute($operation->getOperationCurrentStatus($viewer));
} else {
// TODO: Make this more useful.
$vcs_error = $operation->getWorkingCopyVCSError();
if ($vcs_error) {
switch ($vcs_error['phase']) {
case DrydockWorkingCopyBlueprintImplementation::PHASE_SQUASHMERGE:
$message = pht(
'This change did not merge cleanly. This usually indicates '.
'that the change is out of date and needs to be updated.');
break;
default:
$message = pht(
'Operation encountered an error while performing repository '.
'operations.');
break;
}
$item->addAttribute($message);
$table = $this->renderVCSErrorTable($vcs_error);
list($links, $info) = $this->renderDetailToggles($table);
$item->addAttribute($links);
$item->appendChild($info);
} else {
$item->addAttribute(pht('Operation encountered an error.'));
}
}
return id(new PHUIObjectItemListView())
->addItem($item);
}
private function renderVCSErrorTable(array $vcs_error) {
$rows = array();
$rows[] = array(pht('Command'), $vcs_error['command']);
$rows[] = array(pht('Error'), $vcs_error['err']);
$rows[] = array(pht('Stdout'), $vcs_error['stdout']);
$rows[] = array(pht('Stderr'), $vcs_error['stderr']);
$table = id(new AphrontTableView($rows))
->setColumnClasses(
array(
'header',
'wide',
));
return $table;
}
private function renderDetailToggles(AphrontTableView $table) {
$show_id = celerity_generate_unique_node_id();
$hide_id = celerity_generate_unique_node_id();
$info_id = celerity_generate_unique_node_id();
Javelin::initBehavior('phabricator-reveal-content');
$show_details = javelin_tag(
'a',
array(
'id' => $show_id,
'href' => '#',
'sigil' => 'reveal-content',
'mustcapture' => true,
'meta' => array(
'hideIDs' => array($show_id),
'showIDs' => array($hide_id, $info_id),
),
),
pht('Show Details'));
$hide_details = javelin_tag(
'a',
array(
'id' => $hide_id,
'href' => '#',
'sigil' => 'reveal-content',
'mustcapture' => true,
'style' => 'display: none',
'meta' => array(
'hideIDs' => array($hide_id, $info_id),
'showIDs' => array($show_id),
),
),
pht('Hide Details'));
$info = javelin_tag(
'div',
array(
'id' => $info_id,
'style' => 'display: none',
),
$table);
$links = array(
$show_details,
$hide_details,
);
return array($links, $info);
}
}

View file

@ -90,6 +90,9 @@ final class DrydockRepositoryOperationUpdateWorker
// TODO: This is very similar to leasing in Harbormaster, maybe we can
// share some of the logic?
$working_copy = new DrydockWorkingCopyBlueprintImplementation();
$working_copy_type = $working_copy->getType();
$lease_phid = $operation->getProperty('exec.leasePHID');
if ($lease_phid) {
$lease = id(new DrydockLeaseQuery())
@ -103,9 +106,6 @@ final class DrydockRepositoryOperationUpdateWorker
$lease_phid));
}
} else {
$working_copy_type = id(new DrydockWorkingCopyBlueprintImplementation())
->getType();
$repository = $operation->getRepository();
$allowed_phids = $repository->getAutomationBlueprintPHIDs();
@ -138,6 +138,13 @@ final class DrydockRepositoryOperationUpdateWorker
}
if (!$lease->isActive()) {
$vcs_error = $working_copy->getWorkingCopyVCSError($lease);
if ($vcs_error) {
$operation
->setWorkingCopyVCSError($vcs_error)
->save();
}
throw new PhabricatorWorkerPermanentFailureException(
pht(
'Lease "%s" never activated.',