mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-21 22:32:41 +01:00
Identify published commits in working copies by using remote configuration
Summary: Ref T13546. When running "arc branches", we want to show all unpublished commits. This is often a different set of commits than "commits not present in any remote". Attempt to identify published commits by using the permanent ref rules in Phabricator. Test Plan: Ran "arc look published", saw sensible published commits in Git. Maniphest Tasks: T13546 Differential Revision: https://secure.phabricator.com/D21378
This commit is contained in:
parent
50f7a853b5
commit
80f5166b70
8 changed files with 185 additions and 3 deletions
|
@ -108,4 +108,39 @@ final class ArcanistRepositoryRef
|
||||||
return $branch;
|
return $branch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isPermanentRef(ArcanistMarkerRef $ref) {
|
||||||
|
$rules = idxv(
|
||||||
|
$this->parameters,
|
||||||
|
array('fields', 'refRules', 'permanentRefRules'));
|
||||||
|
|
||||||
|
if ($rules === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the rules exist but there are no specified rules, treat every ref
|
||||||
|
// as permanent.
|
||||||
|
if (!$rules) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: It would be nice to unify evaluation of permanent ref rules
|
||||||
|
// across Arcanist and Phabricator.
|
||||||
|
|
||||||
|
$ref_name = $ref->getName();
|
||||||
|
foreach ($rules as $rule) {
|
||||||
|
$matches = null;
|
||||||
|
if (preg_match('(^regexp\\((.*)\\)\z)', $rule, $matches)) {
|
||||||
|
if (preg_match($matches[1], $ref_name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($rule === $ref_name) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1773,4 +1773,47 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
|
||||||
$uri);
|
$uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function newPublishedCommitHashes() {
|
||||||
|
$remotes = $this->newRemoteRefQuery()
|
||||||
|
->execute();
|
||||||
|
if (!$remotes) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$markers = $this->newMarkerRefQuery()
|
||||||
|
->withIsRemoteCache(true)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
if (!$markers) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$runtime = $this->getRuntime();
|
||||||
|
$workflow = $runtime->getCurrentWorkflow();
|
||||||
|
|
||||||
|
$workflow->loadHardpoints(
|
||||||
|
$remotes,
|
||||||
|
ArcanistRemoteRef::HARDPOINT_REPOSITORYREFS);
|
||||||
|
|
||||||
|
$remotes = mpull($remotes, null, 'getRemoteName');
|
||||||
|
|
||||||
|
$hashes = array();
|
||||||
|
|
||||||
|
foreach ($markers as $marker) {
|
||||||
|
$remote_name = $marker->getRemoteName();
|
||||||
|
$remote = idx($remotes, $remote_name);
|
||||||
|
if (!$remote) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$remote->isPermanentRef($marker)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$hashes[] = $marker->getCommitHash();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $hashes;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -807,4 +807,12 @@ abstract class ArcanistRepositoryAPI extends Phobject {
|
||||||
return $uri;
|
return $uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final public function getPublishedCommitHashes() {
|
||||||
|
return $this->newPublishedCommitHashes();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newPublishedCommitHashes() {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,11 +23,11 @@ final class ArcanistGitRepositoryMarkerQuery
|
||||||
$branch_prefix = 'refs/heads/';
|
$branch_prefix = 'refs/heads/';
|
||||||
$branch_length = strlen($branch_prefix);
|
$branch_length = strlen($branch_prefix);
|
||||||
|
|
||||||
// NOTE: Since we only return branches today, we restrict this operation
|
$remote_prefix = 'refs/remotes/';
|
||||||
// to branches.
|
$remote_length = strlen($remote_prefix);
|
||||||
|
|
||||||
list($stdout) = $api->newFuture(
|
list($stdout) = $api->newFuture(
|
||||||
'for-each-ref --format %s -- refs/heads/',
|
'for-each-ref --format %s -- refs/',
|
||||||
implode('%01', $field_list))->resolve();
|
implode('%01', $field_list))->resolve();
|
||||||
|
|
||||||
$markers = array();
|
$markers = array();
|
||||||
|
@ -53,9 +53,20 @@ final class ArcanistGitRepositoryMarkerQuery
|
||||||
|
|
||||||
list($ref, $hash, $epoch, $tree, $dst_hash, $summary, $text) = $fields;
|
list($ref, $hash, $epoch, $tree, $dst_hash, $summary, $text) = $fields;
|
||||||
|
|
||||||
|
$remote_name = null;
|
||||||
|
|
||||||
if (!strncmp($ref, $branch_prefix, $branch_length)) {
|
if (!strncmp($ref, $branch_prefix, $branch_length)) {
|
||||||
$type = ArcanistMarkerRef::TYPE_BRANCH;
|
$type = ArcanistMarkerRef::TYPE_BRANCH;
|
||||||
$name = substr($ref, $branch_length);
|
$name = substr($ref, $branch_length);
|
||||||
|
} else if (!strncmp($ref, $remote_prefix, $remote_length)) {
|
||||||
|
// This isn't entirely correct: the ref may be a tag, etc.
|
||||||
|
$type = ArcanistMarkerRef::TYPE_BRANCH;
|
||||||
|
|
||||||
|
$label = substr($ref, $remote_length);
|
||||||
|
$parts = explode('/', $label, 2);
|
||||||
|
|
||||||
|
$remote_name = $parts[0];
|
||||||
|
$name = $parts[1];
|
||||||
} else {
|
} else {
|
||||||
// For now, discard other refs.
|
// For now, discard other refs.
|
||||||
continue;
|
continue;
|
||||||
|
@ -70,6 +81,10 @@ final class ArcanistGitRepositoryMarkerQuery
|
||||||
->setSummary($summary)
|
->setSummary($summary)
|
||||||
->setMessage($text);
|
->setMessage($text);
|
||||||
|
|
||||||
|
if ($remote_name !== null) {
|
||||||
|
$marker->setRemoteName($remote_name);
|
||||||
|
}
|
||||||
|
|
||||||
if (strlen($dst_hash)) {
|
if (strlen($dst_hash)) {
|
||||||
$commit_hash = $dst_hash;
|
$commit_hash = $dst_hash;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -20,6 +20,7 @@ final class ArcanistMarkerRef
|
||||||
private $summary;
|
private $summary;
|
||||||
private $message;
|
private $message;
|
||||||
private $isActive = false;
|
private $isActive = false;
|
||||||
|
private $remoteName;
|
||||||
|
|
||||||
public function getRefDisplayName() {
|
public function getRefDisplayName() {
|
||||||
switch ($this->getMarkerType()) {
|
switch ($this->getMarkerType()) {
|
||||||
|
@ -130,6 +131,15 @@ final class ArcanistMarkerRef
|
||||||
return $this->isActive;
|
return $this->isActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setRemoteName($remote_name) {
|
||||||
|
$this->remoteName = $remote_name;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRemoteName() {
|
||||||
|
return $this->remoteName;
|
||||||
|
}
|
||||||
|
|
||||||
public function isBookmark() {
|
public function isBookmark() {
|
||||||
return ($this->getMarkerType() === self::TYPE_BOOKMARK);
|
return ($this->getMarkerType() === self::TYPE_BOOKMARK);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ abstract class ArcanistRepositoryMarkerQuery
|
||||||
private $commitHashes;
|
private $commitHashes;
|
||||||
private $ancestorCommitHashes;
|
private $ancestorCommitHashes;
|
||||||
private $remotes;
|
private $remotes;
|
||||||
|
private $isRemoteCache = false;
|
||||||
|
|
||||||
final public function withMarkerTypes(array $types) {
|
final public function withMarkerTypes(array $types) {
|
||||||
$this->markerTypes = array_fuse($types);
|
$this->markerTypes = array_fuse($types);
|
||||||
|
@ -26,6 +27,11 @@ abstract class ArcanistRepositoryMarkerQuery
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final public function withIsRemoteCache($is_cache) {
|
||||||
|
$this->isRemoteCache = $is_cache;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
final public function withIsActive($active) {
|
final public function withIsActive($active) {
|
||||||
$this->isActive = $active;
|
$this->isActive = $active;
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -88,6 +94,16 @@ abstract class ArcanistRepositoryMarkerQuery
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->isRemoteCache !== null) {
|
||||||
|
$want_cache = $this->isRemoteCache;
|
||||||
|
foreach ($markers as $key => $marker) {
|
||||||
|
$is_cache = ($marker->getRemoteName() !== null);
|
||||||
|
if ($is_cache !== $want_cache) {
|
||||||
|
unset($markers[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $this->sortMarkers($markers);
|
return $this->sortMarkers($markers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,4 +89,13 @@ final class ArcanistRemoteRef
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isPermanentRef(ArcanistMarkerRef $ref) {
|
||||||
|
$repository_ref = $this->getPushRepositoryRef();
|
||||||
|
if (!$repository_ref) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $repository_ref->isPermanentRef($ref);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,10 @@ EOTEXT
|
||||||
return $this->lookRemotes();
|
return $this->lookRemotes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($argv === array('published')) {
|
||||||
|
return $this->lookPublished();
|
||||||
|
}
|
||||||
|
|
||||||
echo tsprintf(
|
echo tsprintf(
|
||||||
"%s\n",
|
"%s\n",
|
||||||
pht(
|
pht(
|
||||||
|
@ -195,6 +199,48 @@ EOTEXT
|
||||||
|
|
||||||
echo tsprintf('%s', $view);
|
echo tsprintf('%s', $view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
echo tsprintf("\n");
|
||||||
|
echo tsprintf(
|
||||||
|
pht(
|
||||||
|
"Across the grove, a stream flows north toward ".
|
||||||
|
"**published** commits.\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function lookPublished() {
|
||||||
|
echo tsprintf(
|
||||||
|
"%W\n\n",
|
||||||
|
pht(
|
||||||
|
'You walk along the narrow bank of the stream as it winds lazily '.
|
||||||
|
'downhill and turns east, gradually widening into a river.'));
|
||||||
|
|
||||||
|
$api = $this->getRepositoryAPI();
|
||||||
|
|
||||||
|
$published = $api->getPublishedCommitHashes();
|
||||||
|
|
||||||
|
if ($published) {
|
||||||
|
echo tsprintf(
|
||||||
|
"%W\n\n",
|
||||||
|
pht(
|
||||||
|
'Floating on the water, you see published commits:'));
|
||||||
|
|
||||||
|
foreach ($published as $hash) {
|
||||||
|
echo tsprintf(
|
||||||
|
"%s\n",
|
||||||
|
$hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo tsprintf(
|
||||||
|
"\n%W\n",
|
||||||
|
pht(
|
||||||
|
'They river bubbles peacefully.'));
|
||||||
|
} else {
|
||||||
|
echo tsprintf(
|
||||||
|
"%W\n",
|
||||||
|
pht(
|
||||||
|
'The river bubbles quietly, but you do not see any published '.
|
||||||
|
'commits anywhere.'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue