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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
final public function getPublishedCommitHashes() {
|
||||
return $this->newPublishedCommitHashes();
|
||||
}
|
||||
|
||||
protected function newPublishedCommitHashes() {
|
||||
return array();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,11 +23,11 @@ final class ArcanistGitRepositoryMarkerQuery
|
|||
$branch_prefix = 'refs/heads/';
|
||||
$branch_length = strlen($branch_prefix);
|
||||
|
||||
// NOTE: Since we only return branches today, we restrict this operation
|
||||
// to branches.
|
||||
$remote_prefix = 'refs/remotes/';
|
||||
$remote_length = strlen($remote_prefix);
|
||||
|
||||
list($stdout) = $api->newFuture(
|
||||
'for-each-ref --format %s -- refs/heads/',
|
||||
'for-each-ref --format %s -- refs/',
|
||||
implode('%01', $field_list))->resolve();
|
||||
|
||||
$markers = array();
|
||||
|
@ -53,9 +53,20 @@ final class ArcanistGitRepositoryMarkerQuery
|
|||
|
||||
list($ref, $hash, $epoch, $tree, $dst_hash, $summary, $text) = $fields;
|
||||
|
||||
$remote_name = null;
|
||||
|
||||
if (!strncmp($ref, $branch_prefix, $branch_length)) {
|
||||
$type = ArcanistMarkerRef::TYPE_BRANCH;
|
||||
$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 {
|
||||
// For now, discard other refs.
|
||||
continue;
|
||||
|
@ -70,6 +81,10 @@ final class ArcanistGitRepositoryMarkerQuery
|
|||
->setSummary($summary)
|
||||
->setMessage($text);
|
||||
|
||||
if ($remote_name !== null) {
|
||||
$marker->setRemoteName($remote_name);
|
||||
}
|
||||
|
||||
if (strlen($dst_hash)) {
|
||||
$commit_hash = $dst_hash;
|
||||
} else {
|
||||
|
|
|
@ -20,6 +20,7 @@ final class ArcanistMarkerRef
|
|||
private $summary;
|
||||
private $message;
|
||||
private $isActive = false;
|
||||
private $remoteName;
|
||||
|
||||
public function getRefDisplayName() {
|
||||
switch ($this->getMarkerType()) {
|
||||
|
@ -130,6 +131,15 @@ final class ArcanistMarkerRef
|
|||
return $this->isActive;
|
||||
}
|
||||
|
||||
public function setRemoteName($remote_name) {
|
||||
$this->remoteName = $remote_name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRemoteName() {
|
||||
return $this->remoteName;
|
||||
}
|
||||
|
||||
public function isBookmark() {
|
||||
return ($this->getMarkerType() === self::TYPE_BOOKMARK);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ abstract class ArcanistRepositoryMarkerQuery
|
|||
private $commitHashes;
|
||||
private $ancestorCommitHashes;
|
||||
private $remotes;
|
||||
private $isRemoteCache = false;
|
||||
|
||||
final public function withMarkerTypes(array $types) {
|
||||
$this->markerTypes = array_fuse($types);
|
||||
|
@ -26,6 +27,11 @@ abstract class ArcanistRepositoryMarkerQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
final public function withIsRemoteCache($is_cache) {
|
||||
$this->isRemoteCache = $is_cache;
|
||||
return $this;
|
||||
}
|
||||
|
||||
final public function withIsActive($active) {
|
||||
$this->isActive = $active;
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -89,4 +89,13 @@ final class ArcanistRemoteRef
|
|||
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();
|
||||
}
|
||||
|
||||
if ($argv === array('published')) {
|
||||
return $this->lookPublished();
|
||||
}
|
||||
|
||||
echo tsprintf(
|
||||
"%s\n",
|
||||
pht(
|
||||
|
@ -195,6 +199,48 @@ EOTEXT
|
|||
|
||||
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