Page MenuHomePhabricator

D7682.diff

diff --git a/bin/commit-hook b/bin/commit-hook
new file mode 120000
--- /dev/null
+++ b/bin/commit-hook
@@ -0,0 +1 @@
+../scripts/repository/commit_hook.php
\ No newline at end of file
diff --git a/scripts/repository/commit_hook.php b/scripts/repository/commit_hook.php
new file mode 100755
--- /dev/null
+++ b/scripts/repository/commit_hook.php
@@ -0,0 +1,56 @@
+#!/usr/bin/env php
+<?php
+
+$root = dirname(dirname(dirname(__FILE__)));
+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) {
+ throw new Exception(pht('usage: commit-hook <callsign>'));
+}
+
+$repository = id(new PhabricatorRepositoryQuery())
+ ->setViewer($user)
+ ->withCallsigns(array($argv[1]))
+ ->requireCapabilities(
+ array(
+ // This capability check is redundant, but can't hurt.
+ PhabricatorPolicyCapability::CAN_VIEW,
+ DiffusionCapabilityPush::CAPABILITY,
+ ))
+ ->executeOne();
+
+if (!$repository) {
+ throw new Exception(pht('No such repository "%s"!', $callsign));
+}
+
+if (!$repository->isHosted()) {
+ // This should be redundant too, but double check just in case.
+ throw new Exception(pht('Repository "%s" is not hosted!', $callsign));
+}
+
+$stdin = @file_get_contents('php://stdin');
+if ($stdin === false) {
+ throw new Exception(pht('Failed to read stdin!'));
+}
+
+$engine = id(new DiffusionCommitHookEngine())
+ ->setViewer($user)
+ ->setRepository($repository)
+ ->setStdin($stdin);
+
+$err = $engine->execute();
+
+exit($err);
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -474,6 +474,7 @@
'DiffusionCommitChangeTableView' => 'applications/diffusion/view/DiffusionCommitChangeTableView.php',
'DiffusionCommitController' => 'applications/diffusion/controller/DiffusionCommitController.php',
'DiffusionCommitEditController' => 'applications/diffusion/controller/DiffusionCommitEditController.php',
+ 'DiffusionCommitHookEngine' => 'applications/diffusion/engine/DiffusionCommitHookEngine.php',
'DiffusionCommitParentsQuery' => 'applications/diffusion/query/parents/DiffusionCommitParentsQuery.php',
'DiffusionCommitQuery' => 'applications/diffusion/query/DiffusionCommitQuery.php',
'DiffusionCommitTagsController' => 'applications/diffusion/controller/DiffusionCommitTagsController.php',
@@ -2797,6 +2798,7 @@
'DiffusionCommitChangeTableView' => 'DiffusionView',
'DiffusionCommitController' => 'DiffusionController',
'DiffusionCommitEditController' => 'DiffusionController',
+ 'DiffusionCommitHookEngine' => 'Phobject',
'DiffusionCommitParentsQuery' => 'DiffusionQuery',
'DiffusionCommitQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'DiffusionCommitTagsController' => 'DiffusionController',
diff --git a/src/applications/diffusion/controller/DiffusionServeController.php b/src/applications/diffusion/controller/DiffusionServeController.php
--- a/src/applications/diffusion/controller/DiffusionServeController.php
+++ b/src/applications/diffusion/controller/DiffusionServeController.php
@@ -318,6 +318,7 @@
'PATH_INFO' => $request_path,
'REMOTE_USER' => $viewer->getUsername(),
+ 'PHABRICATOR_USER' => $viewer->getUsername(),
// TODO: Set these correctly.
// GIT_COMMITTER_NAME
diff --git a/src/applications/diffusion/engine/DiffusionCommitHookEngine.php b/src/applications/diffusion/engine/DiffusionCommitHookEngine.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diffusion/engine/DiffusionCommitHookEngine.php
@@ -0,0 +1,76 @@
+<?php
+
+final class DiffusionCommitHookEngine extends Phobject {
+
+ private $viewer;
+ private $repository;
+ private $stdin;
+
+ public function setStdin($stdin) {
+ $this->stdin = $stdin;
+ return $this;
+ }
+
+ public function getStdin() {
+ return $this->stdin;
+ }
+
+ public function setRepository(PhabricatorRepository $repository) {
+ $this->repository = $repository;
+ return $this;
+ }
+
+ public function getRepository() {
+ return $this->repository;
+ }
+
+ public function setViewer(PhabricatorUser $viewer) {
+ $this->viewer = $viewer;
+ return $this;
+ }
+
+ public function getViewer() {
+ return $this->viewer;
+ }
+
+ public function execute() {
+ $type = $this->getRepository()->getVersionControlSystem();
+ switch ($type) {
+ case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
+ $err = $this->executeGitHook();
+ break;
+ default:
+ throw new Exception(pht('Unsupported repository type "%s"!', $type));
+ }
+
+ return $err;
+ }
+
+ private function executeGitHook() {
+ $updates = $this->parseGitUpdates($this->getStdin());
+
+ // TODO: Do useful things.
+
+ return 0;
+ }
+
+ private function parseGitUpdates($stdin) {
+ $updates = array();
+
+ $lines = phutil_split_lines($stdin, $retain_endings = false);
+ foreach ($lines as $line) {
+ $parts = explode(' ', $line, 3);
+ if (count($parts) != 3) {
+ throw new Exception(pht('Expected "old new ref", got "%s".', $line));
+ }
+ $updates[] = array(
+ 'old' => $parts[0],
+ 'new' => $parts[1],
+ 'ref' => $parts[2],
+ );
+ }
+
+ return $updates;
+ }
+
+}
diff --git a/src/applications/diffusion/ssh/DiffusionSSHGitReceivePackWorkflow.php b/src/applications/diffusion/ssh/DiffusionSSHGitReceivePackWorkflow.php
--- a/src/applications/diffusion/ssh/DiffusionSSHGitReceivePackWorkflow.php
+++ b/src/applications/diffusion/ssh/DiffusionSSHGitReceivePackWorkflow.php
@@ -25,7 +25,8 @@
$command = csprintf('git-receive-pack %s', $repository->getLocalPath());
$command = PhabricatorDaemon::sudoCommandAsDaemonUser($command);
- $future = new ExecFuture('%C', $command);
+ $future = id(new ExecFuture('%C', $command))
+ ->setEnv($this->getEnvironment());
$err = $this->newPassthruCommand()
->setIOChannel($this->getIOChannel())
diff --git a/src/applications/diffusion/ssh/DiffusionSSHGitUploadPackWorkflow.php b/src/applications/diffusion/ssh/DiffusionSSHGitUploadPackWorkflow.php
--- a/src/applications/diffusion/ssh/DiffusionSSHGitUploadPackWorkflow.php
+++ b/src/applications/diffusion/ssh/DiffusionSSHGitUploadPackWorkflow.php
@@ -22,7 +22,8 @@
$command = csprintf('git-upload-pack -- %s', $repository->getLocalPath());
$command = PhabricatorDaemon::sudoCommandAsDaemonUser($command);
- $future = new ExecFuture('%C', $command);
+ $future = id(new ExecFuture('%C', $command))
+ ->setEnv($this->getEnvironment());
$err = $this->newPassthruCommand()
->setIOChannel($this->getIOChannel())
diff --git a/src/applications/diffusion/ssh/DiffusionSSHWorkflow.php b/src/applications/diffusion/ssh/DiffusionSSHWorkflow.php
--- a/src/applications/diffusion/ssh/DiffusionSSHWorkflow.php
+++ b/src/applications/diffusion/ssh/DiffusionSSHWorkflow.php
@@ -17,6 +17,12 @@
return $this->args;
}
+ public function getEnvironment() {
+ return array(
+ 'PHABRICATOR_USER' => $this->getUser()->getUsername(),
+ );
+ }
+
abstract protected function executeRepositoryOperations();
protected function writeError($message) {
diff --git a/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php b/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php
--- a/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php
+++ b/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php
@@ -83,11 +83,15 @@
}
} else {
if ($repository->isHosted()) {
- $this->logPull(
- pht(
- "Repository '%s' is hosted, so Phabricator does not pull ".
- "updates for it.",
- $callsign));
+ if ($is_git) {
+ $this->installGitHook();
+ } else {
+ $this->logPull(
+ pht(
+ "Repository '%s' is hosted, so Phabricator does not pull ".
+ "updates for it.",
+ $callsign));
+ }
} else {
$this->logPull(
pht(
@@ -146,6 +150,22 @@
));
}
+ private function installHook($path) {
+ $this->log('%s', pht('Installing commit hook to "%s"...', $path));
+
+ $repository = $this->getRepository();
+ $callsign = $repository->getCallsign();
+
+ $root = dirname(phutil_get_library_root('phabricator'));
+ $bin = $root.'/bin/commit-hook';
+ $cmd = csprintf('exec -- %s %s', $bin, $callsign);
+
+ $hook = "#!/bin/sh\n{$cmd}\n";
+
+ Filesystem::writeFile($path, $hook);
+ Filesystem::changePermissions($path, 0755);
+ }
+
/* -( Pulling Git Working Copies )----------------------------------------- */
@@ -279,6 +299,23 @@
}
+ /**
+ * @task git
+ */
+ private function installGitHook() {
+ $repository = $this->getRepository();
+ $path = $repository->getLocalPath();
+
+ if ($repository->isWorkingCopyBare()) {
+ $path .= 'hooks/pre-receive';
+ } else {
+ $path .= '.git/hooks/pre-receive';
+ }
+
+ $this->installHook($path);
+ }
+
+
/* -( Pulling Mercurial Working Copies )----------------------------------- */
@@ -357,4 +394,5 @@
execx('svnadmin create -- %s', $path);
}
+
}

File Metadata

Mime Type
text/x-diff
Storage Engine
amazon-s3
Storage Format
Raw Data
Storage Handle
phabricator/eh/5r/mkm2ipvynxqgvphf
Default Alt Text
D7682.diff (9 KB)

Event Timeline