1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-11-24 15:52:40 +01:00

Automatically detect when to mark revisions committed

Summary:
See D945. We have this kludgy "remote_hooks_installed" mess right now, but we
have enough information on the server nowadays to figure this out without it.

Also reduce code duplication by sharing the "mark-committed" workflow.

This causes "arc merge" to effect commit marks.

Test Plan:
In Git, Mercurial and SVN working copies ran like a million
amend/merge/commit/mark-committed commands with and without --finalize in
various states of revision completion.

This change is really hard to exhaustively test because of the number of
combinations of VCS, revision state, command, command flags, repository state
and tracking state. All the reasonable tests I could come up with worked
correctly, though.

Reviewers: Makinde, jungejason, nh, tuomaspelkonen, aran

Reviewed By: jungejason

CC: aran, jungejason

Differential Revision: 967
This commit is contained in:
epriestley 2011-09-27 09:37:11 -07:00
parent fe5355e4e4
commit 2fd37a1728
7 changed files with 96 additions and 64 deletions

View file

@ -3,7 +3,6 @@
"conduit_uri" : "https://secure.phabricator.com/", "conduit_uri" : "https://secure.phabricator.com/",
"lint_engine" : "PhutilLintEngine", "lint_engine" : "PhutilLintEngine",
"unit_engine" : "PhutilUnitTestEngine", "unit_engine" : "PhutilUnitTestEngine",
"remote_hooks_installed" : true,
"copyright_holder" : "Facebook, Inc.", "copyright_holder" : "Facebook, Inc.",
"phutil_libraries" : { "phutil_libraries" : {
"arcanist" : "src/" "arcanist" : "src/"

View file

@ -490,4 +490,10 @@ EODIFF;
return false; return false;
} }
public function getFinalizedRevisionMessage() {
// In other VCSes we give push instructions here, but it never makes sense
// in SVN.
return "Done.";
}
} }

View file

@ -126,30 +126,15 @@ EOTEXT
$repository_api->amendGitHeadCommit($message); $repository_api->amendGitHeadCommit($message);
echo "Amended commit message.\n"; echo "Amended commit message.\n";
$working_copy = $this->getWorkingCopy();
$remote_hooks = $working_copy->getConfig('remote_hooks_installed', false);
if (!$remote_hooks) {
echo "According to .arcconfig, remote commit hooks are not installed ".
"for this project, so the revision will be marked committed now. ".
"Consult the documentation for instructions on installing hooks.".
"\n\n";
$mark_workflow = $this->buildChildWorkflow( $mark_workflow = $this->buildChildWorkflow(
'mark-committed', 'mark-committed',
array($revision_id)); array(
'--finalize',
$revision_id,
));
$mark_workflow->run(); $mark_workflow->run();
} }
$remote_message = ArcanistDifferentialCommitMessage::newFromRawCorpus(
$message);
$remote_message->pullDataFromConduit($conduit);
if ($remote_message->getFieldValue('reviewedByGUIDs') ||
$remote_message->getFieldValue('reviewedByPHIDs')) {
echo phutil_console_wrap(
"You may now push this commit upstream, as appropriate (e.g. with ".
"'git push', or 'git svn dcommit', or by printing and faxing it).\n");
}
}
return 0; return 0;
} }

View file

@ -129,18 +129,13 @@ EOTEXT
throw new Exception("Executing 'svn commit' failed!"); throw new Exception("Executing 'svn commit' failed!");
} }
$working_copy = $this->getWorkingCopy();
$remote_hooks = $working_copy->getConfig('remote_hooks_installed', false);
if (!$remote_hooks) {
echo "According to .arcconfig, remote commit hooks are not installed ".
"for this project, so the revision will be marked committed now. ".
"Consult the documentation for instructions on installing hooks.".
"\n\n";
$mark_workflow = $this->buildChildWorkflow( $mark_workflow = $this->buildChildWorkflow(
'mark-committed', 'mark-committed',
array($revision_id)); array(
'--finalize',
$revision_id,
));
$mark_workflow->run(); $mark_workflow->run();
}
return $err; return $err;
} }

View file

@ -57,19 +57,6 @@ EOTEXT
".arcconfig."); ".arcconfig.");
} }
if (!$working_copy->getConfig('remote_hooks_installed')) {
echo phutil_console_wrap(
"\n".
"NOTE: Arcanist is installed as a git pre-receive hook in the git ".
"remote you are pushing to, but the project's '.arcconfig' does not ".
"have the 'remote_hooks_installed' flag set. Until you set the flag, ".
"some code will run needlessly in both the local and remote, and ".
"revisions will be marked 'committed' in Differential when they are ".
"amended rather than when they are actually pushed to the remote ".
"origin.".
"\n\n");
}
// Git repositories have special rules in pre-receive hooks. We need to // Git repositories have special rules in pre-receive hooks. We need to
// construct the API against the .git directory instead of the project // construct the API against the .git directory instead of the project
// root or commands don't work properly. // root or commands don't work properly.

