1
0
Fork 0
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:
epriestley 2013-12-02 15:45:55 -08:00
parent 618b5cbbc4
commit 017d6ccd07
5 changed files with 89 additions and 28 deletions

View file

@ -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();

View file

@ -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) {

View file

@ -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();

View file

@ -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);

View file

@ -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);
}
} }