mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 23:02:42 +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));
|
pht('usage: %s should be defined!', DiffusionCommitHookEngine::ENV_USER));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: If this is a Mercurial repository, the hook we're responding to
|
if ($repository->isHg()) {
|
||||||
// is available in $argv[2]. It's unclear if we actually need this, or if
|
// We respond to several different hooks in Mercurial.
|
||||||
// we can block all actions we care about with just pretxnchangegroup.
|
$engine->setMercurialHook($argv[2]);
|
||||||
|
}
|
||||||
|
|
||||||
} else if ($repository->isSVN()) {
|
} else if ($repository->isSVN()) {
|
||||||
// NOTE: In Subversion, the entire environment gets wiped so we can't read
|
// 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 $remoteAddress;
|
||||||
private $remoteProtocol;
|
private $remoteProtocol;
|
||||||
private $transactionKey;
|
private $transactionKey;
|
||||||
|
private $mercurialHook;
|
||||||
|
|
||||||
|
|
||||||
/* -( Config )------------------------------------------------------------- */
|
/* -( Config )------------------------------------------------------------- */
|
||||||
|
@ -97,6 +98,15 @@ final class DiffusionCommitHookEngine extends Phobject {
|
||||||
return $this->viewer;
|
return $this->viewer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setMercurialHook($mercurial_hook) {
|
||||||
|
$this->mercurialHook = $mercurial_hook;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMercurialHook() {
|
||||||
|
return $this->mercurialHook;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( Hook Execution )----------------------------------------------------- */
|
/* -( Hook Execution )----------------------------------------------------- */
|
||||||
|
|
||||||
|
@ -239,7 +249,10 @@ final class DiffusionCommitHookEngine extends Phobject {
|
||||||
} else if (preg_match('(^refs/tags/)', $ref_raw)) {
|
} else if (preg_match('(^refs/tags/)', $ref_raw)) {
|
||||||
$ref_type = PhabricatorRepositoryPushLog::REFTYPE_TAG;
|
$ref_type = PhabricatorRepositoryPushLog::REFTYPE_TAG;
|
||||||
} else {
|
} 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()
|
$ref_update = $this->newPushLog()
|
||||||
|
@ -413,6 +426,20 @@ final class DiffusionCommitHookEngine extends Phobject {
|
||||||
|
|
||||||
|
|
||||||
private function findMercurialRefUpdates() {
|
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');
|
$hg_node = getenv('HG_NODE');
|
||||||
if (!$hg_node) {
|
if (!$hg_node) {
|
||||||
throw new Exception(pht('Expected HG_NODE in environment!'));
|
throw new Exception(pht('Expected HG_NODE in environment!'));
|
||||||
|
@ -594,6 +621,87 @@ final class DiffusionCommitHookEngine extends Phobject {
|
||||||
return $ref_updates;
|
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) {
|
private function parseMercurialCommits($raw) {
|
||||||
$commits_lines = explode("\2", $raw);
|
$commits_lines = explode("\2", $raw);
|
||||||
$commits_lines = array_filter($commits_lines);
|
$commits_lines = array_filter($commits_lines);
|
||||||
|
@ -626,11 +734,6 @@ final class DiffusionCommitHookEngine extends Phobject {
|
||||||
return $heads;
|
return $heads;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function findMercurialContentUpdates(array $ref_updates) {
|
|
||||||
// TODO: Implement.
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* -( Subversion )--------------------------------------------------------- */
|
/* -( Subversion )--------------------------------------------------------- */
|
||||||
|
|
||||||
|
|
|
@ -397,11 +397,27 @@ final class PhabricatorRepositoryPullEngine
|
||||||
|
|
||||||
$data = array();
|
$data = array();
|
||||||
$data[] = '[hooks]';
|
$data[] = '[hooks]';
|
||||||
|
|
||||||
|
// This hook handles normal pushes.
|
||||||
$data[] = csprintf(
|
$data[] = csprintf(
|
||||||
'pretxnchangegroup.phabricator = %s %s %s',
|
'pretxnchangegroup.phabricator = %s %s %s',
|
||||||
$bin,
|
$bin,
|
||||||
$repository->getCallsign(),
|
$repository->getCallsign(),
|
||||||
'pretxnchangegroup');
|
'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[] = null;
|
||||||
|
|
||||||
$data = implode("\n", $data);
|
$data = implode("\n", $data);
|
||||||
|
|
|
@ -18,7 +18,6 @@ final class PhabricatorRepositoryPushLog
|
||||||
const REFTYPE_BOOKMARK = 'bookmark';
|
const REFTYPE_BOOKMARK = 'bookmark';
|
||||||
const REFTYPE_SVN = 'svn';
|
const REFTYPE_SVN = 'svn';
|
||||||
const REFTYPE_COMMIT = 'commit';
|
const REFTYPE_COMMIT = 'commit';
|
||||||
const REFTYPE_UNKNOWN = 'unknown';
|
|
||||||
|
|
||||||
const CHANGEFLAG_ADD = 1;
|
const CHANGEFLAG_ADD = 1;
|
||||||
const CHANGEFLAG_DELETE = 2;
|
const CHANGEFLAG_DELETE = 2;
|
||||||
|
|
Loading…
Reference in a new issue