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)