Skip to content

Commit 017d6cc

Browse files
author
epriestley
committedDec 2, 2013
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
1 parent 618b5cb commit 017d6cc

File tree

5 files changed

+89
-28
lines changed

5 files changed

+89
-28
lines changed
 

‎scripts/repository/commit_hook.php

+48-25
Original file line numberDiff line numberDiff line change
@@ -4,52 +4,75 @@
44
$root = dirname(dirname(dirname(__FILE__)));
55
require_once $root.'/scripts/__init_script__.php';
66

7-
$username = getenv('PHABRICATOR_USER');
8-
if (!$username) {
9-
throw new Exception(pht('usage: define PHABRICATOR_USER in environment'));
10-
}
11-
12-
$user = id(new PhabricatorPeopleQuery())
13-
->setViewer(PhabricatorUser::getOmnipotentUser())
14-
->withUsernames(array($username))
15-
->executeOne();
16-
if (!$user) {
17-
throw new Exception(pht('No such user "%s"!', $username));
18-
}
19-
207
if ($argc < 2) {
218
throw new Exception(pht('usage: commit-hook <callsign>'));
229
}
2310

11+
$engine = new DiffusionCommitHookEngine();
12+
2413
$repository = id(new PhabricatorRepositoryQuery())
25-
->setViewer($user)
14+
->setViewer(PhabricatorUser::getOmnipotentUser())
2615
->withCallsigns(array($argv[1]))
27-
->requireCapabilities(
28-
array(
29-
// This capability check is redundant, but can't hurt.
30-
PhabricatorPolicyCapability::CAN_VIEW,
31-
DiffusionCapabilityPush::CAPABILITY,
32-
))
3316
->executeOne();
3417

3518
if (!$repository) {
3619
throw new Exception(pht('No such repository "%s"!', $callsign));
3720
}
3821

3922
if (!$repository->isHosted()) {
40-
// This should be redundant too, but double check just in case.
23+
// This should be redundant, but double check just in case.
4124
throw new Exception(pht('Repository "%s" is not hosted!', $callsign));
4225
}
4326

27+
$engine->setRepository($repository);
28+
29+
30+
// Figure out which user is writing the commit.
31+
32+
if ($repository->isGit()) {
33+
$username = getenv('PHABRICATOR_USER');
34+
if (!strlen($username)) {
35+
throw new Exception(pht('usage: PHABRICATOR_USER should be defined!'));
36+
}
37+
} else if ($repository->isSVN()) {
38+
// NOTE: In Subversion, the entire environment gets wiped so we can't read
39+
// PHABRICATOR_USER. Instead, we've set "--tunnel-user" to specify the
40+
// correct user; read this user out of the commit log.
41+
42+
if ($argc < 4) {
43+
throw new Exception(pht('usage: commit-hook <callsign> <repo> <txn>'));
44+
}
45+
46+
$svn_repo = $argv[2];
47+
$svn_txn = $argv[3];
48+
list($username) = execx('svnlook author -t %s %s', $svn_txn, $svn_repo);
49+
$username = rtrim($username, "\n");
50+
51+
$engine->setSubversionTransactionInfo($svn_txn, $svn_repo);
52+
} else {
53+
throw new Exceptiont(pht('Unknown repository type.'));
54+
}
55+
56+
$user = id(new PhabricatorPeopleQuery())
57+
->setViewer(PhabricatorUser::getOmnipotentUser())
58+
->withUsernames(array($username))
59+
->executeOne();
60+
61+
if (!$user) {
62+
throw new Exception(pht('No such user "%s"!', $username));
63+
}
64+
65+
$engine->setViewer($user);
66+
67+
68+
// Read stdin for the hook engine.
69+
4470
$stdin = @file_get_contents('php://stdin');
4571
if ($stdin === false) {
4672
throw new Exception(pht('Failed to read stdin!'));
4773
}
4874

49-
$engine = id(new DiffusionCommitHookEngine())
50-
->setViewer($user)
51-
->setRepository($repository)
52-
->setStdin($stdin);
75+
$engine->setStdin($stdin);
5376

