summaryrefslogtreecommitdiff
path: root/scripts/send-pull-request
blob: 3af2a9fa7e5faa1aa0d2b7e3c028aed60e1c89ff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#!/bin/bash
AUTO=0

# Check env for any default settings, command line options will override these.
if [ -z "$PULL_MTA" ]; then
    PULL_MTA="sendmail"
fi

# Prevent environment leakage to these vars.
unset TO
unset CC
# allow the user to set FROM in the environment

usage()
{
cat <<EOM
Usage: $(basename $0) [-h] [-a] [[-t email]...] -p pull-dir 
  -t email     Explicitly add email to the recipients
  -a           Automatically harvest recipients from "*-by: email" lines
               in the patches in the pull-dir
  -f           Specify a FROM address, you can also use the FROM environment
               variable. If you do not specify one, it will try to use the one
               from your git config. This is ignored if -g is used.
  -g           Use git-send-email to send mail instead of sendmail
  -p pull-dir  Directory containing summary and patch files
EOM
}

# Collect To and CC addresses from the patch files if they exist
# $1: Which header to add the recipients to, "TO" or "CC"
# $2: The regex to match and strip from the line with email addresses
harvest_recipients()
{
    TO_CC=$1
    REGX=$2
    export IFS=$',\n'
    for PATCH in $PDIR/*.patch; do
        # Grab To addresses
        for EMAIL in $(sed '/^---$/q' $PATCH | grep -e "$REGX" | sed "s/$REGX//"); do
            if [ "$TO_CC" == "TO" ] && [ "${TO/$EMAIL/}" == "$TO" ] && [ -n "$EMAIL" ]; then
                if [ -z "$TO" ]; then TO=$EMAIL; else TO="$TO,$EMAIL"; fi
            elif [ "$TO_CC" == "CC" ] && [ "${CC/$EMAIL/}" == "$CC" ] && [ -n "$EMAIL" ]; then
                if [ -z "$CC" ]; then CC=$EMAIL; else CC="$CC,$EMAIL"; fi
            fi
        done
    done
    unset IFS
}


# Parse and verify arguments
while getopts "af:ghp:t:" OPT; do
    case $OPT in
        a)
            AUTO=1
            ;;
        f)
            FROM="$OPTARG"
            ;;
        g)
            PULL_MTA="git"
            ;;
        h)
            usage
            exit 0
            ;;
        p)
            PDIR=${OPTARG%/}
            if [ ! -d $PDIR ]; then
                echo "ERROR: pull-dir \"$PDIR\" does not exist."
                usage
                exit 1
            fi
            ;;
        t)
            if [ -n "$TO" ]; then
                TO="$TO,$OPTARG"
            else
                TO="$OPTARG"
            fi
            ;;
    esac
done

if [ -z "$PDIR" ]; then
    echo "ERROR: you must specify a pull-dir."
    usage
    exit 1
fi


# Verify the cover letter is complete and free of tokens
CL="$PDIR/0000-cover-letter.patch"
for TOKEN in SUBJECT BLURB; do
    grep -q "*** $TOKEN HERE ***" "$CL"
    if [ $? -eq 0 ]; then
        echo "ERROR: Please edit $CL and try again (Look for '*** $TOKEN HERE ***')."
        exit 1
    fi
done


# Harvest emails from the generated patches and populate the TO and CC variables
# In addition to To and CC headers/lines, the common Signed-off-by, Tested-by,
# etc. (*-by) will be added to CC.
if [ $AUTO -eq 1 ]; then
    harvest_recipients TO "^[Tt][Oo]: *"
    harvest_recipients CC "^[Cc][Cc]: *"
    harvest_recipients CC "^.*-[Bb][Yy]: *"
fi

case "$PULL_MTA" in
    git)
        FROM="$(git config sendemail.from)"
	AUTO_TO="$(git config sendemail.to)"
	if [ -n "$AUTO_TO" ]; then
	    if [ -n "$TO" ]; then
		TO="$TO,$AUTO_TO"
	    else
		TO="$AUTO_TO"
	    fi
	fi
        ;;
    sendmail)
        if [ -z "$FROM" ]; then
            FROM="$(git config user.name) <$(git config user.email)>"
            if [ -z "$FROM" ]; then
                echo "ERROR: unable to determine a FROM address"
                usage
                exit 1
            fi
        fi
        ;;
esac

if [ -z "$TO" ] && [ -z "$CC" ]; then
    echo "ERROR: you have not specified any recipients."
    usage
    exit 1
fi


# Generate report for the user and require confirmation before sending
cat <<EOM
The following patches:
$(for PATCH in $PDIR/*.patch; do echo "    $PATCH"; done)

will be sent with the following headers:
  From: $FROM
    To: $TO
    CC: $CC

EOM
echo "Continue? [y/N] "
read cont

if [ "$cont" == "y" ] || [ "$cont" == "Y" ]; then
    ERROR=0
    case "$PULL_MTA" in
        git)
            export IFS=$','
            GIT_TO=$(for R in $TO; do echo -n "--to='$R' "; done)
            GIT_CC=$(for R in $CC; do echo -n "--cc='$R' "; done)
            unset IFS
            for PATCH in $PDIR/*patch; do
                # We harvest the emails manually, so force git not to.
                eval "git send-email $GIT_TO $GIT_CC --no-chain-reply-to --suppress-cc=all $PATCH"
                if [ $? -eq 1 ]; then
                    ERROR=1
                fi
            done
            ;;
        sendmail)
            for PATCH in $PDIR/*patch; do
                # Insert To and CC headers via formail to keep them separate and
                # appending them to the sendmail command as -- $TO $CC has
                # proven to be an exercise in futility.
                #
                # Clear the From header, leaving it up to sendmail to insert an
                # appropriate one. Insert the original sender (per git) into the
                # body of the message.
                #
                # Use tail to remove the email envelope from git or formail as
                # msmtp (sendmail) would choke on them.
                #
                # Modify the patch date for sequential delivery, but retain the
                # original date as "Old-Date".
                DATE=$(date +"%a, %d %b %Y %k:%M:%S %z")
                GIT_FROM=$(cat $PATCH | formail -X "From:")
                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
                if [ $? -eq 1 ]; then
                    ERROR=1
                fi
            done
            ;;
        *)
            echo "ERROR: unknown MTA: $PULL_MTA"
            usage
            exit 1
            ;;
    esac

    if [ $ERROR -eq 1 ]; then
        echo "ERROR: Failed to send one or more messages. Check your MTA log for details."
    fi
else
    echo "Send aborted."
fi