Commit db195990 authored by epriestley's avatar epriestley

(stable) Promote 2019 Week 44

parents 79ec6e44 cc1ff388
This diff is collapsed.
...@@ -13,6 +13,8 @@ abstract class ArcanistLandEngine extends Phobject { ...@@ -13,6 +13,8 @@ abstract class ArcanistLandEngine extends Phobject {
private $shouldSquash; private $shouldSquash;
private $shouldDeleteRemote; private $shouldDeleteRemote;
private $shouldPreview; private $shouldPreview;
private $remoteArgument;
private $ontoArgument;
// TODO: This is really grotesque. // TODO: This is really grotesque.
private $buildMessageCallback; private $buildMessageCallback;
...@@ -117,6 +119,25 @@ abstract class ArcanistLandEngine extends Phobject { ...@@ -117,6 +119,25 @@ abstract class ArcanistLandEngine extends Phobject {
return $this->commitMessageFile; return $this->commitMessageFile;
} }
final public function setRemoteArgument($remote_argument) {
$this->remoteArgument = $remote_argument;
return $this;
}
final public function getRemoteArgument() {
return $this->remoteArgument;
}
final public function setOntoArgument($onto_argument) {
$this->ontoArgument = $onto_argument;
return $this;
}
final public function getOntoArgument() {
return $this->ontoArgument;
}
abstract public function parseArguments();
abstract public function execute(); abstract public function execute();
abstract protected function getLandingCommits(); abstract protected function getLandingCommits();
......
...@@ -464,15 +464,27 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI { ...@@ -464,15 +464,27 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
*/ */
public function getFullGitDiff($base, $head = null) { public function getFullGitDiff($base, $head = null) {
$options = $this->getDiffFullOptions(); $options = $this->getDiffFullOptions();
$config_options = array();
// See T13432. Disable the rare "diff.suppressBlankEmpty" configuration
// option, which discards the " " (space) change type prefix on unchanged
// blank lines. At time of writing the parser does not handle these
// properly, but generating a more-standard diff is generally desirable
// even if a future parser handles this case more gracefully.
$config_options[] = '-c';
$config_options[] = 'diff.suppressBlankEmpty=false';
if ($head !== null) { if ($head !== null) {
list($stdout) = $this->execxLocal( list($stdout) = $this->execxLocal(
"diff {$options} %s %s --", "%LR diff {$options} %s %s --",
$config_options,
$base, $base,
$head); $head);
} else { } else {
list($stdout) = $this->execxLocal( list($stdout) = $this->execxLocal(
"diff {$options} %s --", "%LR diff {$options} %s --",
$config_options,
$base); $base);
} }
...@@ -1550,4 +1562,31 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI { ...@@ -1550,4 +1562,31 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
return $path; return $path;
} }
public function isPerforceRemote($remote_name) {
// See T13434. In Perforce workflows, "git p4 clone" creates "p4" refs
// under "refs/remotes/", but does not define a real remote named "p4".
// We treat this remote as though it were a real remote during "arc land",
// but it does not respond to commands like "git remote show p4", so we
// need to handle it specially.
if ($remote_name !== 'p4') {
return false;
}
$remote_dir = $this->getMetadataPath().'/refs/remotes/p4';
if (!Filesystem::pathExists($remote_dir)) {
return false;
}
return true;
}
public function isPushableRemote($remote_name) {
list($err, $stdout) = $this->execManualLocal(
'remote get-url --push -- %s',
$remote_name);
return !$err;
}
} }
...@@ -44,10 +44,10 @@ EOTEXT ...@@ -44,10 +44,10 @@ EOTEXT
public function getCommandHelp() { public function getCommandHelp() {
return phutil_console_format(<<<EOTEXT return phutil_console_format(<<<EOTEXT
Supports: git, hg Supports: git, git/p4, hg
Publish an accepted revision after review. This command is the last Publish an accepted revision after review. This command is the last
step in the standard Differential pre-publish code review workflow. step in the standard Differential code review workflow.
This command merges and pushes changes associated with an accepted This command merges and pushes changes associated with an accepted
revision that are currently sitting in __ref__, which is usually the revision that are currently sitting in __ref__, which is usually the
...@@ -57,6 +57,9 @@ EOTEXT ...@@ -57,6 +57,9 @@ EOTEXT
Under Git: branches, tags, and arbitrary commits (detached HEADs) Under Git: branches, tags, and arbitrary commits (detached HEADs)
may be landed. may be landed.
Under Git/Perforce: branches, tags, and arbitrary commits may
be submitted.
Under Mercurial: branches and bookmarks may be landed, but only Under Mercurial: branches and bookmarks may be landed, but only
onto a target of the same type. See T3855. onto a target of the same type. See T3855.
...@@ -66,7 +69,8 @@ EOTEXT ...@@ -66,7 +69,8 @@ EOTEXT
A target branch is selected by examining these sources in order: A target branch is selected by examining these sources in order:
- the **--onto** flag; - the **--onto** flag;
- the upstream of the current branch, recursively (Git only); - the upstream of the branch targeted by the land operation,
recursively (Git only);
- the __arc.land.onto.default__ configuration setting; - the __arc.land.onto.default__ configuration setting;
- or by falling back to a standard default: - or by falling back to a standard default:
- "master" in Git; - "master" in Git;
...@@ -76,6 +80,8 @@ EOTEXT ...@@ -76,6 +80,8 @@ EOTEXT
- the **--remote** flag; - the **--remote** flag;
- the upstream of the current branch, recursively (Git only); - the upstream of the current branch, recursively (Git only);
- the special "p4" remote which indicates a repository has
been synchronized with Perforce (Git only);
- or by falling back to a standard default: - or by falling back to a standard default:
- "origin" in Git; - "origin" in Git;
- the default remote in Mercurial. - the default remote in Mercurial.
...@@ -159,7 +165,7 @@ EOTEXT ...@@ -159,7 +165,7 @@ EOTEXT
'remote' => array( 'remote' => array(
'param' => 'origin', 'param' => 'origin',
'help' => pht( 'help' => pht(
"Push to a remote other than the default ('origin' in git)."), 'Push to a remote other than the default.'),
), ),
'merge' => array( 'merge' => array(
'help' => pht( 'help' => pht(
...@@ -224,23 +230,36 @@ EOTEXT ...@@ -224,23 +230,36 @@ EOTEXT
} }
if ($engine) { if ($engine) {
$this->readEngineArguments();
$this->requireCleanWorkingCopy();
$should_hold = $this->getArgument('hold'); $should_hold = $this->getArgument('hold');
$remote_arg = $this->getArgument('remote');
$onto_arg = $this->getArgument('onto');
$engine $engine
->setWorkflow($this) ->setWorkflow($this)
->setRepositoryAPI($this->getRepositoryAPI()) ->setRepositoryAPI($this->getRepositoryAPI())
->setSourceRef($this->branch) ->setSourceRef($this->branch)
->setTargetRemote($this->remote)
->setTargetOnto($this->onto)
->setShouldHold($should_hold) ->setShouldHold($should_hold)
->setShouldKeep($this->keepBranch) ->setShouldKeep($this->keepBranch)
->setShouldSquash($this->useSquash) ->setShouldSquash($this->useSquash)
->setShouldPreview($this->preview) ->setShouldPreview($this->preview)
->setRemoteArgument($remote_arg)
->setOntoArgument($onto_arg)
->setBuildMessageCallback(array($this, 'buildEngineMessage')); ->setBuildMessageCallback(array($this, 'buildEngineMessage'));
// The goal here is to raise errors with flags early (which is cheap),
// before we test if the working copy is clean (which can be slow). This
// could probably be structured more cleanly.
$engine->parseArguments();
// This must be configured or we fail later inside "buildEngineMessage()".
// This is less than ideal.
$this->ontoRemoteBranch = sprintf(
'%s/%s',
$engine->getTargetRemote(),
$engine->getTargetOnto());
$this->requireCleanWorkingCopy();
$engine->execute(); $engine->execute();
if (!$should_hold && !$this->preview) { if (!$should_hold && !$this->preview) {
...@@ -337,123 +356,6 @@ EOTEXT ...@@ -337,123 +356,6 @@ EOTEXT
return $refspec; return $refspec;
} }
private function readEngineArguments() {
// NOTE: This is hard-coded for Git right now.
// TODO: Clean this up and move it into LandEngines.
$onto = $this->getEngineOnto();
$remote = $this->getEngineRemote();
// This just overwrites work we did earlier, but it has to be up in this
// class for now because other parts of the workflow still depend on it.
$this->onto = $onto;
$this->remote = $remote;
$this->ontoRemoteBranch = $this->remote.'/'.$onto;
}
private function getEngineOnto() {
$onto = $this->getArgument('onto');
if ($onto !== null) {
$this->writeInfo(
pht('TARGET'),
pht(
'Landing onto "%s", selected by the --onto flag.',
$onto));
return $onto;
}
$api = $this->getRepositoryAPI();
$path = $api->getPathToUpstream($this->branch);
if ($path->getLength()) {
$cycle = $path->getCycle();
if ($cycle) {
$this->writeWarn(
pht('LOCAL CYCLE'),
pht(
'Local branch tracks an upstream, but following it leads to a '.
'local cycle; ignoring branch upstream.'));
echo tsprintf(
"\n %s\n\n",
implode(' -> ', $cycle));
} else {
if ($path->isConnectedToRemote()) {
$onto = $path->getRemoteBranchName();
$this->writeInfo(
pht('TARGET'),
pht(
'Landing onto "%s", selected by following tracking branches '.
'upstream to the closest remote.',
$onto));
return $onto;
} else {
$this->writeInfo(
pht('NO PATH TO UPSTREAM'),
pht(
'Local branch tracks an upstream, but there is no path '.
'to a remote; ignoring branch upstream.'));
}
}
}
$config_key = 'arc.land.onto.default';
$onto = $this->getConfigFromAnySource($config_key);
if ($onto !== null) {
$this->writeInfo(
pht('TARGET'),
pht(
'Landing onto "%s", selected by "%s" configuration.',
$onto,
$config_key));
return $onto;
}
$onto = 'master';
$this->writeInfo(
pht('TARGET'),
pht(
'Landing onto "%s", the default target under git.',
$onto));
return $onto;
}
private function getEngineRemote() {
$remote = $this->getArgument('remote');
if ($remote !== null) {
$this->writeInfo(
pht('REMOTE'),
pht(
'Using remote "%s", selected by the --remote flag.',
$remote));
return $remote;
}
$api = $this->getRepositoryAPI();
$path = $api->getPathToUpstream($this->branch);
$remote = $path->getRemoteRemoteName();
if ($remote !== null) {
$this->writeInfo(
pht('REMOTE'),
pht(
'Using remote "%s", selected by following tracking branches '.
'upstream to the closest remote.',
$remote));
return $remote;
}
$remote = 'origin';
$this->writeInfo(
pht('REMOTE'),
pht(
'Using remote "%s", the default remote under git.',
$remote));
return $remote;
}
private function readArguments() { private function readArguments() {
$repository_api = $this->getRepositoryAPI(); $repository_api = $this->getRepositoryAPI();
$this->isGit = $repository_api instanceof ArcanistGitAPI; $this->isGit = $repository_api instanceof ArcanistGitAPI;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment