1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-25 00:02:41 +01:00
phorge-phorge/src/applications/diffusion/conduit/DiffusionBranchQueryConduitAPIMethod.php
epriestley f5f784f4c1 Version clustered, observed repositories in a reasonable way (by largest discovered HEAD)
Summary:
Ref T4292. For hosted, clustered repositories we have a good way to increment the internal version of the repository: every time a user pushes something, we increment the version by 1.

We don't have a great way to do this for observed/remote repositories because when we `git fetch` we might get nothing, or we might get some changes, and we can't easily tell //what// changes we got.

For example, if we see that another node is at "version 97", and we do a fetch and see some changes, we don't know if we're in sync with them (i.e., also at "version 97") or ahead of them (at "version 98").

This implements a simple way to version an observed repository:

  - Take the head of every branch/tag.
  - Look them up.
  - Pick the biggest internal ID number.

This will work //except// when branches are deleted, which could cause the version to go backward if the "biggest commit" is the one that was deleted. This should be OK, since it's rare and the effects are minor and the repository will "self-heal" on the next actual push.

Test Plan:
  - Created an observed repository.
  - Ran `bin/repository update` and observed a sensible version number appear in the version table.
  - Pushed to the remote, did another update, saw a sensible update.
  - Did an update with no push, saw no effect on version number.
  - Toggled repository to hosted, saw the version reset.
  - Simulated read traffic to out-of-sync node, saw it do a remote fetch.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T4292

Differential Revision: https://secure.phabricator.com/D15986
2016-05-30 09:53:01 -07:00

128 lines
3.6 KiB
PHP

<?php
final class DiffusionBranchQueryConduitAPIMethod
extends DiffusionQueryConduitAPIMethod {
public function getAPIMethodName() {
return 'diffusion.branchquery';
}
public function getMethodDescription() {
return pht('Determine what branches exist for a repository.');
}
protected function defineReturnType() {
return 'list<dict>';
}
protected function defineCustomParamTypes() {
return array(
'closed' => 'optional bool',
'limit' => 'optional int',
'offset' => 'optional int',
'contains' => 'optional string',
);
}
protected function getGitResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$contains = $request->getValue('contains');
if (strlen($contains)) {
// NOTE: We can't use DiffusionLowLevelGitRefQuery here because
// `git for-each-ref` does not support `--contains`.
if ($repository->isWorkingCopyBare()) {
list($stdout) = $repository->execxLocalCommand(
'branch --verbose --no-abbrev --contains %s --',
$contains);
$ref_map = DiffusionGitBranch::parseLocalBranchOutput(
$stdout);
} else {
list($stdout) = $repository->execxLocalCommand(
'branch -r --verbose --no-abbrev --contains %s --',
$contains);
$ref_map = DiffusionGitBranch::parseRemoteBranchOutput(
$stdout,
DiffusionGitBranch::DEFAULT_GIT_REMOTE);
}
$refs = array();
foreach ($ref_map as $ref => $commit) {
$refs[] = id(new DiffusionRepositoryRef())
->setShortName($ref)
->setCommitIdentifier($commit);
}
} else {
$refs = id(new DiffusionLowLevelGitRefQuery())
->setRepository($repository)
->withRefTypes(
array(
PhabricatorRepositoryRefCursor::TYPE_BRANCH,
))
->execute();
}
return $this->processBranchRefs($request, $refs);
}
protected function getMercurialResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$query = id(new DiffusionLowLevelMercurialBranchesQuery())
->setRepository($repository);
$contains = $request->getValue('contains');
if (strlen($contains)) {
$query->withContainsCommit($contains);
}
$refs = $query->execute();
return $this->processBranchRefs($request, $refs);
}
protected function getSVNResult(ConduitAPIRequest $request) {
// Since SVN doesn't have meaningful branches, just return nothing for all
// queries.
return array();
}
private function processBranchRefs(ConduitAPIRequest $request, array $refs) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$offset = $request->getValue('offset');
$limit = $request->getValue('limit');
foreach ($refs as $key => $ref) {
if (!$repository->shouldTrackBranch($ref->getShortName())) {
unset($refs[$key]);
}
}
$with_closed = $request->getValue('closed');
if ($with_closed !== null) {
foreach ($refs as $key => $ref) {
$fields = $ref->getRawFields();
if (idx($fields, 'closed') != $with_closed) {
unset($refs[$key]);
}
}
}
// NOTE: We can't apply the offset or limit until here, because we may have
// filtered untrackable branches out of the result set.
if ($offset) {
$refs = array_slice($refs, $offset);
}
if ($limit) {
$refs = array_slice($refs, 0, $limit);
}
return mpull($refs, 'toDictionary');
}
}