@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+89 -28
+48 -25
scripts/repository/commit_hook.php
··· 4 4 $root = dirname(dirname(dirname(__FILE__))); 5 5 require_once $root.'/scripts/__init_script__.php'; 6 6 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 - 20 7 if ($argc < 2) { 21 8 throw new Exception(pht('usage: commit-hook <callsign>')); 22 9 } 10 + 11 + $engine = new DiffusionCommitHookEngine(); 23 12 24 13 $repository = id(new PhabricatorRepositoryQuery()) 25 - ->setViewer($user) 14 + ->setViewer(PhabricatorUser::getOmnipotentUser()) 26 15 ->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 - )) 33 16 ->executeOne(); 34 17 35 18 if (!$repository) { ··· 37 20 } 38 21 39 22 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. 41 24 throw new Exception(pht('Repository "%s" is not hosted!', $callsign)); 42 25 } 43 26 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 + 44 70 $stdin = @file_get_contents('php://stdin'); 45 71 if ($stdin === false) { 46 72 throw new Exception(pht('Failed to read stdin!')); 47 73 } 48 74 49 - $engine = id(new DiffusionCommitHookEngine()) 50 - ->setViewer($user) 51 - ->setRepository($repository) 52 - ->setStdin($stdin); 75 + $engine->setStdin($stdin); 53 76 54 77 $err = $engine->execute(); 55 78
+6 -1
src/applications/diffusion/controller/DiffusionRepositoryController.php
··· 173 173 $serve_ssh = $repository->getServeOverSSH(); 174 174 if ($serve_ssh !== $serve_off) { 175 175 $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 + } 177 182 178 183 $ssh_user = PhabricatorEnv::getEnvConfig('diffusion.ssh-user'); 179 184 if ($ssh_user) {
+19
src/applications/diffusion/engine/DiffusionCommitHookEngine.php
··· 5 5 private $viewer; 6 6 private $repository; 7 7 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 + } 8 17 9 18 public function setStdin($stdin) { 10 19 $this->stdin = $stdin; ··· 39 48 case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: 40 49 $err = $this->executeGitHook(); 41 50 break; 51 + case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: 52 + $err = $this->executeSubversionHook(); 53 + break; 42 54 default: 43 55 throw new Exception(pht('Unsupported repository type "%s"!', $type)); 44 56 } ··· 50 62 $updates = $this->parseGitUpdates($this->getStdin()); 51 63 52 64 // TODO: Do useful things. 65 + 66 + return 0; 67 + } 68 + 69 + private function executeSubversionHook() { 70 + 71 + // TODO: Do useful things here, too. 53 72 54 73 return 0; 55 74 }
+3 -1
src/applications/diffusion/ssh/DiffusionSSHSubversionServeWorkflow.php
··· 38 38 throw new Exception("Expected `svnserve -t`!"); 39 39 } 40 40 41 - $command = csprintf('svnserve -t'); 41 + $command = csprintf( 42 + 'svnserve -t --tunnel-user=%s', 43 + $this->getUser()->getUsername()); 42 44 $command = PhabricatorDaemon::sudoCommandAsDaemonUser($command); 43 45 44 46 $future = new ExecFuture('%C', $command);
+13 -1
src/applications/repository/engine/PhabricatorRepositoryPullEngine.php
··· 85 85 if ($repository->isHosted()) { 86 86 if ($is_git) { 87 87 $this->installGitHook(); 88 + } else if ($is_svn) { 89 + $this->installSubversionHook(); 88 90 } else { 89 91 $this->logPull( 90 92 pht( ··· 158 160 159 161 $root = dirname(phutil_get_library_root('phabricator')); 160 162 $bin = $root.'/bin/commit-hook'; 161 - $cmd = csprintf('exec -- %s %s', $bin, $callsign); 163 + $cmd = csprintf('exec -- %s %s "$@"', $bin, $callsign); 162 164 163 165 $hook = "#!/bin/sh\n{$cmd}\n"; 164 166 ··· 392 394 393 395 $path = rtrim($repository->getLocalPath(), '/'); 394 396 execx('svnadmin create -- %s', $path); 397 + } 398 + 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); 395 407 } 396 408 397 409