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 {
private $shouldSquash;
private $shouldDeleteRemote;
private $shouldPreview;
private $remoteArgument;
private $ontoArgument;
// TODO: This is really grotesque.
private $buildMessageCallback;
......@@ -117,6 +119,25 @@ abstract class ArcanistLandEngine extends Phobject {
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 protected function getLandingCommits();
......
......@@ -464,15 +464,27 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
*/
public function getFullGitDiff($base, $head = null) {
$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) {
list($stdout) = $this->execxLocal(
"diff {$options} %s %s --",
"%LR diff {$options} %s %s --",
$config_options,
$base,
$head);
} else {
list($stdout) = $this->execxLocal(
"diff {$options} %s --",
"%LR diff {$options} %s --",
$config_options,
$base);
}
......@@ -1550,4 +1562,31 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
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
public function getCommandHelp() {
return phutil_console_format(<<<EOTEXT
Supports: git, hg
Supports: git, git/p4, hg
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
revision that are currently sitting in __ref__, which is usually the
......@@ -57,6 +57,9 @@ EOTEXT
Under Git: branches, tags, and arbitrary commits (detached HEADs)
may be landed.
Under Git/Perforce: branches, tags, and arbitrary commits may
be submitted.
Under Mercurial: branches and bookmarks may be landed, but only
onto a target of the same type. See T3855.
......@@ -66,7 +69,8 @@ EOTEXT
A target branch is selected by examining these sources in order:
- 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;
- or by falling back to a standard default:
- "master" in Git;
......@@ -76,6 +80,8 @@ EOTEXT
- the **--remote** flag;
- 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:
- "origin" in Git;
- the default remote in Mercurial.
......@@ -159,7 +165,7 @@ EOTEXT
'remote' => array(
'param' => 'origin',
'help' => pht(
"Push to a remote other than the default ('origin' in git)."),
'Push to a remote other than the default.'),
),
'merge' => array(
'help' => pht(
......@@ -224,23 +230,36 @@ EOTEXT
}
if ($engine) {
$this->readEngineArguments();
$this->requireCleanWorkingCopy();
$should_hold = $this->getArgument('hold');
$remote_arg = $this->getArgument('remote');
$onto_arg = $this->getArgument('onto');
$engine
->setWorkflow($this)
->setRepositoryAPI($this->getRepositoryAPI())
->setSourceRef($this->branch)
->setTargetRemote($this->remote)
->setTargetOnto($this->onto)
->setShouldHold($should_hold)
->setShouldKeep($this->keepBranch)
->setShouldSquash($this->useSquash)
->setShouldPreview($this->preview)
->setRemoteArgument($remote_arg)
->setOntoArgument($onto_arg)
->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();
if (!$should_hold && !$this->preview) {
......@@ -337,123 +356,6 @@ EOTEXT
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() {
$repository_api = $this->getRepositoryAPI();
$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