1#!/bin/sh
2#
3# Copyright (c) 2010-2013,  Intel Corporation.
4#
5# SPDX-License-Identifier: GPL-2.0-or-later
6#
7
8#
9# This script is intended to be used to prepare a series of patches
10# and a cover letter in an appropriate and consistent format for
11# submission to Open Embedded and The Yocto Project, as well as to
12# related projects and layers.
13#
14
15ODIR=pull-$$
16RELATIVE_TO="master"
17COMMIT_ID="HEAD"
18PREFIX="PATCH"
19RFC=0
20
21usage() {
22CMD=$(basename $0)
23cat <<EOM
24Usage: $CMD [-h] [-o output_dir] [-m msg_body_file] [-s subject] [-r relative_to] [-i commit_id] [-d relative_dir] -u remote [-b branch] [-- <format-patch options>]
25  -b branch           Branch name in the specified remote (default: current branch)
26  -l local branch     Local branch name (default: HEAD)
27  -c                  Create an RFC (Request for Comment) patch series
28  -h                  Display this help message
29  -a                  Automatically push local branch (-l) to remote branch (-b),
30                      or set CPR_CONTRIB_AUTO_PUSH in env
31  -i commit_id        Ending commit (default: HEAD)
32  -m msg_body_file    The file containing a blurb to be inserted into the summary email
33  -o output_dir       Specify the output directory for the messages (default: pull-PID)
34  -p prefix           Use [prefix N/M] instead of [PATCH N/M] as the subject prefix
35  -r relative_to      Starting commit (default: master)
36  -s subject          The subject to be inserted into the summary email
37  -u remote           The git remote where the branch is located, or set CPR_CONTRIB_REMOTE in env
38  -d relative_dir     Generate patches relative to directory
39
40 Examples:
41   $CMD -u contrib -b nitin/basic
42   $CMD -u contrib -r distro/master -i nitin/distro -b nitin/distro
43   $CMD -u contrib -r distro/master -i nitin/distro -b nitin/distro -l distro
44   $CMD -u contrib -r master -i misc -b nitin/misc -o pull-misc
45   $CMD -u contrib -p "RFC PATCH" -b nitin/experimental
46   $CMD -u contrib -i misc -b nitin/misc -d ./bitbake
47   $CMD -u contrib -r origin/master -o /tmp/out.v3 -- -v3 --in-reply-to=20170511120134.XX7799@site.com
48EOM
49}
50
51REMOTE="$CPR_CONTRIB_REMOTE"
52# Parse and validate arguments
53while getopts "b:acd:hi:m:o:p:r:s:u:l:" OPT; do
54	case $OPT in
55	b)
56		BRANCH="$OPTARG"
57		;;
58	l)
59		L_BRANCH="$OPTARG"
60		;;
61	c)
62		RFC=1
63		;;
64	d)
65		RELDIR="$OPTARG"
66		;;
67	h)
68		usage
69		exit 0
70		;;
71	i)
72		COMMIT_ID="$OPTARG"
73		;;
74	m)
75		BODY="$OPTARG"
76		if [ ! -e "$BODY" ]; then
77			echo "ERROR: Body file does not exist"
78			exit 1
79		fi
80		;;
81	o)
82		ODIR="$OPTARG"
83		;;
84	p)
85		PREFIX="$OPTARG"
86		;;
87	r)
88		RELATIVE_TO="$OPTARG"
89		;;
90	s)
91		SUBJECT="$OPTARG"
92		;;
93	u)
94		REMOTE="$OPTARG"
95		;;
96	a)
97		CPR_CONTRIB_AUTO_PUSH="1"
98		;;
99	--)
100		shift
101		break
102		;;
103	esac
104done
105
106shift "$((OPTIND - 1))"
107extraopts="$@"
108
109if [ -z "$REMOTE" ]; then
110	echo "ERROR: Missing parameter -u or CPR_CONTRIB_REMOTE in env, no git remote!"
111	usage
112	exit 1
113fi
114
115REMOTE_URL=$(git config remote.$REMOTE.url)
116if [ $? -ne 0 ]; then
117	echo "ERROR: git config failed to find a url for '$REMOTE'"
118	echo
119	echo "To add a remote url for $REMOTE, use:"
120	echo "  git config remote.$REMOTE.url <url>"
121	exit 1
122fi
123
124# Rewrite private URLs to public URLs
125# Determine the repository name for use in the WEB_URL later
126USER_RE="[A-Za-z0-9_.@][A-Za-z0-9_.@-]*\$\?"
127PROTO_RE="[a-z][a-z+]*://"
128GIT_RE="\(^\($PROTO_RE\)\?\)\($USER_RE@\)\?\([^:/]*\)[:/]\(.*\)"
129REMOTE_URL=${REMOTE_URL%.git}
130REMOTE_REPO=$(echo $REMOTE_URL | sed "s#$GIT_RE#\5#")
131REMOTE_URL=$(echo $REMOTE_URL | sed "s#$GIT_RE#git://\4/\5#")
132
133if [ -z "$BRANCH" ]; then
134	BRANCH=$(git branch | grep -e "^\* " | cut -d' ' -f2)
135	echo "NOTE: Assuming remote branch '$BRANCH', use -b to override."
136fi
137
138if [ -z "$L_BRANCH" ]; then
139	L_BRANCH=HEAD
140	echo "NOTE: Assuming local branch HEAD, use -l to override."
141fi
142
143if [ $RFC -eq 1 ]; then
144	PREFIX="RFC $PREFIX"
145fi
146
147
148# Set WEB_URL from known remotes
149WEB_URL=""
150case "$REMOTE_URL" in
151	*git.yoctoproject.org*)
152		WEB_URL="http://git.yoctoproject.org/cgit.cgi/$REMOTE_REPO/log/?h=$BRANCH"
153		;;
154	*git.pokylinux.org*)
155		WEB_URL="http://git.pokylinux.org/cgit.cgi/$REMOTE_REPO/log/?h=$BRANCH"
156		;;
157	*git.openembedded.org*)
158		WEB_URL="http://cgit.openembedded.org/$REMOTE_REPO/log/?h=$BRANCH"
159		;;
160	*github.com*)
161		WEB_URL="https://github.com/$REMOTE_REPO/tree/$BRANCH"
162		;;
163esac
164
165# Perform a sanity test on the web URL. Issue a warning if it is not
166# accessible, but do not abort as users may want to run offline.
167if [ -n "$WEB_URL" ]; then
168	if [ "$CPR_CONTRIB_AUTO_PUSH" = "1" ]; then
169		echo "Pushing '$BRANCH' on '$REMOTE' as requested..."
170		git push $REMOTE $L_BRANCH:$BRANCH
171		echo ""
172	fi
173	wget --no-check-certificate -q $WEB_URL -O /dev/null
174	if [ $? -ne 0 ]; then
175		echo "WARNING: Branch '$BRANCH' was not found on the contrib git tree."
176		echo "         Please check your remote and branch parameter before sending."
177		echo ""
178	fi
179fi
180
181if [ -e $ODIR ]; then
182	echo "ERROR: output directory $ODIR exists."
183	exit 1
184fi
185mkdir $ODIR
186
187if [ -n "$RELDIR" ]; then
188	ODIR=$(realpath $ODIR)
189	pdir=$(pwd)
190	cd $RELDIR
191	extraopts="$extraopts --relative"
192fi
193
194# Generate the patches and cover letter
195git format-patch $extraopts -M40 --subject-prefix="$PREFIX" -n -o $ODIR --thread=shallow --cover-letter $RELATIVE_TO..$COMMIT_ID > /dev/null
196
197if [ -z "$(ls -A $ODIR 2> /dev/null)" ]; then
198    echo "ERROR: $ODIR is empty, no cover letter and patches was generated!"
199    echo "       This is most likely due to that \$RRELATIVE_TO..\$COMMIT_ID"
200    echo "       ($RELATIVE_TO..$COMMIT_ID) don't contain any differences."
201    rmdir $ODIR
202    exit 1
203fi
204
205[ -n "$RELDIR" ] && cd $pdir
206
207# Customize the cover letter
208CL="$(echo $ODIR/*0000-cover-letter.patch)"
209PM="$ODIR/pull-msg"
210GIT_VERSION=$(`git --version` | tr -d '[:alpha:][:space:].' | sed 's/\(...\).*/\1/')
211NEWER_GIT_VERSION=210
212if [ $GIT_VERSION -lt $NEWER_GIT_VERSION ]; then
213	git request-pull $RELATIVE_TO $REMOTE_URL $COMMIT_ID >> "$PM"
214else
215	git request-pull $RELATIVE_TO $REMOTE_URL $L_BRANCH:$BRANCH >> "$PM"
216fi
217if [ $? -ne 0 ]; then
218	echo "ERROR: git request-pull reported an error"
219	rm -rf $ODIR
220	exit 1
221fi
222
223# The cover letter already has a diffstat, remove it from the pull-msg
224# before inserting it.
225sed -n "0,\#$REMOTE_URL# p" "$PM" | sed -i "/BLURB HERE/ r /dev/stdin" "$CL"
226rm "$PM"
227
228# If this is an RFC, make that clear in the cover letter
229if [ $RFC -eq 1 ]; then
230(cat <<EOM
231Please review the following changes for suitability for inclusion. If you have
232any objections or suggestions for improvement, please respond to the patches. If
233you agree with the changes, please provide your Acked-by.
234
235EOM
236) | sed -i "/BLURB HERE/ r /dev/stdin" "$CL"
237fi
238
239# Insert the WEB_URL if there is one
240if [ -n "$WEB_URL" ]; then
241	echo "  $WEB_URL" | sed -i "\#$REMOTE_URL# r /dev/stdin" "$CL"
242fi
243
244
245# If the user specified a message body, insert it into the cover letter and
246# remove the BLURB token.
247if [ -n "$BODY" ]; then
248	sed -i "/BLURB HERE/ r $BODY" "$CL"
249	sed -i "/BLURB HERE/ d" "$CL"
250fi
251
252# Set subject automatically if there is only one patch
253patch_cnt=`git log --pretty=oneline ${RELATIVE_TO}..${L_BRANCH} | wc -l`
254if [ -z "$SUBJECT" -a $patch_cnt -eq 1 ]; then
255    SUBJECT="`git log --format=%s ${RELATIVE_TO}..${L_BRANCH}`"
256fi
257
258# Replace the SUBJECT token with it.
259if [ -n "$SUBJECT" ]; then
260	sed -i -e "s\`\*\*\* SUBJECT HERE \*\*\*\`$SUBJECT\`" "$CL"
261fi
262
263
264# Generate report for user
265cat <<EOM
266The following patches have been prepared:
267$(for PATCH in $(ls $ODIR/*); do echo "    $PATCH"; done)
268
269Review their content, especially the summary mail:
270    $CL
271
272When you are satisfied, you can send them with:
273    send-pull-request -a -p $ODIR
274EOM
275
276# Check the patches for trailing white space
277egrep -q -e "^\+.*\s+$" $ODIR/*
278if [ $? -ne 1 ]; then
279	echo
280	echo "WARNING: Trailing white space detected at these locations"
281	egrep -nH --color -e "^\+.*\s+$" $ODIR/*
282fi
283