1848b8605Smrg#!/bin/sh
2848b8605Smrg
3848b8605Smrg# Script for generating a list of candidates for cherry-picking to a stable branch
4848b8605Smrg#
5848b8605Smrg# Usage examples:
6848b8605Smrg#
7848b8605Smrg# $ bin/get-pick-list.sh
8848b8605Smrg# $ bin/get-pick-list.sh > picklist
9848b8605Smrg# $ bin/get-pick-list.sh | tee picklist
10b8e80941Smrg#
11b8e80941Smrg# The output is as follows:
12b8e80941Smrg# [nomination_type] commit_sha commit summary
13b8e80941Smrg
14b8e80941Smrgis_stable_nomination()
15b8e80941Smrg{
16b8e80941Smrg	git show --pretty=medium --summary "$1" | grep -q -i -o "CC:.*mesa-stable"
17b8e80941Smrg}
18b8e80941Smrg
19b8e80941Smrgis_typod_nomination()
20b8e80941Smrg{
21b8e80941Smrg	git show --pretty=medium --summary "$1" | grep -q -i -o "CC:.*mesa-dev"
22b8e80941Smrg}
23b8e80941Smrg
24b8e80941Smrgfixes=
25b8e80941Smrg
26b8e80941Smrg# Helper to handle various mistypos of the fixes tag.
27b8e80941Smrg# The tag string itself is passed as argument and normalised within.
28b8e80941Smrg#
29b8e80941Smrg# Resulting string in the global variable "fixes" and contains entries
30b8e80941Smrg# in the form "fixes:$sha"
31b8e80941Smrgis_sha_nomination()
32b8e80941Smrg{
33b8e80941Smrg	fixes=`git show --pretty=medium -s $1 | tr -d "\n" | \
34b8e80941Smrg		sed -e 's/'"$2"'/\nfixes:/Ig' | \
35b8e80941Smrg		grep -Eo 'fixes:[a-f0-9]{8,40}'`
36b8e80941Smrg
37b8e80941Smrg	fixes_count=`echo "$fixes" | grep "fixes:" | wc -l`
38b8e80941Smrg	if test $fixes_count -eq 0; then
39b8e80941Smrg		return 1
40b8e80941Smrg	fi
41b8e80941Smrg
42b8e80941Smrg	# Throw a warning for each invalid sha
43b8e80941Smrg	while test $fixes_count -gt 0; do
44b8e80941Smrg		# Treat only the current line
45b8e80941Smrg		id=`echo "$fixes" | tail -n $fixes_count | head -n 1 | cut -d : -f 2`
46b8e80941Smrg		fixes_count=$(($fixes_count-1))
47b8e80941Smrg		if ! git show $id >/dev/null 2>&1; then
48b8e80941Smrg			echo WARNING: Commit $1 lists invalid sha $id
49b8e80941Smrg		fi
50b8e80941Smrg	done
51b8e80941Smrg
52b8e80941Smrg	return 0
53b8e80941Smrg}
54b8e80941Smrg
55b8e80941Smrg# Checks if at least one of offending commits, listed in the global
56b8e80941Smrg# "fixes", is in branch.
57b8e80941Smrgsha_in_range()
58b8e80941Smrg{
59b8e80941Smrg	fixes_count=`echo "$fixes" | grep "fixes:" | wc -l`
60b8e80941Smrg	while test $fixes_count -gt 0; do
61b8e80941Smrg		# Treat only the current line
62b8e80941Smrg		id=`echo "$fixes" | tail -n $fixes_count | head -n 1 | cut -d : -f 2`
63b8e80941Smrg		fixes_count=$(($fixes_count-1))
64b8e80941Smrg
65b8e80941Smrg		# Be that cherry-picked ...
66b8e80941Smrg		# ... or landed before the branchpoint.
67b8e80941Smrg		if grep -q ^$id already_picked ||
68b8e80941Smrg		   grep -q ^$id already_landed ; then
69b8e80941Smrg			return 0
70b8e80941Smrg		fi
71b8e80941Smrg	done
72b8e80941Smrg	return 1
73b8e80941Smrg}
74b8e80941Smrg
75b8e80941Smrgis_fixes_nomination()
76b8e80941Smrg{
77b8e80941Smrg	is_sha_nomination "$1" "fixes:[[:space:]]*"
78b8e80941Smrg	if test $? -eq 0; then
79b8e80941Smrg		return 0
80b8e80941Smrg	fi
81b8e80941Smrg	is_sha_nomination "$1" "fixes[[:space:]]\+"
82b8e80941Smrg}
83b8e80941Smrg
84b8e80941Smrgis_brokenby_nomination()
85b8e80941Smrg{
86b8e80941Smrg	is_sha_nomination "$1" "broken by"
87b8e80941Smrg}
88b8e80941Smrg
89b8e80941Smrgis_revert_nomination()
90b8e80941Smrg{
91b8e80941Smrg	is_sha_nomination "$1" "This reverts commit "
92b8e80941Smrg}
93b8e80941Smrg
94b8e80941Smrg# Use the last branchpoint as our limit for the search
95b8e80941Smrglatest_branchpoint=`git merge-base origin/master HEAD`
96b8e80941Smrg
97b8e80941Smrg# List all the commits between day 1 and the branch point...
98b8e80941Smrggit log --reverse --pretty=%H $latest_branchpoint > already_landed
99848b8605Smrg
100b8e80941Smrg# ... and the ones cherry-picked.
101b8e80941Smrggit log --reverse --pretty=medium --grep="cherry picked from commit" $latest_branchpoint..HEAD |\
102848b8605Smrg	grep "cherry picked from commit" |\
103848b8605Smrg	sed -e 's/^[[:space:]]*(cherry picked from commit[[:space:]]*//' -e 's/)//' > already_picked
104848b8605Smrg
105b8e80941Smrg# Grep for potential candidates
106b8e80941Smrggit log --reverse --pretty=%H -i --grep='^CC:.*mesa-stable\|^CC:.*mesa-dev\|\<fixes\>\|\<broken by\>\|This reverts commit' $latest_branchpoint..origin/master |\
107848b8605Smrgwhile read sha
108848b8605Smrgdo
109848b8605Smrg	# Check to see whether the patch is on the ignore list.
110b8e80941Smrg	if test -f bin/.cherry-ignore; then
111848b8605Smrg		if grep -q ^$sha bin/.cherry-ignore ; then
112848b8605Smrg			continue
113848b8605Smrg		fi
114848b8605Smrg	fi
115848b8605Smrg
116848b8605Smrg	# Check to see if it has already been picked over.
117848b8605Smrg	if grep -q ^$sha already_picked ; then
118848b8605Smrg		continue
119848b8605Smrg	fi
120848b8605Smrg
121b8e80941Smrg	if is_fixes_nomination "$sha"; then
122b8e80941Smrg		tag=fixes
123b8e80941Smrg	elif is_brokenby_nomination "$sha"; then
124b8e80941Smrg		tag=brokenby
125b8e80941Smrg	elif is_revert_nomination "$sha"; then
126b8e80941Smrg		tag=revert
127b8e80941Smrg	elif is_stable_nomination "$sha"; then
128b8e80941Smrg		tag=stable
129b8e80941Smrg	elif is_typod_nomination "$sha"; then
130b8e80941Smrg		tag=typod
131b8e80941Smrg	else
132b8e80941Smrg		continue
133b8e80941Smrg	fi
134b8e80941Smrg
135b8e80941Smrg	case "$tag" in
136b8e80941Smrg	fixes | brokenby | revert )
137b8e80941Smrg		if ! sha_in_range; then
138b8e80941Smrg			continue
139b8e80941Smrg		fi
140b8e80941Smrg		;;
141b8e80941Smrg	* )
142b8e80941Smrg		;;
143b8e80941Smrg	esac
144b8e80941Smrg
145b8e80941Smrg	printf "[ %8s ] " "$tag"
146b8e80941Smrg	git --no-pager show --no-patch --oneline $sha
147848b8605Smrgdone
148848b8605Smrg
149848b8605Smrgrm -f already_picked
150b8e80941Smrgrm -f already_landed
151