5477
$err = $engine->execute();
5578

‎src/applications/diffusion/controller/DiffusionRepositoryController.php

+6-1
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,12 @@ private function buildPropertiesTable(PhabricatorRepository $repository) {
173173
$serve_ssh = $repository->getServeOverSSH();
174174
if ($serve_ssh !== $serve_off) {
175175
$uri = new PhutilURI(PhabricatorEnv::getProductionURI($repo_path));
176-
$uri->setProtocol('ssh');
176+
177+
if ($repository->isSVN()) {
178+
$uri->setProtocol('svn+ssh');
179+
} else {
180+
$uri->setProtocol('ssh');
181+
}
177182

178183
$ssh_user = PhabricatorEnv::getEnvConfig('diffusion.ssh-user');
179184
if ($ssh_user) {

‎src/applications/diffusion/engine/DiffusionCommitHookEngine.php

+19
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ final class DiffusionCommitHookEngine extends Phobject {
55
private $viewer;
66
private $repository;
77
private $stdin;
8+
private $subversionTransaction;
9+
private $subversionRepository;
10+
11+
12+
public function setSubversionTransactionInfo($transaction, $repository) {
13+
$this->subversionTransaction = $transaction;
14+
$this->subversionRepository = $repository;
15+
return $this;
16+
}
817

918
public function setStdin($stdin) {
1019
$this->stdin = $stdin;
@@ -39,6 +48,9 @@ public function execute() {
3948
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
4049
$err = $this->executeGitHook();
4150
break;
51+
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
52+
$err = $this->executeSubversionHook();
53+
break;
4254
default:
4355
throw new Exception(pht('Unsupported repository type "%s"!', $type));
4456
}
@@ -54,6 +66,13 @@ private function executeGitHook() {
5466
return 0;
5567
}
5668

69+
private function executeSubversionHook() {
70+
71+
// TODO: Do useful things here, too.
72+
73+
return 0;
74+
}
75+
5776
private function parseGitUpdates($stdin) {
5877
$updates = array();
5978

‎src/applications/diffusion/ssh/DiffusionSSHSubversionServeWorkflow.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ protected function executeRepositoryOperations() {
3838
throw new Exception("Expected `svnserve -t`!");
3939
}
4040

41-
$command = csprintf('svnserve -t');
41+
$command = csprintf(
42+
'svnserve -t --tunnel-user=%s',
43+
$this->getUser()->getUsername());
4244
$command = PhabricatorDaemon::sudoCommandAsDaemonUser($command);
4345

4446
$future = new ExecFuture('%C', $command);

‎src/applications/repository/engine/PhabricatorRepositoryPullEngine.php

+13-1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ public function pullRepository() {
8585
if ($repository->isHosted()) {
8686
if ($is_git) {
8787
$this->installGitHook();
88+
} else if ($is_svn) {
89+
$this->installSubversionHook();
8890
} else {
8991
$this->logPull(
9092
pht(
@@ -158,7 +160,7 @@ private function installHook($path) {
158160

159161
$root = dirname(phutil_get_library_root('phabricator'));
160162
$bin = $root.'/bin/commit-hook';
161-
$cmd = csprintf('exec -- %s %s', $bin, $callsign);
163+
$cmd = csprintf('exec -- %s %s "$@"', $bin, $callsign);
162164

163165
$hook = "#!/bin/sh\n{$cmd}\n";
164166

@@ -394,5 +396,15 @@ private function executeSubversionCreate() {
394396
execx('svnadmin create -- %s', $path);
395397
}
396398

399+
/**
400+
* @task svn
401+
*/
402+
private function installSubversionHook() {
403+
$repository = $this->getRepository();
404+
$path = $repository->getLocalPath().'hooks/pre-commit';
405+
406+
$this->installHook($path);
407+
}
408+
397409

398410
}

0 commit comments

Comments
 (0)
Failed to load comments.