1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-11-10 08:52:39 +01:00

Augment arc patch behavior

Summary:
under git, we now create a branch that is at the patch's base revision if we
know it or whatever the working copy happened to be at if we don't.   This diff
also adds the --nobranch flag to disable this new behavior.
Also added an --update flag.  When specified, we run the appropriate "update"
command in the VCS.  By default this is off.
Finally, tried to give the user more information about what the heck arc just
did to their working copy.

Test Plan:
// verify --update flag works
// -- git
Assume we are at HEAD and we got to HEAD from HEAD^1 via DX
git reset --hard <THE BEGINNING>
arc patch --update DX
// ...versus svn
Assume we are at HEAD and we got to HEAD from HEAD^1 via DX
svn checkout -r 1
arc patch --update DX
// ...versus hg
Assume we are at HEAD and we got to HEAD from HEAD^1 via DX
hg update -r 1
arc patch --update DX

// verify under git a nice branch is made
// -- test where we should get a good name
// -- test where we have a base revision to check out the branch at
Assume we are at HEAD and we got to HEAD from HEAD^1 via DX
git reset --hard HEAD^1
arc patch DX

// verify under git an "okay" branch is made if we can't get "nice"
// -- test where we should get a "bad" name
// -- test where we DON'T have a base revision to check out the branch at
git diff HEAD^1 > ~/example.patch
git reset --hard HEAD^1
arc patch --patch ~/example.patch

// verify --nobranch flag skips the test for git
Assume we are at HEAD and we got to HEAD from HEAD^1 via DX
git reset --head HEAD^1
arc patch --nobranch DX

Reviewers: epriestley

Reviewed By: epriestley

CC: aran

Maniphest Tasks: T479

Differential Revision: https://secure.phabricator.com/D1459
This commit is contained in:
Bob Trahan 2012-01-19 12:16:01 -08:00
parent 2c4eb00a12
commit a1a25f72f5

View file

@ -75,6 +75,16 @@ EOTEXT
'help' =>
"Apply changes from a git patchfile or unified patchfile.",
),
'update' => array(
'supports' => array(
'git', 'svn', 'hg'
),
'help' =>
"Update the local working copy before applying the patch.",
'conflicts' => array(
'nobranch' => true,
),
),
'nocommit' => array(
'supports' => array(
'git'
@ -83,6 +93,19 @@ EOTEXT
"Normally under git if the patch is successful the changes are ".
"committed to the working copy. This flag prevents the commit.",
),
'nobranch' => array(
'supports' => array(
'git'
),
'help' =>
"Normally under git a new branch is created and then the patch ".
"is applied and committed in the branch. This flag skips the ".
"branch creation step and applies and commits the patch to the ".
"current branch.",
'conflicts' => array(
'update' => true,
),
),
'force' => array(
'help' =>
"Do not run any sanity checks.",
@ -171,6 +194,114 @@ EOTEXT
return true;
}
private function shouldBranch() {
// git only for now
$repository_api = $this->getRepositoryAPI();
if (!($repository_api instanceof ArcanistGitAPI)) {
return false;
}
$no_branch = $this->getArgument('nobranch', false);
if ($no_branch) {
return false;
}
return true;
}
private function getBranchName(ArcanistBundle $bundle) {
$branch_name = null;
$repository_api = $this->getRepositoryAPI();
$revision_id = $bundle->getRevisionID();
if ($revision_id) {
$base_name = "D{$revision_id}";
} else {
$base_name = "Arcanist-created-branch";
}
$suffixes = array(null, '-1', '-2', '-3');
foreach ($suffixes as $suffix) {
$proposed_name = $base_name.$suffix;
list($err) = exec_manual(
'(cd %s; git rev-parse --verify %s)',
$repository_api->getPath(),
$proposed_name
);
// no error means git rev-parse found a branch
if (!$err) {
echo phutil_console_format(
"Branch name {$proposed_name} alread exists; trying a new name.\n"
);
continue;
} else {
$branch_name = $proposed_name;
break;
}
}
if (!$branch_name) {
throw new Exception(
"Arc was unable to automagically make a name for this patch. ".
"Please clean up your working copy and try again."
);
}
return $branch_name;
}
private function createBranch(ArcanistBundle $bundle) {
$branch_name = $this->getBranchName($bundle);
$repository_api = $this->getRepositoryAPI();
$base_revision = $bundle->getBaseRevision();
if ($base_revision) {
execx(
'(cd %s; git checkout -b %s %s)',
$repository_api->getPath(),
$branch_name,
$base_revision);
} else {
execx(
'(cd %s; git checkout -b %s)',
$repository_api->getPath(),
$branch_name);
}
echo phutil_console_format(
"Created and checked out branch {$branch_name}.\n"
);
}
private function shouldUpdateWorkingCopy() {
return $this->getArgument('update', false);
}
private function updateWorkingCopy() {
$repository_api = $this->getRepositoryAPI();
if ($repository_api instanceof ArcanistSubversionAPI) {
execx(
'(cd %s; svn up)',
$repository_api->getPath());
$message = "Updated to HEAD. ";
} else if ($repository_api instanceof ArcanistGitAPI) {
execx(
'(cd %s; git pull)',
$repository_api->getPath());
$message = "Updated to HEAD. ";
} else if ($repository_api instanceof ArcanistMercurialAPI) {
execx(
'(cd %s; hg up)',
$repository_api->getPath());
$message = "Updated to tip. ";
} else {
throw new Exception('Unknown version control system.');
}
echo phutil_console_format($message."\n");
}
public function run() {
$source = $this->getSource();
@ -215,6 +346,15 @@ EOTEXT
}
}
// we should update the working copy before we do ANYTHING else
if ($this->shouldUpdateWorkingCopy()) {
$this->updateWorkingCopy();
}
if ($this->shouldBranch()) {
$this->createBranch($bundle);
}
$force = $this->getArgument('force', false);
if ($force) {
// force means don't do any sanity checks about the patch
@ -405,8 +545,8 @@ EOTEXT
if ($patch_err == 0) {
echo phutil_console_format(
"<bg:green>** OKAY **</bg> Successfully applied patch to the ".
"working copy.\n");
"<bg:green>** OKAY **</bg> Successfully applied patch ".
"to the working copy.\n");
} else {
echo phutil_console_format(
"\n\n<bg:yellow>** WARNING **</bg> Some hunks could not be applied ".