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