#!/usr/bin/env php 1) { $context = $argv[1]; $context = explode(':', $context, 2); $argv[1] = $context[0]; if (count($context) > 1) { $_ENV['PHABRICATOR_INSTANCE'] = $context[1]; putenv('PHABRICATOR_INSTANCE='.$context[1]); } } $root = dirname(dirname(dirname(__FILE__))); require_once $root.'/scripts/__init_script__.php'; if ($argc < 2) { throw new Exception(pht('usage: commit-hook ')); } $engine = id(new DiffusionCommitHookEngine()) ->setStartTime($hook_start); $repository = id(new PhabricatorRepositoryQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withIdentifiers(array($argv[1])) ->needProjectPHIDs(true) ->executeOne(); if (!$repository) { throw new Exception(pht('No such repository "%s"!', $argv[1])); } if (!$repository->isHosted()) { // In Mercurial, the "pretxnchangegroup" hook fires for both pulls and // pushes. Normally we only install the hook for hosted repositories, but // if a hosted repository is later converted into an observed repository we // can end up with an observed repository that has the hook installed. // If we're running hooks from an observed repository, just exit without // taking action. For more discussion, see PHI24. return 0; } $engine->setRepository($repository); $args = new PhutilArgumentParser($argv); $args->parsePartial( array( array( 'name' => 'hook-mode', 'param' => 'mode', 'help' => pht('Hook execution mode.'), ), )); $argv = array_merge( array($argv[0]), $args->getUnconsumedArgumentVector()); // Figure out which user is writing the commit. $hook_mode = $args->getArg('hook-mode'); if ($hook_mode !== null) { $known_modes = array( 'svn-revprop' => true, ); if (empty($known_modes[$hook_mode])) { throw new Exception( pht( 'Invalid Hook Mode: This hook was invoked in "%s" mode, but this '. 'is not a recognized hook mode. Valid modes are: %s.', $hook_mode, implode(', ', array_keys($known_modes)))); } } $is_svnrevprop = ($hook_mode == 'svn-revprop'); if ($is_svnrevprop) { // For now, we let these through if the repository allows dangerous changes // and prevent them if it doesn't. See T11208 for discussion. $revprop_key = $argv[5]; if ($repository->shouldAllowDangerousChanges()) { $err = 0; } else { $err = 1; $console = PhutilConsole::getConsole(); $console->writeErr( pht( "DANGEROUS CHANGE: Dangerous change protection is enabled for this ". "repository, so you can not change revision properties (you are ". "attempting to edit \"%s\").\n". "Edit the repository configuration before making dangerous changes.", $revprop_key)); } exit($err); } else if ($repository->isGit() || $repository->isHg()) { $username = getenv(DiffusionCommitHookEngine::ENV_USER); if (!phutil_nonempty_string($username)) { throw new Exception( pht( 'No Direct Pushes: You are pushing directly to a hosted repository. '. 'This will not work. See "No Direct Pushes" in the documentation '. 'for more information.')); } if ($repository->isHg()) { // We respond to several different hooks in Mercurial. $engine->setMercurialHook($argv[2]); } } else if ($repository->isSVN()) { // NOTE: In Subversion, the entire environment gets wiped so we can't read // DiffusionCommitHookEngine::ENV_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 ')); } $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 Exception(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. if ($repository->isHg()) { // Mercurial leaves stdin open, so we can't just read it until EOF. $stdin = ''; } else { // Git and Subversion write data into stdin and then close it. Read the // data. $stdin = @file_get_contents('php://stdin'); if ($stdin === false) { throw new Exception(pht('Failed to read stdin!')); } } $engine->setStdin($stdin); $engine->setOriginalArgv(array_slice($argv, 2)); $remote_address = getenv(DiffusionCommitHookEngine::ENV_REMOTE_ADDRESS); if (phutil_nonempty_string($remote_address)) { $engine->setRemoteAddress($remote_address); } $remote_protocol = getenv(DiffusionCommitHookEngine::ENV_REMOTE_PROTOCOL); if (phutil_nonempty_string($remote_protocol)) { $engine->setRemoteProtocol($remote_protocol); } $request_identifier = getenv(DiffusionCommitHookEngine::ENV_REQUEST); if (phutil_nonempty_string($request_identifier)) { $engine->setRequestIdentifier($request_identifier); } try { $err = $engine->execute(); } catch (DiffusionCommitHookRejectException $ex) { $console = PhutilConsole::getConsole(); if (PhabricatorEnv::getEnvConfig('phabricator.serious-business')) { $preamble = pht('*** PUSH REJECTED BY COMMIT HOOK ***'); } else { $preamble = pht(<<writeErr("%s\n\n", $preamble); $console->writeErr("%s\n\n", $ex->getMessage()); $err = 1; } exit($err);