bk triggers(7.3ce) BitKeeper User's Manual bk triggers(7.3ce)
NAME
bk triggers - using BitKeeper event triggers
DESCRIPTION
BitKeeper supports a variety of trigger types. Triggers are simple
programs, usually shell scripts, which may be called before and/or
after certain events, such as a commit, pull, push, resolve, etc.
Triggers can be used for event notification and/or to implement control
over the events themselves.
When a trigger is called, it is called with the current working direc-
tory set to the root of the repository. Note that in the case of
incoming data, the root of the repository is defined as the RESYNC
directory.
If an incoming changeset adds or updates a trigger, the incoming trig-
ger is not the trigger fired, with the exception of the post-incoming
trigger. The trigger already present in the repository, if any, is the
trigger used. This arrangement is for security reasons; incoming
changes could be malicious or ill advised and a prudent repository man-
ager may have developed triggers to look for problems. If the incoming
data contained a new or modified trigger, and that trigger was run,
triggers could not be used to implement security or other policies at
the repository boundary.
TRIGGER NAMES
When an event occurs, if there exists a file BitKeeper/trig-
gers/event_class in the repository root that corresponds to the event,
BitKeeper will execute that trigger. For example, if there is a push
from repository B going into repository A and repository A has a file
BitKeeper/triggers/pre-incoming, the pre-incoming script will be run
before the push event applies to repository A.
All triggers for a particular class must be named with the class name
and prefix, for example pre-incoming-ok. More than one trigger per
event class is allowed; each trigger program has the class name and
prefix and a suffix of your choosing. The trigger programs are sorted
and run alphabetically (C locale sort order).
If there are multiple pre- triggers (see below), the first trigger to
exit with a non-zero status will halt the trigger processing. If there
are pre- triggers that must always be run, they must be named such that
their name will sort earlier than any other trigger of that class.
In order to avoid name space conflicts, the typical approach is to use
the reason for the trigger as the suffix, i.e.,
post-incoming.mail
post-incoming.regression-test
Files ending in ~ are ignored to avoid editor backup files.
TRIGGER PATHS
By default, triggers are stored in the repository under the Bit-
Keeper/triggers/ directory and this is the only directory searched when
looking for triggers. More than one triggers directory may be used by
setting the triggers variable. The format is one or more paths sepa-
rated by a vertical bar, each path has "BitKeeper/triggers" appended to
it and the resulting path is scanned for triggers. For example, if you
wanted to run triggers from /etc/BitKeeper/triggers and from the repos-
itories' BitKeeper/triggers, set the variable as follows in your con-
figuration:
triggers: /etc|.
The directories are processed in the order found in the variable.
There are several special values which are interpreted:
. It means `bk -R pwd`/BitKeeper/triggers is scanned for triggers.
$BK_DOTBK
If present, `bk dotbk`/BitKeeper/triggers is scanned for triggers.
$BK_BIN
If present, `bk bin`/BitKeeper/triggers is scanned for triggers.
$NONE
If present, with no other values, then no triggers are processed.
$PRODUCT
If present, `bk -P pwd`/BitKeeper/triggers is scanned for triggers.
This only applies when in a component repository of a nested col-
lection. It is a way to run product level triggers in each compo-
nent.
$SOMETHING_ELSE
All other paths starting with "$" are ignored, that character is
reserved.
If the the variable is not defined, the default is:
triggers: $PRODUCT|.
TRIGGER CLASSES
There are multiple event classes which may activate triggers: incoming
events, outgoing events, deltas, commits, tags, undo, and collapses.
The incoming event is broken into multiple events: incoming, resolve,
and apply.
Most events may have triggers which run before and/or after the event.
The difference between pre- and post- event triggers is that pre-trig-
gers may cause events to fail, but post-triggers are strictly informa-
tional. The exit status from post-triggers are ignored.
Not all triggers have both pre- and post- versions, the set of sup-
ported triggers are as follows:
pre-apply
=> called after the data has been merged in the RESYNC directory but
before it is applied to the tree. Last chance to say no, allows
examination of the merged changes.
=> called in the RESYNC directory, not the enclosing repository.
=> exit 0 allows the pull/push.
=> exit 1 fails the entire pull/push.
=> exit 2 fails the pull/push but leaves the patch in PENDING.
=> exit 3 fails the pull/push but leaves the patch in PENDING and the
RESYNC tree in PENDING/RESYNC-date.
pre-collapse
=> called before a changeset is collapsed (see bk collapse). Typical-
ly used as part of a process to record the renaming of changesets
in bug tracking systems.
=> exit 0 allows the collapse.
=> non-zero exit values will fail the collapse.
pre-commit
=> called before a changeset is committed.
=> exit 0 allows the commit.
=> exit 1 fails the commit. If the commit was initiated from citool,
citool will exit. See example below.
=> exit 2 also fails the commit. However, if it was initiated from
citool, citool will not exit. This allows the user to try the com-
mit again. See example below.
post-commit
=> called after a changeset is committed or attempted to be committed.
=> typically used for notification.
pre-delta
=> called before a delta is created. Can be use for triggers that
check code style
=> exit 0 allows the delta.
=> exit 2 indicates that the trigger called delta itself, upon which
the calling delta command treats it as a successful delta.
=> Other than 2, all other non-zero exit values will fail the delta.
pre-incoming
=> called before an incoming push/pull is started.
=> non-zero exit status fails the incoming event.
=> typically used for locking down a repository.
=> may be used to fail the event based on remote user, host, directo-
ry, and/or BitKeeper version.
post-incoming
=> called after the data has been applied to the tree.
=> typically used for notification.
pre-outgoing
=> called before an outgoing pull/push/clone event.
=> non-zero exit status fails the outgoing event.
=> typically used for locking down a repository.
post-outgoing
=> called after the outgoing event.
=> typically used for notification.
pre-resolve
=> called after the data has been union-ed in the RESYNC directory.
=> called in the RESYNC directory, not the enclosing repository.
=> exit 0 allows the pull/push.
=> exit 1 fails the entire pull/push.
=> exit 2 fails the entire pull/push but leaves the patch in PENDING.
=> typically used to examine changes before taking them.
pre-tag
=> called before a tag event, such as a bk commit with a specified tag
or a bk tag.
=> exit 0 allows the tag.
=> exit 1 causes the tag operation to fail as well as the commit oper-
ation if the tag was part of a commit.
=> exit 2 causes the tag operation to fail but allows the commit oper-
ation to proceed if the tag was part of a commit.
pre-undo
=> called before a undo is run by user or by unpull and clone -r.
=> exit 0 allows the undo.
=> exit 1 causes the undo operation to fail.
post-undo
=> called after an undo is run successfully.
TRIGGER LOCKING
Triggers are called with a locked repository. When a post trigger is
called, the repository is read locked, even in the case that the event
was an event which changed the repository. A read lock will allow the
trigger to do outgoing events, such as a push, but will prevent incom-
ing events. Pre-incoming and pre-commit triggers will be called with a
write locked repository.
TRIGGER SECURITY ISSUES
Triggers are arbitrary programs (or scripts) which are run automatical-
ly and without warning. It is possible that a malicious person could
add a trigger which effect a security breach, damage files, etc. If
you are operating in a non-trusted environment, you may disable all
triggers by setting the BK_NO_TRIGGERS environment variable. This is
the safest thing to do but then the trigger functionality is lost.
Alternatively, a "paranoid" trigger could be added which refused to ac-
cept a new trigger into a repository without being examined first.
Here's an example of such a trigger, which would typically be named
BitKeeper/triggers/pre-apply.paranoid:
#!/bin/sh
# This is running in the RESYNC tree, we're looking
# for any new triggers and/or changes to triggers.
# Done after the resolve stage because they could
# be sneaky and create the file in an earlier
# changeset and then move it.
test `bk gfiles BitKeeper/triggers | wc -l` -gt 0 || exit 0
if [ $BK_SIDE = server ]
then echo Refusing to accept any changes to triggers on push,
echo get the project admin to pull your changes.
exit 1
fi
rm -f BitKeeper/tmp/t_reject
for i in `bk gfiles BitKeeper/triggers`
do (
echo Please review the following trigger for security risks.
echo Do not accept it if you think it is a problem.
echo
echo ===== $i =====
bk cat $i
) > BitKeeper/tmp/prompt$$
bk prompt -fBitKeeper/tmp/prompt$$ \
-t"Review trigger" -yAccept -nReject
STATUS=$?
rm -f BitKeeper/tmp/prompt$$
test $STATUS = 0 || {
touch BitKeeper/tmp/t_reject
break
}
done
test -f BitKeeper/tmp/t_reject && {
rm -f BitKeeper/tmp/t_reject
exit 3
}
rm -f BitKeeper/tmp/t_reject
exit 0
TRIGGER ENVIRONMENT VARIABLES
Information which might be useful to the trigger is passed in environ-
ment variables. There are variables for user, host, location, BitKeep-
er version, repository level, amongst others. There are two classes of
variables, client side variables (BK_*) and server side variables
(BKD_*). The client side variables are associated with the user who
initiated the command. The server side variables, if present, are as-
sociated with the "other" repository. For example, if a user on host
"to" does a pull from host "from", then BK_HOST=to and BKD_HOST=from.
In the list of variables which follow, BKD_* variables are not present
unless the command has two end points, such as a pull, push, or clone.
The BKD_* variables are not defined for commit, resolve, and apply
events. In all other cases, the variable is present in all triggers
unless otherwise stated.
BK_CSETLIST If set, contains the name of a file which contains the
list of changesets being received. Valid in pre-apply,
post-incoming pre-outgoing, post-outgoing, pre-resolve,
and pre-undo triggers.
BK_CSETS If set, contains the list of changesets being sent.
Valid only in pre-outgoing and post-outgoing clone
events.
BK_COMMENTFILE Location of the comment file for the changeset. Useful
when writing triggers that need to parse the changeset
comments. See example below.
BK_EVENT The event from the point of view of the trigger. The
full list of values for this variable is: apply, col-
lapse, commit, delta, fix, incoming clone, incoming
port, incoming pull, incoming push, outgoing clone, out-
going pull, outgoing push, resolve, tag, and undo.
BK_FILE Valid only in the pre-delta trigger, and contains the
filename of the file about to be delta-ed, relative to
the repository root.
BK_HOST The hostname of the client side host.
BKD_HOST The hostname of the server side host.
BK_LEVEL The "level" of the client side repository.
BKD_LEVEL The "level" of the server side repository.
BK_LOCALCSETS The number of changesets (and/or tags) which are not
present in the remote repository but are present in the
local repository. Note that this variable does not have
a BKD_ version because it is valid only on the outgoing
end of a pull or a push. The other variable is BK_RE-
MOTECSETS. Both variables are valid in pre-outgoing and
post-outgoing triggers only.
BK_REPO_TYPE The repository type. One of product, component, or
standalone.
BKD_REPO_TYPE As above.
BK_PATCH Valid only in the pre-resolve trigger, and contains the
full pathname of the file containing the patch being re-
solved.
BK_PENDING Contains the name of a file which contains the list of
files with pending deltas. Valid only in pre-commit.
BK_REMOTECSETS The number of remote changesets (and/or tags) which are
not present in the local repository but are present in
the remote repository. Goes with BK_LOCALCSETS and is
valid only in pre-outgoing and post-outgoing triggers.
BK_ROOT The full path name to the root of the client side repos-
itory.
BKD_ROOT The full path name to the root of the server side repos-
itory.
BK_SIDE If the trigger is part of a two-sided operation (i.e.,
pull, push), then this is set to "server" if the trigger
is running on the server repository. Otherwise this is
set to "client."
BK_STATUS The status of the command, if known. Values may in-
clude:
NOTHING There was nothing to pull or push.
FAILED The command did not complete because of an error.
DRYRUN The command did not complete because it was a "dry run,"
i.e., a "bk pull -n" to look to see if there is anything
to pull.
CONFLICTS The command did not complete because there were con-
flicts (parallel work).
LOCAL_WORK The command did not complete because there is local work
and an update only operation was requested.
SIGNALED The command did not complete because it received a sig-
nal.
OK The command completed successfully.
UNKNOWN Unknown status.
BK_TAG If set, contains the value of the symbolic tag to be
added to the repository. Valid only in pre-tag trigger.
BK_TAG_REV If set, contains the changeset revision on which the tag
will be placed. This will be set if and only if the re-
vision is not the most recent revision. Valid only in
pre-tag trigger.
BK_TIME_T The UNIX style time stamp of the client side BitKeeper
binary.
BKD_TIME_T The UNIX style time stamp of the server side BitKeeper
binary.
BK_TRIGGER The basename name of the trigger program.
BK_USER The user name of the user who ran the command on the
client.
BKD_USER The user name of the user who ran the command on the
server.
BK_UTC The time stamp of the client side BitKeeper binary ex-
pressed as YYYYMMDDHHMMSS.
BKD_UTC The time stamp of the server side BitKeeper binary ex-
pressed as YYYYMMDDHHMMSS.
BK_VERSION The version of the client side BitKeeper binary as the
symbolic name or the UTC.
BKD_VERSION The version of the server side BitKeeper binary as the
symbolic name or the UTC.
EXAMPLE 1
#!/bin/sh
# Simple post-commit trigger for email notification of changes
# For nested collections, we don't want notification in components,
# the product recurses.
test `bk repotype` = "component" && exit 0
# Let bk changes do all the work for us.
bk changes -vvr+ |
mail -s "commit in `bk gethost -r`:`bk pwd` bk $BK_USER"
exit 0
EXAMPLE 2
#!/bin/sh
# Display info about incoming and outgoing csets.
if [ X$BK_STATUS = XDRYRUN -o X$BK_STATUS = XNOTHING ]
then exit 0
fi
if [ $BK_SIDE = server ]
then U=$BKD_USER
H=$BKD_HOST
R=$BKD_ROOT
else U=$BK_USER
H=$BK_HOST
R=$BK_ROOT
fi
(
if [ X$BKD_ROOT != X ]
then printf '%-10s%-20s%-20s\n' VAR CLIENT SERVER
printf '%-10s%-20s%-20s\n' === ====== ======
printf '%-10s%-20s%-20s\n' USER $BK_USER $BKD_USER
printf '%-10s%-20s%-20s\n' HOST $BK_HOST $BKD_HOST
printf '%-10s%-20s%-20s\n' ROOT $BK_ROOT $BKD_ROOT
printf '%-10s%-20s%-20s\n' LEVEL $BK_LEVEL $BKD_LEVEL
printf '%-10s%-20s%-20s\n' TIME_T $BK_TIME_T $BKD_TIME_T
printf '%-10s%-20s%-20s\n' UTC $BK_UTC $BKD_UTC
printf '%-10s%-20s%-20s\n' VERSION $BK_VERSION $BKD_VERSION
echo
fi
echo ${U}@${H} fired the $BK_TRIGGER trigger in $R
case $BK_TRIGGER in
pre-outgoing) VERB=Sending;;
post-outgoing) VERB=Sent;;
pre-incoming) VERB=Receiving;;
post-incoming) VERB=Received;;
pre-resolve) VERB=Resolving;;
pre-commit) VERB=Committing;;
post-commit) VERB=Committed;;
pre-apply) VERB=Applying;;
esac
if [ X$BK_PENDING != X ]
then (
echo $VERB the following deltas
echo
bk log - < $BK_PENDING
) | sed 's/^/ /'
fi
if [ X$BK_CSETLIST != X ]
then (
echo $VERB the following changesets
echo
bk changes -v - < $BK_CSETLIST
) | sed 's/^/ /'
fi
if [ X$BK_CSETS != X ]
then (
echo $VERB the following changesets
echo
bk changes -v -r$BK_CSETS
) | sed 's/^/ /'
fi
) | mail -s "$BK_EVENT in ${H}:${R}" notify@bitkeeper.com
EXAMPLE 3
#!/bin/sh
#
# Using pre-commit trigger to verify changeset comment
# BitKeeper/trigger/pre-commit.cset_comments
#
# only run in the product (or a traditional repo)
bk repotype -q
test $? -eq 1 && exit 0
# if this is a merge, we are in the RESYNC directory
# since it is not a user cset, ignore
test "`basename "$BK_ROOT"`" = "RESYNC" && exit 0
grep -q 'BUGID:' $BK_COMMENTFILE && exit 0
msg="A 'BUGID:' field is needed in the checkin comments"
# Bring up an external program to browse bugs so that the
# engineer can add a valid bugid to the changeset comments.
#/opt/bugtrack/bin/bugviewer 'http://server.host.com/bugs?status=open' &
# Ask user if he needs to enter a bugid. returning an exit code of 2
# from the trigger will allow user to retry the commit from
# within citool.
bk prompt -y"Reenter bugid" -n"Force commit with no bugid" "$msg" && exit 2
# If you wish to provide the option to fail out of citool, use this.
#bk prompt -y"Abort commit" -n"Force commit with no bugid" "$msg" && exit 1
exit 0
EXAMPLE 4
#!/bin/sh
#
# Using a pre-collapse trigger to checks to see if the key is in
# some repo that is frozen.
bk changes -R bk://work/bk-4.0.x - < $BK_CSETS > /tmp/csets$$
OK=0
test -s /tmp/csets$$ && OK=1
rm -f /tmp/csets$$
exit $OK
EXAMPLE 5
#!/bin/sh
#
# A post-incoming trigger that will push incoming changesets
# to a mirror repository
MIRROR=REPO-mirror
# Debug
#Q=
#OUT=/tmp/OUT
# Quiet
Q=-q
OUT=/dev/null
# Do not run in components
test `bk repotype` = component && exit 0
# Only run on successful pulls/pushes
test "$BK_EVENT" = "incoming clone" && exit 0
test "$BK_STATUS" != "OK" && exit 0
# Foreground mirror - incoming operation will block
# until the mirror push is complete
#bk push $Q "$MIRROR"
#exit 0
# Background mirror
# Start a background process to push the incoming
# changesets to a mirror repository
#
(
# Avoid possible race, wait for any locks to be dropped
bk lock -U
bk push $Q "$MIRROR"
) > $OUT 2>&1 &
SEE ALSO
bk clone
bk changes
bk commit
bk collapse
bk delta
bk prompt
bk pull
bk push
bk re-solve
bk repotype
bk tag
CATEGORY
Repository
BitKeeper Inc 1E1 bk triggers(7.3ce)