Advertisement
p4geoff

Untitled

Dec 4th, 2013
295
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 13.70 KB | None | 0 0
  1. #!/bin/bash
  2. #
  3. # Perforce Swarm Trigger Script
  4. #
  5. # @copyright   2013 Perforce Software. All rights reserved.
  6. # @version     <release>/<patch>
  7. #
  8. # This script is meant to be called from a Perforce trigger.
  9. # It should be placed on the Perforce Server machine.
  10. # See usage information below for more details.
  11.  
  12. # ------------------------------------------------------------------ #
  13. # This script requires certain variables to operate correctly
  14. # By default, you can modify this script and manually change the
  15. # values in-place.
  16. # However, if you prefer to separate the configuration from this
  17. # script, define TRIGGER_CONFIG and ensure it points to a valid
  18. # file with the necessary variables defined (see below).
  19.  
  20. # TRIGGER_CONFIG (optional)
  21. # If set and the file exists, it will be sourced (below).
  22. # This is useful to separate configuration from this script.
  23. #TRIGGER_CONFIG="/etc/swarm-trigger.conf"
  24.  
  25. # SWARM_HOST (required)
  26. # Hostname of your Swarm instance, with leading "http://" or "https://".
  27. SWARM_HOST="http://my-swarm-host"
  28.  
  29. # SWARM_TOKEN (required)
  30. # The token used when talking to Swarm to offer some security.
  31. # To obtain the value, log in to Swarm as a super user and select
  32. #'About Swarm' to see the token value.
  33. SWARM_TOKEN="MY-UUID-STYLE-TOKEN"
  34.  
  35. # ADMIN_USER (optional)
  36. # For enforcing reviewed changes, optionally specify the Perforce
  37. # user with admin privileges (to read keys); if not set, will use
  38. # whatever Perforce user is set in environment.
  39. #ADMIN_USER=
  40.  
  41. # ADMIN_TICKET_FILE (optional)
  42. # For enforcing reviewed changes, optionally specify the location of
  43. # the p4tickets file if different from the default ($HOME/.p4tickets).
  44. # Ensure this user is a member of a group with an 'unlimited' or very
  45. # long timeout; then, manually login as this user from the Perforce
  46. # server machine to set the ticket.
  47. #ADMIN_TICKET_FILE=
  48.  
  49. # LOGGER (optional, default set here)
  50. # For logging errors, we use the 'logger' command. If it is not
  51. # available in the PATH of the environment in which Perforce trigger
  52. # scripts run, specify the full path here.
  53. LOGGER="logger"
  54.  
  55. # P4, SED & GREP: (optional, defaults set here)
  56. # For 'enforce' and 'strict' types, we use the following utilities.
  57. # If they are not availabe in the PATH of the environment in which
  58. # Perforce trigger scripts run, specify the full path of the utility
  59. # here.
  60. P4="p4"
  61. SED="sed"
  62. GREP="grep"
  63.  
  64. # DO NOT EDIT PAST THIS LINE --------------------------------------- #
  65.  
  66. # Source the default configuration file if set and readable. Variables
  67. # contained in this file will override any variables defined above.
  68. [ ! -z "$TRIGGER_CONFIG" ] && [ -r "$TRIGGER_CONFIG" ] &&
  69.     source "$TRIGGER_CONFIG"
  70.  
  71. ME=${0##*/}
  72. MYDIR=`cd $(dirname $0) && pwd`
  73. function usage
  74. {
  75.     cat << ! >&2
  76. Usage: $ME ( -t <type> -v <value> [-p <p4port>] [-g <group-to-exclude>] | -o )
  77.     -t: specify the Swarm trigger type (e.g. job, shelve, commit)
  78.     -v: specify the ID value
  79.     -p: specify optional (recommended) P4PORT, only intended for
  80.         '-t enforce' or '-t strict'
  81.     -r: when using '-t strict' or '-t enforce', only apply this check
  82.         to changes that are in review.
  83.     -g: specify optional group to exclude for '-t enforce' or
  84.        '-t strict'; members of this group, or subgroups thereof will
  85.        not be subject to these triggers
  86.     -o: convenience flag to output the trigger lines
  87.  
  88. This script is meant to be called from a Perforce trigger. It should
  89. be placed on the Perforce Server machine and the following entries
  90. should be added using 'p4 triggers' (use the -o flag to this script
  91. to only output these lines):
  92.  
  93. $TRIGGER_ENTRIES
  94. Notes:
  95.  
  96. * The use of '%quote%' is not supported on 2010.2 servers (they are
  97.   harmless though); if you're using this version, ensure you don't
  98.   have any spaces in the pathname to this script.
  99.  
  100. * Be sure to configure this script with knowledge of your Swarm host
  101.   and token prior to installing it. Configuration details can be
  102.   found near the top of the script.
  103.  
  104. * For 'enforce' triggers (enforce that a change to be submitted is
  105.   tied to an approved review), or 'strict' triggers (verify that the
  106.   content of a change to be submitted matches the content of its
  107.   associated approved review), uncomment the appropriate lines and
  108.   replace DEPOT_PATH as appropriate. For additional paths to check,
  109.   increment the trigger name suffix so that each trigger name is
  110.   named uniquely.
  111.  
  112. * For 'enforce' or 'strict' triggers, you can optionally specify a
  113.   group whose members will not be subject to these triggers.
  114.  
  115. * For 'enforce' or 'strict' triggers, if your Perforce Server is
  116.   SSL-enabled, add the "ssl:" protocol prefix to "%serverport%".
  117.  
  118. !
  119.     exit 99
  120. }
  121.  
  122. # Define the trigger entries suitable for this script; replace depot paths as appropriate
  123. IFS='' read -d '' -r TRIGGER_ENTRIES <<EOF-TRIGGER
  124.     swarm.job      form-commit   job    "%quote%$MYDIR/$ME%quote% -t job      -v %formname%"
  125.     swarm.user     form-commit   user   "%quote%$MYDIR/$ME%quote% -t user     -v %formname%"
  126.     swarm.userdel  form-delete   user   "%quote%$MYDIR/$ME%quote% -t userdel  -v %formname%"
  127.     swarm.group    form-commit   group  "%quote%$MYDIR/$ME%quote% -t group    -v %formname%"
  128.     swarm.groupdel form-delete   group  "%quote%$MYDIR/$ME%quote% -t groupdel -v %formname%"
  129.     swarm.change   form-commit   change "%quote%$MYDIR/$ME%quote% -t change   -v %formname%"
  130.     swarm.shelve   shelve-commit //...  "%quote%$MYDIR/$ME%quote% -t shelve   -v %change%"
  131.     swarm.commit   change-commit //...  "%quote%$MYDIR/$ME%quote% -t commit   -v %change%"
  132.     #swarm.enforce.1 change-submit  //DEPOT_PATH1/... "%quote%$MYDIR/$ME%quote% -t enforce -v %change% -p %serverport%"
  133.     #swarm.enforce.2 change-submit  //DEPOT_PATH2/... "%quote%$MYDIR/$ME%quote% -t enforce -v %change% -p %serverport%"
  134.     #swarm.strict.1  change-content //DEPOT_PATH1/... "%quote%$MYDIR/$ME%quote% -t strict -v %change% -p %serverport%"
  135.     #swarm.strict.2  change-content //DEPOT_PATH2/... "%quote%$MYDIR/$ME%quote% -t strict -v %change% -p %serverport%"
  136. EOF-TRIGGER
  137.  
  138. # Show the usage if no arguments passed
  139. [ -z "$1" ] && usage
  140.  
  141. # Trap call to self to post to Swarm
  142. BACKGROUND_FLAG="background-call"
  143. if [ "$1" == "$BACKGROUND_FLAG" ]
  144. then
  145.     TYPE="$2"
  146.     VALUE="$3"
  147.  
  148.     # We assume SWARM_HOST and SWARM_TOKEN are properly set at this point
  149.     SWARM_QUEUE="$SWARM_HOST/queue/add/$SWARM_TOKEN"
  150.  
  151.     UTIL="wget"
  152.     wget --quiet --output-document /dev/null --timeout 10 --post-data ${TYPE},${VALUE} ${SWARM_QUEUE}
  153.     RC=$?
  154.  
  155.     # If wget command is not found (http://tldp.org/LDP/abs/html/exitcodes.html), try curl
  156.     if [ $RC -eq 127 ]
  157.     then
  158.         UTIL="curl"
  159.         curl --silent --output /dev/null --max-time 10 --data ${TYPE},${VALUE} ${SWARM_QUEUE}
  160.         RC=$?
  161.     fi
  162.  
  163.     if [ $RC -ne 0 ]
  164.     then
  165.         $LOGGER -p3 -t $ME "Error ($RC) trying to post [$TYPE,$VALUE] via [$UTIL] to [$SWARM_QUEUE]"
  166.     fi
  167.  
  168.     exit 0
  169. fi
  170.  
  171. # Sanity check default arguments
  172. if ! command -v "$LOGGER" > /dev/null
  173. then
  174.     echo "$ME: Error: LOGGER is not set properly in this script; please contact your administrator."
  175.     exit 1
  176. fi
  177.  
  178. # Default flag(s)
  179. CHECK_REVIEW_CHANGES_ONLY=0
  180.  
  181. # Parse arguments
  182. while getopts :t:v:p:g:roh OPT
  183. do
  184.     case "$OPT" in
  185.     t)  TYPE="$OPTARG" ;;
  186.     v)  VALUE="$OPTARG" ;;
  187.     p)  P4_PORT="$OPTARG" ;;
  188.     r)  CHECK_REVIEW_CHANGES_ONLY=1 ;;
  189.     g)  GROUP="$OPTARG" ;;
  190.     o)  echo "$TRIGGER_ENTRIES"; exit 0 ;;
  191.     h)  usage ;;
  192.     *)  $LOGGER -p3 -t $ME -s "unknown argument [-$OPTARG]" && usage ;;
  193.     esac
  194. done
  195.  
  196. # Sanity check supplied arguments
  197. [ -z "$TYPE" ]  && $LOGGER -p3 -t $ME -s "no event type supplied" && usage
  198. [ -z "$VALUE" ] && $LOGGER -p3 -t $ME -s "$TYPE: no value supplied" && usage
  199.  
  200. # If -t enforce/strict is specified, perform that logic here
  201. if [ "$TYPE" == "enforce" -o "$TYPE" == "strict" ]
  202. then
  203.     # Set up how we call p4
  204.     P4_CMD="$P4 -zprog=p4($ME)"
  205.     [ ! -z "$P4_PORT" ]    && P4_CMD="$P4_CMD -p $P4_PORT"
  206.     [ ! -z "$ADMIN_USER" ] && P4_CMD="$P4_CMD -u $ADMIN_USER"
  207.  
  208.     [ ! -z "$ADMIN_TICKET_FILE" ] && export P4TICKETS="$ADMIN_TICKET_FILE"
  209.  
  210.     # Verify our credentials
  211.     if ! $P4_CMD login -s > /dev/null 2>&1
  212.     then
  213.         echo "Invalid login credentials within this trigger script; please contact your administrator."
  214.         logger -p3 -t $ME "$TYPE: reject change $VALUE: invalid login credentials"
  215.         exit 1
  216.     fi
  217.  
  218.     # Check if a group was specified
  219.     if [ ! -z "$GROUP" ]
  220.     then
  221.         # Obtain the user from the change
  222.         CHANGE_USER=`$P4_CMD -ztag change -o $VALUE | $SED -n '/^\.\.\. User /s///p'`
  223.  
  224.         # Check the user's groups and see if the group to exclude is there
  225.         if [ ! -z "$CHANGE_USER" ] &&
  226.             $P4_CMD groups -i -u "$CHANGE_USER" | $GREP -qx "$GROUP"
  227.         then
  228.             # User belong to group to exclude, exit cleanly
  229.             $LOGGER -p5 -t $ME "$TYPE: accept change $VALUE: $CHANGE_USER belongs to exempt group $GROUP"
  230.             exit 0
  231.         fi
  232.     fi
  233.  
  234.     # Search for the review key based on the encoded change number
  235.     CMD="$P4_CMD search 1301=$(echo $VALUE | $SED -e 's,\(.\),3\1,g')"
  236.     REVIEW_KEY=`$CMD | $SED '1q'`
  237.     RC=$?
  238.  
  239.     # Detect if there is any problem with the command
  240.     if [ $RC -ne 0 ]
  241.     then
  242.         echo "Error searching Perforce for reviews involving this change ($VALUE); please contact your administrator."
  243.         $LOGGER -p3 -t $ME "$TYPE: reject change $VALUE: error ($RC) from [$CMD]"
  244.         exit $RC
  245.     fi
  246.  
  247.     # Detect if no review is found
  248.     if [ -z "$REVIEW_KEY" ]
  249.     then
  250.         # if enforcement is only set for reviews, exit happy for changes not associated to any
  251.         if [ $CHECK_REVIEW_CHANGES_ONLY -eq 1 ]
  252.         then
  253.             exit 0
  254.         fi
  255.  
  256.         echo "Cannot find a Swarm review associated with this change ($VALUE)."
  257.         $LOGGER -p5 -t $ME "$TYPE: reject change $VALUE: no Swarm review found"
  258.         exit 1
  259.     fi
  260.  
  261.     # Detect if the key name is badly formated
  262.     if ! echo "$REVIEW_KEY" | $GREP -qx "swarm-review-[0-9a-f]*"
  263.     then
  264.         echo "Bad review key for this change ($VALUE); please contact your administrator."
  265.         logger -p3 -t $ME "$TYPE: reject change $VALUE: bad Swarm review key ($REVIEW_KEY)"
  266.         exit 1
  267.     fi
  268.  
  269.     # Obtain the JSON value of the associated review
  270.     CMD="$P4_CMD counter -u $REVIEW_KEY"
  271.     REVIEW_JSON=`$CMD`
  272.     RC=$?
  273.  
  274.     # Detect if there is an error or no value for the key (stale index?)
  275.     if [ $RC -ne 0 -o -z "$REVIEW_JSON" ]
  276.     then
  277.         echo "Cannot find Swarm review data for this change ($VALUE)."
  278.         $LOGGER -p4 -t $ME "$TYPE: reject change $VALUE: empty value for $REVIEW_KEY"
  279.         exit 1
  280.     fi
  281.  
  282.     # Calculate the human friendly review ID
  283.     REVIEW_ID="$(($((0xffffffff))-$((0x${REVIEW_KEY##swarm-review-}))))"
  284.  
  285.     # Locate the change inside the review's associated changes
  286.     REVIEW_CHANGES=`echo "$REVIEW_JSON" | $SED -ne 's/.*\"changes\":\[\([0-9, ]*\)\].*/\1/p'`
  287.     if [ -z "$REVIEW_CHANGES" -o -z "`echo $REVIEW_CHANGES | $GREP -w $VALUE`" ]
  288.     then
  289.         echo "This change ($VALUE) is not associated with its linked Swarm review $REVIEW_ID."
  290.         $LOGGER -p5 -t $ME "$TYPE: reject change $VALUE: change not part of $REVIEW_KEY ($REVIEW_ID)"
  291.         exit 1
  292.     fi
  293.  
  294.     # Obtain review state and see if it's approved
  295.     REVIEW_STATE=`echo "$REVIEW_JSON" | $SED -e 's/.*"state":"\([^"]*\)".*/\1/'`
  296.     if [ "$REVIEW_STATE" != "approved" ]
  297.     then
  298.         echo "Swarm review $REVIEW_ID for this change ($VALUE) is not approved ($REVIEW_STATE)."
  299.         $LOGGER -p5 -t $ME "$TYPE: reject change $VALUE: $REVIEW_KEY ($REVIEW_ID) not approved ($REVIEW_STATE)"
  300.         exit 1
  301.     fi
  302.  
  303.     # for -t strict, check that the change's content matches that of its review
  304.     if [ "$TYPE" == "strict" ]
  305.     then
  306.         REVIEW_FSTAT=`$P4_CMD fstat -Ol -T "depotFile, headType, digest" @=$REVIEW_ID`
  307.         RC1=$?
  308.         CHANGE_FSTAT=`$P4_CMD fstat -Ol -T "depotFile, headType, digest" @=$VALUE`
  309.         RC2=$?
  310.         if [ $RC1 -ne 0 -o $RC2 -ne 0 -o -z "$REVIEW_FSTAT" -o -z "$CHANGE_FSTAT" ]
  311.         then
  312.             echo "Error obtaining fstat output for this change ($VALUE) or its associated review ($REVIEW_ID); please contact your administrator."
  313.             $LOGGER -p3 -t $ME "$TYPE: reject change $VALUE: error obtaining fstat output for either change or review ($REVIEW_ID)"
  314.             exit 1
  315.         fi
  316.  
  317.         # check that the fstat output matches
  318.         if [ "$REVIEW_FSTAT" != "$CHANGE_FSTAT" ]
  319.         then
  320.             echo "The content of this change ($VALUE) does not match the content of the associated Swarm review ($REVIEW_ID)."
  321.             $LOGGER -p5 -t $ME "$TYPE: reject change $VALUE: content does not match review ($REVIEW_ID)"
  322.             exit 1
  323.         fi
  324.     fi
  325.  
  326.     # Return success at this point
  327.     exit 0
  328. fi
  329.  
  330. # Sanity check global variables we need for posting events to Swarm
  331. if [ -z "$SWARM_HOST" -o "$SWARM_HOST" == "http://my-swarm-host" ]
  332. then
  333.     echo "Error: SWARM_HOST is not set properly in this trigger script; please contact your administrator."
  334.     $LOGGER -p3 -t $ME  "$TYPE: SWARM_HOST empty or default; please update in this script"
  335.     exit 1
  336. fi
  337. if [ -z "$SWARM_TOKEN" -o "$SWARM_TOKEN" == "MY-UUID-STYLE-TOKEN" ]
  338. then
  339.     echo "Error: SWARM_TOKEN is not set properly in this trigger script; please contact your administrator."
  340.     $LOGGER -p3 -t $ME "$TYPE: SWARM_TOKEN empty or default; please update in this script"
  341.     exit 1
  342. fi
  343.  
  344. # For other Swarm trigger types, post the event to Swarm asynchronously
  345. # (call self, but detach to the background)
  346. $0 "$BACKGROUND_FLAG" "$TYPE" "$VALUE" > /dev/null 2>&1 < /dev/null &
  347.  
  348. # Always return success to avoid affecting Perforce users
  349. exit 0
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement