]> git.lizzy.rs Git - rust.git/blob - src/ci/scripts/verify-backported-commits.sh
Auto merge of #83342 - Count-Count:win-console-incomplete-utf8, r=m-ou-se
[rust.git] / src / ci / scripts / verify-backported-commits.sh
1 #!/bin/bash
2 # Ensure commits in beta are in master & commits in stable are in beta + master.
3 set -euo pipefail
4 IFS=$'\n\t'
5
6 source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
7
8 # We don't care about commits that predate this automation check, so we pass a
9 # `<limit>` argument to `git cherry`.
10 BETA_LIMIT="53fd98ca776cb875bc9e5514f56b52eb74f9e7a9"
11 STABLE_LIMIT="a178d0322ce20e33eac124758e837cbd80a6f633"
12
13 verify_backported_commits_main() {
14   ci_base_branch=$(ciBaseBranch)
15
16   if [[ "$ci_base_branch" != "beta" && "$ci_base_branch" != "stable" ]]; then
17     echo 'Skipping. This is only run when merging to the beta or stable branches.'
18     exit 0
19   fi
20
21   echo 'git: unshallowing the repository so we can check commits'
22   git fetch \
23     --no-tags \
24     --no-recurse-submodules \
25     --progress \
26     --prune \
27     --unshallow
28
29   if [[ $ci_base_branch == "beta" ]]; then
30     verify_cherries master "$BETA_LIMIT" \
31       || exit 1
32
33   elif [[ $ci_base_branch == "stable" ]]; then
34     (verify_cherries master "$STABLE_LIMIT" \
35       & verify_cherries beta "$STABLE_LIMIT") \
36       || exit 1
37
38   fi
39 }
40
41 # Verify all commits in `HEAD` are backports of a commit in <upstream>. See
42 # https://git-scm.com/docs/git-cherry for an explanation of the arguments.
43 #
44 # $1 = <upstream>
45 # $2 = <limit>
46 verify_cherries() {
47   # commits that lack a `backport-of` comment.
48   local no_backports=()
49   # commits with an incorrect `backport-of` comment.
50   local bad_backports=()
51
52   commits=$(git cherry "origin/$1" HEAD "$2")
53
54   if [[ -z "$commits" ]]; then
55     echo "All commits in \`HEAD\` are present in \`$1\`"
56     return 0
57   fi
58
59   commits=$(echo "$commits" | grep '^\+' | cut -c 3-)
60
61   while read sha; do
62     # Check each commit in <current>..<upstream>
63     backport_sha=$(get_backport "$sha")
64
65     if [[ "$backport_sha" == "nothing" ]]; then
66       echo "✓ \`$sha\` backports nothing"
67       continue
68     fi
69
70     if [[ -z "$backport_sha" ]]; then
71       no_backports+=("$sha")
72       continue
73     fi
74
75     if ! is_in_master "$backport_sha"; then
76       bad_backports+=("$sha")
77       continue
78     fi
79
80     echo "✓ \`$sha\` backports \`$backport_sha\`"
81   done <<< "$commits"
82
83   failure=0
84
85   if [ ${#no_backports[@]} -ne 0 ]; then
86         echo 'Error: Could not find backports for all commits.'
87         echo
88         echo 'All commits in \`HEAD\` are required to have a corresponding upstream commit.'
89         echo 'It looks like the following commits:'
90         echo
91         for commit in "${no_backports[@]}"; do
92           echo "    $commit"
93         done
94         echo
95         echo "do not match any commits in \`$1\`. If this was intended, add the text"
96         echo '\`backport-of: <SHA of a commit already in master>\`'
97         echo 'somewhere in the message of each of these commits.'
98         echo
99         failure=1
100   fi
101
102   if [ ${#bad_backports[@]} -ne 0 ]; then
103         echo 'Error: Found incorrectly marked commits.'
104         echo
105         echo 'The following commits:'
106         echo
107         for commit in "${bad_backports[@]}"; do
108           echo "    $commit"
109         done
110         echo
111         echo 'have commit messages marked \`backport-of: <SHA>\`, but the SHA is not in'
112         echo '\`master\`.'
113         echo
114         failure=1
115   fi
116
117   return $failure
118 }
119
120 # Get the backport of a commit. It echoes one of:
121 #
122 # 1. A SHA of the backported commit
123 # 2. The string "nothing"
124 # 3. An empty string
125 #
126 # $1 = <sha>
127 get_backport() {
128   # This regex is:
129   #
130   # ^.* - throw away any extra starting characters
131   # backport-of: - prefix
132   # \s\? - optional space
133   # \(\) - capture group
134   # [a-f0-9]\+\|nothing - a SHA or the text 'nothing'
135   # .* - throw away any extra ending characters
136   # \1 - replace it with the first match
137   # {s//\1/p;q} - print the first occurrence and quit
138   #
139   git show -s --format=%B "$1" \
140     | sed -n '/^.*backport-of:\s\?\([a-f0-9]\+\|nothing\).*/{s//\1/p;q}'
141 }
142
143 # Check if a commit is in master.
144 #
145 # $1 = <sha>
146 is_in_master() {
147   git merge-base --is-ancestor "$1" origin/master 2> /dev/null
148 }
149
150 verify_backported_commits_main