send-pull-request 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. #!/bin/bash
  2. AUTO=0
  3. # Check env for any default settings, command line options will override these.
  4. if [ -z "$PULL_MTA" ]; then
  5. PULL_MTA="sendmail"
  6. fi
  7. # Prevent environment leakage to these vars.
  8. unset TO
  9. unset CC
  10. # allow the user to set FROM in the environment
  11. usage()
  12. {
  13. cat <<EOM
  14. Usage: $(basename $0) [-h] [-a] [[-t email]...] -p pull-dir
  15. -t email Explicitly add email to the recipients
  16. -a Automatically harvest recipients from "*-by: email" lines
  17. in the patches in the pull-dir
  18. -f Specify a FROM address, you can also use the FROM environment
  19. variable. If you do not specify one, it will try to use the one
  20. from your git config. This is ignored if -g is used.
  21. -g Use git-send-email to send mail instead of sendmail
  22. -p pull-dir Directory containing summary and patch files
  23. EOM
  24. }
  25. # Collect To and CC addresses from the patch files if they exist
  26. # $1: Which header to add the recipients to, "TO" or "CC"
  27. # $2: The regex to match and strip from the line with email addresses
  28. harvest_recipients()
  29. {
  30. TO_CC=$1
  31. REGX=$2
  32. export IFS=$',\n'
  33. for PATCH in $PDIR/*.patch; do
  34. # Grab To addresses
  35. for EMAIL in $(sed '/^---$/q' $PATCH | grep -e "$REGX" | sed "s/$REGX//"); do
  36. if [ "$TO_CC" == "TO" ] && [ "${TO/$EMAIL/}" == "$TO" ] && [ -n "$EMAIL" ]; then
  37. if [ -z "$TO" ]; then TO=$EMAIL; else TO="$TO,$EMAIL"; fi
  38. elif [ "$TO_CC" == "CC" ] && [ "${CC/$EMAIL/}" == "$CC" ] && [ -n "$EMAIL" ]; then
  39. if [ -z "$CC" ]; then CC=$EMAIL; else CC="$CC,$EMAIL"; fi
  40. fi
  41. done
  42. done
  43. unset IFS
  44. }
  45. # Parse and verify arguments
  46. while getopts "af:ghp:t:" OPT; do
  47. case $OPT in
  48. a)
  49. AUTO=1
  50. ;;
  51. f)
  52. FROM="$OPTARG"
  53. ;;
  54. g)
  55. PULL_MTA="git"
  56. ;;
  57. h)
  58. usage
  59. exit 0
  60. ;;
  61. p)
  62. PDIR=${OPTARG%/}
  63. if [ ! -d $PDIR ]; then
  64. echo "ERROR: pull-dir \"$PDIR\" does not exist."
  65. usage
  66. exit 1
  67. fi
  68. ;;
  69. t)
  70. if [ -n "$TO" ]; then
  71. TO="$TO,$OPTARG"
  72. else
  73. TO="$OPTARG"
  74. fi
  75. ;;
  76. esac
  77. done
  78. if [ -z "$PDIR" ]; then
  79. echo "ERROR: you must specify a pull-dir."
  80. usage
  81. exit 1
  82. fi
  83. # Verify the cover letter is complete and free of tokens
  84. CL="$PDIR/0000-cover-letter.patch"
  85. for TOKEN in SUBJECT BLURB; do
  86. grep -q "*** $TOKEN HERE ***" "$CL"
  87. if [ $? -eq 0 ]; then
  88. echo "ERROR: Please edit $CL and try again (Look for '*** $TOKEN HERE ***')."
  89. exit 1
  90. fi
  91. done
  92. # Harvest emails from the generated patches and populate the TO and CC variables
  93. # In addition to To and CC headers/lines, the common Signed-off-by, Tested-by,
  94. # etc. (*-by) will be added to CC.
  95. if [ $AUTO -eq 1 ]; then
  96. harvest_recipients TO "^[Tt][Oo]: *"
  97. harvest_recipients CC "^[Cc][Cc]: *"
  98. harvest_recipients CC "^.*-[Bb][Yy]: *"
  99. fi
  100. if [ -z "$TO" ] && [ -z "$CC" ]; then
  101. echo "ERROR: you have not specified any recipients."
  102. usage
  103. exit 1
  104. fi
  105. case "$PULL_MTA" in
  106. git)
  107. FROM="$(git config sendemail.from)"
  108. ;;
  109. sendmail)
  110. if [ -z "$FROM" ]; then
  111. FROM="$(git config user.name) <$(git config user.email)>"
  112. if [ -z "$FROM" ]; then
  113. echo "ERROR: unable to determine a FROM address"
  114. usage
  115. exit 1
  116. fi
  117. fi
  118. ;;
  119. esac
  120. # Generate report for the user and require confirmation before sending
  121. cat <<EOM
  122. The following patches:
  123. $(for PATCH in $PDIR/*.patch; do echo " $PATCH"; done)
  124. will be sent with the following headers:
  125. From: $FROM
  126. To: $TO
  127. CC: $CC
  128. EOM
  129. echo "Continue? [y/N] "
  130. read cont
  131. if [ "$cont" == "y" ] || [ "$cont" == "Y" ]; then
  132. ERROR=0
  133. case "$PULL_MTA" in
  134. git)
  135. export IFS=$','
  136. GIT_TO=$(for R in $TO; do echo -n "--to='$R' "; done)
  137. GIT_CC=$(for R in $CC; do echo -n "--cc='$R' "; done)
  138. unset IFS
  139. for PATCH in $PDIR/*patch; do
  140. # We harvest the emails manually, so force git not to.
  141. eval "git send-email $GIT_TO $GIT_CC --no-chain-reply-to --suppress-cc=all $PATCH"
  142. if [ $? -eq 1 ]; then
  143. ERROR=1
  144. fi
  145. done
  146. ;;
  147. sendmail)
  148. for PATCH in $PDIR/*patch; do
  149. # Insert To and CC headers via formail to keep them separate and
  150. # appending them to the sendmail command as -- $TO $CC has
  151. # proven to be an exercise in futility.
  152. #
  153. # Clear the From header, leaving it up to sendmail to insert an
  154. # appropriate one. Insert the original sender (per git) into the
  155. # body of the message.
  156. #
  157. # Use tail to remove the email envelope from git or formail as
  158. # msmtp (sendmail) would choke on them.
  159. #
  160. # Modify the patch date for sequential delivery, but retain the
  161. # original date as "Old-Date".
  162. DATE=$(date +"%a, %d %b %Y %k:%M:%S %z")
  163. GIT_FROM=$(cat $PATCH | formail -X "From:")
  164. cat $PATCH | formail -I "To: $TO" -I "CC: $CC" -I "From: $FROM" -i "Date: $DATE" | sed "0,/^$/s/^$/\n$GIT_FROM\n/" | tail -n +2 | sendmail -t
  165. if [ $? -eq 1 ]; then
  166. ERROR=1
  167. fi
  168. done
  169. ;;
  170. *)
  171. echo "ERROR: unknown MTA: $PULL_MTA"
  172. usage
  173. exit 1
  174. ;;
  175. esac
  176. if [ $ERROR -eq 1 ]; then
  177. echo "ERROR: Failed to send one or more messages. Check your MTA log for details."
  178. fi
  179. else
  180. echo "Send aborted."
  181. fi