View file

@ -28,16 +28,23 @@ class ArcanistMarkCommittedWorkflow extends ArcanistBaseWorkflow {
**mark-committed** __revision__ **mark-committed** __revision__
Supports: git, svn Supports: git, svn
Manually mark a revision as committed. You should not normally need Manually mark a revision as committed. You should not normally need
to do this; arc commit (svn), arc amend (git) or commit hooks in the to do this; arc commit (svn), arc amend (git), arc merge (git, hg) or
master remote repository should do it for you. However, if these repository tracking on the master remote repository should do it for
mechanisms have failed for some reason you can use this command to you. However, if these mechanisms have failed for some reason you can
manually change a revision status from "Accepted" to "Committed". use this command to manually change a revision status from "Accepted"
to "Committed".
EOTEXT EOTEXT
); );
} }
public function getArguments() { public function getArguments() {
return array( return array(
'finalize' => array(
'help' =>
"Mark committed only if the repository is untracked and the ".
"revision is accepted. Continue even if the mark can't happen. This ".
"is a soft version of 'mark-committed' used by other workflows.",
),
'*' => 'revision', '*' => 'revision',
); );
} }
@ -50,7 +57,16 @@ EOTEXT
return true; return true;
} }
public function requiresRepositoryAPI() {
// NOTE: Technically we only use this to generate the right message at
// the end, and you can even get the wrong message (e.g., if you run
// "arc mark-committed D123" from a git repository, but D123 is an SVN
// revision). We could be smarter about this, but it's just display fluff.
return true;
}
public function run() { public function run() {
$is_finalize = $this->getArgument('finalize');
$conduit = $this->getConduit(); $conduit = $this->getConduit();
@ -73,6 +89,7 @@ EOTEXT
), ),
)); ));
$revision = null;
try { try {
$revision_id = reset($revision_list); $revision_id = reset($revision_list);
$revision_id = $this->normalizeRevisionID($revision_id); $revision_id = $this->normalizeRevisionID($revision_id);
@ -80,23 +97,61 @@ EOTEXT
$revision_data, $revision_data,
$revision_id); $revision_id);
} catch (ArcanistChooseInvalidRevisionException $ex) { } catch (ArcanistChooseInvalidRevisionException $ex) {
if (!$is_finalize) {
throw new ArcanistUsageException( throw new ArcanistUsageException(
"Revision D{$revision_id} is not committable. You can only mark ". "Revision D{$revision_id} is not committable. You can only mark ".
"revisions which have been 'accepted' as committed."); "revisions which have been 'accepted' as committed.");
} }
}
if ($revision) {
$actually_mark = true;
if ($is_finalize) {
$project_info = $conduit->callMethodSynchronous(
'arcanist.projectinfo',
array(
'name' => $this->getWorkingCopy()->getProjectID(),
));
if ($project_info['tracked']) {
$actually_mark = false;
}
}
if ($actually_mark) {
$revision_id = $revision->getID(); $revision_id = $revision->getID();
$revision_name = $revision->getName(); $revision_name = $revision->getName();
echo "Marking revision D{$revision_id} '{$revision_name}' committed...\n"; echo "Marking revision D{$revision_id} '{$revision_name}' ".
"committed...\n";
$conduit->callMethodSynchronous( $conduit->callMethodSynchronous(
'differential.markcommitted', 'differential.markcommitted',
array( array(
'revision_id' => $revision_id, 'revision_id' => $revision_id,
)); ));
}
}
$revision_info = $conduit->callMethodSynchronous(
'differential.getrevision',
array(
'revision_id' => $revision_id,
));
$status = $revision_info['statusName'];
if ($status == 'Accepted' || $status == 'Committed') {
// If this has already been attached to commits, don't show the
// "you can push this commit" message since we know it's been committed
// already.
$is_finalized = empty($revision_info['commits']);
} else {
$is_finalized = false;
}
if ($is_finalized) {
$message = $this->getRepositoryAPI()->getFinalizedRevisionMessage();
echo phutil_console_wrap($message)."\n";
} else {
echo "Done.\n"; echo "Done.\n";
}
return 0; return 0;
} }

View file

@ -144,15 +144,20 @@ EOTEXT
$repository_api->performLocalBranchMerge($branch, $message); $repository_api->performLocalBranchMerge($branch, $message);
echo "Merged '{$branch}'.\n"; echo "Merged '{$branch}'.\n";
$done_message = $repository_api->getFinalizedRevisionMessage(); $mark_workflow = $this->buildChildWorkflow(
echo phutil_console_wrap($done_message."\n"); 'mark-committed',
array(
'--finalize',
$revision_id,
));
$mark_workflow->run();
} }
return 0; return 0;
} }
protected function getSupportedRevisionControlSystems() { protected function getSupportedRevisionControlSystems() {
return array('git'); return array('git', 'hg');
} }
} }