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:
parent
fe5355e4e4
commit
2fd37a1728
7 changed files with 96 additions and 64 deletions
|
@ -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/"
|
||||||
|
|
|
@ -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.";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue