Something went wrong. Try again.
@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
Something went wrong. Try again.
7.8 kB · 245 lines
PHP
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246#!/usr/bin/env php<?php
// NOTE: This script will sometimes emit a warning like this on startup://// No entry for terminal type "unknown";// using dumb terminal settings.//// This can be fixed by adding "TERM=dumb" to the shebang line, but doing so// causes some systems to hang mysteriously. See T7119.
// Commit hooks execute in an unusual context where the environment may be// unavailable, particularly in SVN. The first parameter to this script is// either a bare repository identifier ("X"), or a repository identifier// followed by an instance identifier ("X:instance"). If we have an instance// identifier, unpack it into the environment before we start up. This allows// subclasses of PhabricatorConfigSiteSource to read it and build an instance// environment.
$hook_start = microtime(true);
if ($argc > 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 <repository>'));}
$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 ($username !== false) { 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 <repository> <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 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 ($remote_address !== false) { if (phutil_nonempty_string($remote_address)) { $engine->setRemoteAddress($remote_address); }}
$remote_protocol = getenv(DiffusionCommitHookEngine::ENV_REMOTE_PROTOCOL);if ($remote_protocol !== false) { if (phutil_nonempty_string($remote_protocol)) { $engine->setRemoteProtocol($remote_protocol); }}
$request_identifier = getenv(DiffusionCommitHookEngine::ENV_REQUEST);if ($request_identifier !== false) { 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(<<<EOTXT+---------------------------------------------------------------+| * * * PUSH REJECTED BY EVIL DRAGON BUREAUCRATS * * * |+---------------------------------------------------------------+ \ \ ^ /^ \ / \ // \ \ |\___/| / \// .\ \ /V V \__ / // | \ \ *----* / / \/_/ // | \ \ \ | @___@` \/_ // | \ \ \/\ \ 0/0/| \/_ // | \ \ \ \ 0/0/0/0/| \/// | \ \ | | 0/0/0/0/0/_|_ / ( // | \ _\ | / 0/0/0/0/0/0/`/,_ _ _/ ) ; -. | _ _\.-~ / / ,-} _ *-.|.-~-. .~ ~ * \__/ `/\ / ~-. _ .-~ / \____(Oo) *. } { / ( (..) .----~-.\ \-` .~ //___\\\\ \ DENIED! ///.----..< \ _ -~ // \\\\ ///-._ _ _ _ _ _ _{^ - - - - ~
EOTXT); }
$console->writeErr("%s\n\n", $preamble); $console->writeErr("%s\n\n", $ex->getMessage()); $err = 1;}
exit($err);