Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2892004
commit_hook.php
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
7 KB
Referenced Files
None
Subscribers
None
commit_hook.php
View Options
#!/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.
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
=
new
DiffusionCommitHookEngine
(
)
;
$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
(
!
strlen
(
$username
)
)
{
throw
new
Exception
(
pht
(
'No Direct Pushes: You are pushing directly to a repository hosted '
.
'by Phabricator. 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
(
strlen
(
$remote_address
)
)
{
$engine
->
setRemoteAddress
(
$remote_address
)
;
}
$remote_protocol
=
getenv
(
DiffusionCommitHookEngine
::
ENV_REMOTE_PROTOCOL
)
;
if
(
strlen
(
$remote_protocol
)
)
{
$engine
->
setRemoteProtocol
(
$remote_protocol
)
;
}
$request_identifier
=
getenv
(
DiffusionCommitHookEngine
::
ENV_REQUEST
)
;
if
(
strlen
(
$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
)
;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Jan 19, 16:03 (2 w, 6 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1126302
Default Alt Text
commit_hook.php (7 KB)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment