mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-25 16:22:43 +01:00
Support SVN pre-commit hoooks
Summary: Ref T4189. This adds SVN support, which was a little more messy than I though. Principally, we can not use `PHABRICATOR_USER` for Subversion, because it strips away the entire environment for "security reasons". Instead, use `--tunnel-user` plus `svnlook author` to figure out the author. Also fix "ssh://" clone URIs, which needs to be "svn+ssh://". Test Plan: - Made SVN commits through the hook. - Made Git commits, too, to make sure I didn't break anything. Reviewers: btrahan Reviewed By: btrahan CC: aran Maniphest Tasks: T4189 Differential Revision: https://secure.phabricator.com/D7683
This commit is contained in:
parent
618b5cbbc4
commit
017d6ccd07
5 changed files with 89 additions and 28 deletions
|
@ -4,32 +4,15 @@
|
||||||
$root = dirname(dirname(dirname(__FILE__)));
|
$root = dirname(dirname(dirname(__FILE__)));
|
||||||
require_once $root.'/scripts/__init_script__.php';
|
require_once $root.'/scripts/__init_script__.php';
|
||||||
|
|
||||||
$username = getenv('PHABRICATOR_USER');
|
|
||||||
if (!$username) {
|
|
||||||
throw new Exception(pht('usage: define PHABRICATOR_USER in environment'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$user = id(new PhabricatorPeopleQuery())
|
|
||||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
|
||||||
->withUsernames(array($username))
|
|
||||||
->executeOne();
|
|
||||||
if (!$user) {
|
|
||||||
throw new Exception(pht('No such user "%s"!', $username));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($argc < 2) {
|
if ($argc < 2) {
|
||||||
throw new Exception(pht('usage: commit-hook <callsign>'));
|
throw new Exception(pht('usage: commit-hook <callsign>'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$engine = new DiffusionCommitHookEngine();
|
||||||
|
|
||||||
$repository = id(new PhabricatorRepositoryQuery())
|
$repository = id(new PhabricatorRepositoryQuery())
|
||||||
->setViewer($user)
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||||
->withCallsigns(array($argv[1]))
|
->withCallsigns(array($argv[1]))
|
||||||
->requireCapabilities(
|
|
||||||
array(
|
|
||||||
// This capability check is redundant, but can't hurt.
|
|
||||||
PhabricatorPolicyCapability::CAN_VIEW,
|
|
||||||
DiffusionCapabilityPush::CAPABILITY,
|
|
||||||
))
|
|
||||||
->executeOne();
|
->executeOne();
|
||||||
|
|
||||||
if (!$repository) {
|
if (!$repository) {
|
||||||
|
@ -37,19 +20,59 @@ if (!$repository) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$repository->isHosted()) {
|
if (!$repository->isHosted()) {
|
||||||
// This should be redundant too, but double check just in case.
|
// This should be redundant, but double check just in case.
|
||||||
throw new Exception(pht('Repository "%s" is not hosted!', $callsign));
|
throw new Exception(pht('Repository "%s" is not hosted!', $callsign));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$engine->setRepository($repository);
|
||||||
|
|
||||||
|
|
||||||
|
// Figure out which user is writing the commit.
|
||||||
|
|
||||||
|
if ($repository->isGit()) {
|
||||||
|
$username = getenv('PHABRICATOR_USER');
|
||||||
|
if (!strlen($username)) {
|
||||||
|
throw new Exception(pht('usage: PHABRICATOR_USER should be defined!'));
|
||||||
|
}
|
||||||
|
} else if ($repository->isSVN()) {
|
||||||
|
// NOTE: In Subversion, the entire environment gets wiped so we can't read
|
||||||
|
// PHABRICATOR_USER. Instead, we've set "--tunnel-user" to specify the
|
||||||
|
// correct user; read this user out of the commit log.
|
||||||
|
|
||||||
|
if ($argc < 4) {
|
||||||
|
throw new Exception(pht('usage: commit-hook <callsign> <repo> <txn>'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$svn_repo = $argv[2];
|
||||||
|
$svn_txn = $argv[3];
|
||||||
|
list($username) = execx('svnlook author -t %s %s', $svn_txn, $svn_repo);
|
||||||
|
$username = rtrim($username, "\n");
|
||||||
|
|
||||||
|
$engine->setSubversionTransactionInfo($svn_txn, $svn_repo);
|
||||||
|
} else {
|
||||||
|
throw new Exceptiont(pht('Unknown repository type.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = id(new PhabricatorPeopleQuery())
|
||||||
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||||
|
->withUsernames(array($username))
|
||||||
|
->executeOne();
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
throw new Exception(pht('No such user "%s"!', $username));
|
||||||
|
}
|
||||||
|
|
||||||
|
$engine->setViewer($user);
|
||||||
|
|
||||||
|
|
||||||
|
// Read stdin for the hook engine.
|
||||||
|
|
||||||
$stdin = @file_get_contents('php://stdin');
|
$stdin = @file_get_contents('php://stdin');
|
||||||
if ($stdin === false) {
|
if ($stdin === false) {
|
||||||
throw new Exception(pht('Failed to read stdin!'));
|
throw new Exception(pht('Failed to read stdin!'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$engine = id(new DiffusionCommitHookEngine())
|
$engine->setStdin($stdin);
|
||||||
->setViewer($user)
|
|
||||||
->setRepository($repository)
|
|
||||||
->setStdin($stdin);
|
|
||||||
|
|
||||||
$err = $engine->execute();
|
$err = $engine->execute();
|
||||||
|
|
||||||
|
|
|
@ -173,7 +173,12 @@ final class DiffusionRepositoryController extends DiffusionController {
|
||||||
$serve_ssh = $repository->getServeOverSSH();
|
$serve_ssh = $repository->getServeOverSSH();
|
||||||
if ($serve_ssh !== $serve_off) {
|
if ($serve_ssh !== $serve_off) {
|
||||||
$uri = new PhutilURI(PhabricatorEnv::getProductionURI($repo_path));
|
$uri = new PhutilURI(PhabricatorEnv::getProductionURI($repo_path));
|
||||||
$uri->setProtocol('ssh');
|
|
||||||
|
if ($repository->isSVN()) {
|
||||||
|
$uri->setProtocol('svn+ssh');
|
||||||
|
} else {
|
||||||
|
$uri->setProtocol('ssh');
|
||||||
|
}
|
||||||
|
|
||||||
$ssh_user = PhabricatorEnv::getEnvConfig('diffusion.ssh-user');
|
$ssh_user = PhabricatorEnv::getEnvConfig('diffusion.ssh-user');
|
||||||
if ($ssh_user) {
|
if ($ssh_user) {
|
||||||
|
|
|
@ -5,6 +5,15 @@ final class DiffusionCommitHookEngine extends Phobject {
|
||||||
private $viewer;
|
private $viewer;
|
||||||
private $repository;
|
private $repository;
|
||||||
private $stdin;
|
private $stdin;
|
||||||
|
private $subversionTransaction;
|
||||||
|
private $subversionRepository;
|
||||||
|
|
||||||
|
|
||||||
|
public function setSubversionTransactionInfo($transaction, $repository) {
|
||||||
|
$this->subversionTransaction = $transaction;
|
||||||
|
$this->subversionRepository = $repository;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function setStdin($stdin) {
|
public function setStdin($stdin) {
|
||||||
$this->stdin = $stdin;
|
$this->stdin = $stdin;
|
||||||
|
@ -39,6 +48,9 @@ final class DiffusionCommitHookEngine extends Phobject {
|
||||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
||||||
$err = $this->executeGitHook();
|
$err = $this->executeGitHook();
|
||||||
break;
|
break;
|
||||||
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
||||||
|
$err = $this->executeSubversionHook();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Exception(pht('Unsupported repository type "%s"!', $type));
|
throw new Exception(pht('Unsupported repository type "%s"!', $type));
|
||||||
}
|
}
|
||||||
|
@ -54,6 +66,13 @@ final class DiffusionCommitHookEngine extends Phobject {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function executeSubversionHook() {
|
||||||
|
|
||||||
|
// TODO: Do useful things here, too.
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
private function parseGitUpdates($stdin) {
|
private function parseGitUpdates($stdin) {
|
||||||
$updates = array();
|
$updates = array();
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,9 @@ final class DiffusionSSHSubversionServeWorkflow
|
||||||
throw new Exception("Expected `svnserve -t`!");
|
throw new Exception("Expected `svnserve -t`!");
|
||||||
}
|
}
|
||||||
|
|
||||||
$command = csprintf('svnserve -t');
|
$command = csprintf(
|
||||||
|
'svnserve -t --tunnel-user=%s',
|
||||||
|
$this->getUser()->getUsername());
|
||||||
$command = PhabricatorDaemon::sudoCommandAsDaemonUser($command);
|
$command = PhabricatorDaemon::sudoCommandAsDaemonUser($command);
|
||||||
|
|
||||||
$future = new ExecFuture('%C', $command);
|
$future = new ExecFuture('%C', $command);
|
||||||
|
|
|
@ -85,6 +85,8 @@ final class PhabricatorRepositoryPullEngine
|
||||||
if ($repository->isHosted()) {
|
if ($repository->isHosted()) {
|
||||||
if ($is_git) {
|
if ($is_git) {
|
||||||
$this->installGitHook();
|
$this->installGitHook();
|
||||||
|
} else if ($is_svn) {
|
||||||
|
$this->installSubversionHook();
|
||||||
} else {
|
} else {
|
||||||
$this->logPull(
|
$this->logPull(
|
||||||
pht(
|
pht(
|
||||||
|
@ -158,7 +160,7 @@ final class PhabricatorRepositoryPullEngine
|
||||||
|
|
||||||
$root = dirname(phutil_get_library_root('phabricator'));
|
$root = dirname(phutil_get_library_root('phabricator'));
|
||||||
$bin = $root.'/bin/commit-hook';
|
$bin = $root.'/bin/commit-hook';
|
||||||
$cmd = csprintf('exec -- %s %s', $bin, $callsign);
|
$cmd = csprintf('exec -- %s %s "$@"', $bin, $callsign);
|
||||||
|
|
||||||
$hook = "#!/bin/sh\n{$cmd}\n";
|
$hook = "#!/bin/sh\n{$cmd}\n";
|
||||||
|
|
||||||
|
@ -394,5 +396,15 @@ final class PhabricatorRepositoryPullEngine
|
||||||
execx('svnadmin create -- %s', $path);
|
execx('svnadmin create -- %s', $path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @task svn
|
||||||
|
*/
|
||||||
|
private function installSubversionHook() {
|
||||||
|
$repository = $this->getRepository();
|
||||||
|
$path = $repository->getLocalPath().'hooks/pre-commit';
|
||||||
|
|
||||||
|
$this->installHook($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue