mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-21 22:32:41 +01:00
Support bookmark hook operations in Mercurial
Summary: Ref T4195. Turns bookmark mutations in Mercurial into log objects. Test Plan: Pushed a pile of bookmarks and got logs: {F89313} Reviewers: btrahan Reviewed By: btrahan CC: aran Maniphest Tasks: T4195 Differential Revision: https://secure.phabricator.com/D7764
This commit is contained in:
parent
6f3a99eb39
commit
74251b3636
4 changed files with 129 additions and 10 deletions
|
@ -36,9 +36,10 @@ if ($repository->isGit() || $repository->isHg()) {
|
|||
pht('usage: %s should be defined!', DiffusionCommitHookEngine::ENV_USER));
|
||||
}
|
||||
|
||||
// TODO: If this is a Mercurial repository, the hook we're responding to
|
||||
// is available in $argv[2]. It's unclear if we actually need this, or if
|
||||
// we can block all actions we care about with just pretxnchangegroup.
|
||||
if ($repository->isHg()) {
|
||||
// We respond to several different hooks in Mercurial.
|
||||
$engine->setMercurialHook($argv[2]);
|
||||
}
|
||||
|
||||
} else if ($repository->isSVN()) {
|
||||
// NOTE: In Subversion, the entire environment gets wiped so we can't read
|
||||
|
|
|
@ -24,6 +24,7 @@ final class DiffusionCommitHookEngine extends Phobject {
|
|||
private $remoteAddress;
|
||||
private $remoteProtocol;
|
||||
private $transactionKey;
|
||||
private $mercurialHook;
|
||||
|
||||
|
||||
/* -( Config )------------------------------------------------------------- */
|
||||
|
@ -97,6 +98,15 @@ final class DiffusionCommitHookEngine extends Phobject {
|
|||
return $this->viewer;
|
||||
}
|
||||
|
||||
public function setMercurialHook($mercurial_hook) {
|
||||
$this->mercurialHook = $mercurial_hook;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMercurialHook() {
|
||||
return $this->mercurialHook;
|
||||
}
|
||||
|
||||
|
||||
/* -( Hook Execution )----------------------------------------------------- */
|
||||
|
||||
|
@ -239,7 +249,10 @@ final class DiffusionCommitHookEngine extends Phobject {
|
|||
} else if (preg_match('(^refs/tags/)', $ref_raw)) {
|
||||
$ref_type = PhabricatorRepositoryPushLog::REFTYPE_TAG;
|
||||
} else {
|
||||
$ref_type = PhabricatorRepositoryPushLog::REFTYPE_UNKNOWN;
|
||||
throw new Exception(
|
||||
pht(
|
||||
"Unable to identify the reftype of '%s'. Rejecting push.",
|
||||
$ref_raw));
|
||||
}
|
||||
|
||||
$ref_update = $this->newPushLog()
|
||||
|
@ -413,6 +426,20 @@ final class DiffusionCommitHookEngine extends Phobject {
|
|||
|
||||
|
||||
private function findMercurialRefUpdates() {
|
||||
$hook = $this->getMercurialHook();
|
||||
switch ($hook) {
|
||||
case 'pretxnchangegroup':
|
||||
return $this->findMercurialChangegroupRefUpdates();
|
||||
case 'prepushkey':
|
||||
return $this->findMercurialPushKeyRefUpdates();
|
||||
case 'pretag':
|
||||
return $this->findMercurialPreTagRefUpdates();
|
||||
default:
|
||||
throw new Exception(pht('Unrecognized hook "%s"!', $hook));
|
||||
}
|
||||
}
|
||||
|
||||
private function findMercurialChangegroupRefUpdates() {
|
||||
$hg_node = getenv('HG_NODE');
|
||||
if (!$hg_node) {
|
||||
throw new Exception(pht('Expected HG_NODE in environment!'));
|
||||
|
@ -594,6 +621,87 @@ final class DiffusionCommitHookEngine extends Phobject {
|
|||
return $ref_updates;
|
||||
}
|
||||
|
||||
private function findMercurialPushKeyRefUpdates() {
|
||||
$key_namespace = getenv('HG_NAMESPACE');
|
||||
|
||||
if ($key_namespace === 'phases') {
|
||||
// Mercurial changes commit phases as part of normal push operations. We
|
||||
// just ignore these, as they don't seem to represent anything
|
||||
// interesting.
|
||||
return array();
|
||||
}
|
||||
|
||||
$key_name = getenv('HG_KEY');
|
||||
|
||||
$key_old = getenv('HG_OLD');
|
||||
if (!strlen($key_old)) {
|
||||
$key_old = null;
|
||||
}
|
||||
|
||||
$key_new = getenv('HG_NEW');
|
||||
if (!strlen($key_new)) {
|
||||
$key_new = null;
|
||||
}
|
||||
|
||||
if ($key_namespace !== 'bookmarks') {
|
||||
throw new Exception(
|
||||
pht(
|
||||
"Unknown Mercurial key namespace '%s', with key '%s' (%s -> %s). ".
|
||||
"Rejecting push.",
|
||||
$key_namespace,
|
||||
$key_name,
|
||||
coalesce($key_old, pht('null')),
|
||||
coalesce($key_new, pht('null'))));
|
||||
}
|
||||
|
||||
if ($key_old === $key_new) {
|
||||
// We get a callback when the bookmark doesn't change. Just ignore this,
|
||||
// as it's a no-op.
|
||||
return array();
|
||||
}
|
||||
|
||||
$ref_flags = 0;
|
||||
$merge_base = null;
|
||||
if ($key_old === null) {
|
||||
$ref_flags |= PhabricatorRepositoryPushLog::CHANGEFLAG_ADD;
|
||||
} else if ($key_new === null) {
|
||||
$ref_flags |= PhabricatorRepositoryPushLog::CHANGEFLAG_DELETE;
|
||||
} else {
|
||||
list($merge_base_raw) = $this->getRepository()->execxLocalCommand(
|
||||
'log --template %s --rev %s',
|
||||
'{node}',
|
||||
hgsprintf('ancestor(%s, %s)', $key_old, $key_new));
|
||||
|
||||
if (strlen(trim($merge_base_raw))) {
|
||||
$merge_base = trim($merge_base_raw);
|
||||
}
|
||||
|
||||
if ($merge_base && ($merge_base === $key_old)) {
|
||||
$ref_flags |= PhabricatorRepositoryPushLog::CHANGEFLAG_APPEND;
|
||||
} else {
|
||||
$ref_flags |= PhabricatorRepositoryPushLog::CHANGEFLAG_REWRITE;
|
||||
}
|
||||
}
|
||||
|
||||
$ref_update = $this->newPushLog()
|
||||
->setRefType(PhabricatorRepositoryPushLog::REFTYPE_BOOKMARK)
|
||||
->setRefName($key_name)
|
||||
->setRefOld(coalesce($key_old, self::EMPTY_HASH))
|
||||
->setRefNew(coalesce($key_new, self::EMPTY_HASH))
|
||||
->setChangeFlags($ref_flags);
|
||||
|
||||
return array($ref_update);
|
||||
}
|
||||
|
||||
private function findMercurialPreTagRefUpdates() {
|
||||
return array();
|
||||
}
|
||||
|
||||
private function findMercurialContentUpdates(array $ref_updates) {
|
||||
// TODO: Implement.
|
||||
return array();
|
||||
}
|
||||
|
||||
private function parseMercurialCommits($raw) {
|
||||
$commits_lines = explode("\2", $raw);
|
||||
$commits_lines = array_filter($commits_lines);
|
||||
|
@ -626,11 +734,6 @@ final class DiffusionCommitHookEngine extends Phobject {
|
|||
return $heads;
|
||||
}
|
||||
|
||||
private function findMercurialContentUpdates(array $ref_updates) {
|
||||
// TODO: Implement.
|
||||
return array();
|
||||
}
|
||||
|
||||
|
||||
/* -( Subversion )--------------------------------------------------------- */
|
||||
|
||||
|
|
|
@ -397,11 +397,27 @@ final class PhabricatorRepositoryPullEngine
|
|||
|
||||
$data = array();
|
||||
$data[] = '[hooks]';
|
||||
|
||||
// This hook handles normal pushes.
|
||||
$data[] = csprintf(
|
||||
'pretxnchangegroup.phabricator = %s %s %s',
|
||||
$bin,
|
||||
$repository->getCallsign(),
|
||||
'pretxnchangegroup');
|
||||
|
||||
// This one handles creating bookmarks.
|
||||
$data[] = csprintf(
|
||||
'prepushkey.phabricator = %s %s %s',
|
||||
$bin,
|
||||
$repository->getCallsign(),
|
||||
'prepushkey');
|
||||
|
||||
// This one handles creating tags.
|
||||
$data[] = csprintf(
|
||||
'pretag.phabricator = %s %s %s',
|
||||
$bin,
|
||||
$repository->getCallsign(),
|
||||
'pretag');
|
||||
$data[] = null;
|
||||
|
||||
$data = implode("\n", $data);
|
||||
|
|
|
@ -18,7 +18,6 @@ final class PhabricatorRepositoryPushLog
|
|||
const REFTYPE_BOOKMARK = 'bookmark';
|
||||
const REFTYPE_SVN = 'svn';
|
||||
const REFTYPE_COMMIT = 'commit';
|
||||
const REFTYPE_UNKNOWN = 'unknown';
|
||||
|
||||
const CHANGEFLAG_ADD = 1;
|
||||
const CHANGEFLAG_DELETE = 2;
|
||||
|
|
Loading…
Reference in a new issue