xref: /aosp_15_r20/external/grpc-grpc/tools/release/backport_pr.sh (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1*cc02d7e2SAndroid Build Coastguard Worker#!/bin/bash
2*cc02d7e2SAndroid Build Coastguard Worker#Copyright 2021 The gRPC authors.
3*cc02d7e2SAndroid Build Coastguard Worker#
4*cc02d7e2SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
5*cc02d7e2SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
6*cc02d7e2SAndroid Build Coastguard Worker# You may obtain a copy of the License at
7*cc02d7e2SAndroid Build Coastguard Worker#
8*cc02d7e2SAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
9*cc02d7e2SAndroid Build Coastguard Worker#
10*cc02d7e2SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
11*cc02d7e2SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
12*cc02d7e2SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*cc02d7e2SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
14*cc02d7e2SAndroid Build Coastguard Worker# limitations under the License.
15*cc02d7e2SAndroid Build Coastguard Worker
16*cc02d7e2SAndroid Build Coastguard Workerset -euo pipefail
17*cc02d7e2SAndroid Build Coastguard Worker
18*cc02d7e2SAndroid Build Coastguard Workerensure_command () {
19*cc02d7e2SAndroid Build Coastguard Worker  if command -v "$1" 1>/dev/null 2>&1; then
20*cc02d7e2SAndroid Build Coastguard Worker    return 0
21*cc02d7e2SAndroid Build Coastguard Worker  else
22*cc02d7e2SAndroid Build Coastguard Worker    echo "$1 is not installed. Please install it to proceed." 1>&2
23*cc02d7e2SAndroid Build Coastguard Worker    exit 1
24*cc02d7e2SAndroid Build Coastguard Worker  fi
25*cc02d7e2SAndroid Build Coastguard Worker}
26*cc02d7e2SAndroid Build Coastguard Worker
27*cc02d7e2SAndroid Build Coastguard Workerdisplay_usage () {
28*cc02d7e2SAndroid Build Coastguard Worker  cat << EOF >/dev/stderr
29*cc02d7e2SAndroid Build Coastguard WorkerUSAGE: $0 PR_ID GITHUB_USER BACKPORT_BRANCHES REVIEWERS [-c PER_BACKPORT_COMMAND]
30*cc02d7e2SAndroid Build Coastguard Worker   PR_ID: The ID of the PR to be backported.
31*cc02d7e2SAndroid Build Coastguard Worker   GITHUB_USER: Your GitHub username.
32*cc02d7e2SAndroid Build Coastguard Worker   BACKPORT_BRANCHES: A space-separated list of branches to which the source PR will be backported.
33*cc02d7e2SAndroid Build Coastguard Worker   REVIEWERS: A comma-separated list of users to add as both reviewer and assignee.
34*cc02d7e2SAndroid Build Coastguard Worker   PER_BACKPORT_COMMAND : An optional command to run after cherrypicking the PR to the target branch.
35*cc02d7e2SAndroid Build Coastguard Worker     If you use this option, ensure your working directory is clean, as "git add -A" will be used to
36*cc02d7e2SAndroid Build Coastguard Worker     incorporate any generated files. Try running "git clean -xdff" beforehand.
37*cc02d7e2SAndroid Build Coastguard Worker
38*cc02d7e2SAndroid Build Coastguard WorkerExample: $0 25456 gnossen "v1.30.x v1.31.x v1.32.x v1.33.x v1.34.x v1.35.x v1.36.x" "menghanl,gnossen"
39*cc02d7e2SAndroid Build Coastguard WorkerExample: $0 25493 gnossen "\$(seq 30 33 | xargs -n1 printf 'v1.%s.x ')" "menghanl" -c ./tools/dockerfile/push_testing_images.sh
40*cc02d7e2SAndroid Build Coastguard WorkerEOF
41*cc02d7e2SAndroid Build Coastguard Worker  exit 1
42*cc02d7e2SAndroid Build Coastguard Worker}
43*cc02d7e2SAndroid Build Coastguard Worker
44*cc02d7e2SAndroid Build Coastguard Workerensure_command "curl"
45*cc02d7e2SAndroid Build Coastguard Workerensure_command "egrep"
46*cc02d7e2SAndroid Build Coastguard Workerensure_command "hub"
47*cc02d7e2SAndroid Build Coastguard Workerensure_command "jq"
48*cc02d7e2SAndroid Build Coastguard Worker
49*cc02d7e2SAndroid Build Coastguard Workerif [ "$#" -lt "4" ]; then
50*cc02d7e2SAndroid Build Coastguard Worker  display_usage
51*cc02d7e2SAndroid Build Coastguard Workerfi
52*cc02d7e2SAndroid Build Coastguard Worker
53*cc02d7e2SAndroid Build Coastguard WorkerPR_ID="$1"
54*cc02d7e2SAndroid Build Coastguard WorkerGITHUB_USER="$2"
55*cc02d7e2SAndroid Build Coastguard WorkerBACKPORT_BRANCHES="$3"
56*cc02d7e2SAndroid Build Coastguard WorkerREVIEWERS="$4"
57*cc02d7e2SAndroid Build Coastguard Workershift 4
58*cc02d7e2SAndroid Build Coastguard Worker
59*cc02d7e2SAndroid Build Coastguard WorkerPER_BACKPORT_COMMAND=""
60*cc02d7e2SAndroid Build Coastguard Workerwhile getopts "c:" OPT; do
61*cc02d7e2SAndroid Build Coastguard Worker  case "$OPT" in
62*cc02d7e2SAndroid Build Coastguard Worker    c )
63*cc02d7e2SAndroid Build Coastguard Worker      PER_BACKPORT_COMMAND="$OPTARG"
64*cc02d7e2SAndroid Build Coastguard Worker      ;;
65*cc02d7e2SAndroid Build Coastguard Worker    \? )
66*cc02d7e2SAndroid Build Coastguard Worker      echo "Invalid option: $OPTARG" >/dev/stderr
67*cc02d7e2SAndroid Build Coastguard Worker      display_usage
68*cc02d7e2SAndroid Build Coastguard Worker      ;;
69*cc02d7e2SAndroid Build Coastguard Worker    : )
70*cc02d7e2SAndroid Build Coastguard Worker      echo "Invalid option: $OPTARG requires an argument." >/dev/stderr
71*cc02d7e2SAndroid Build Coastguard Worker      display_usage
72*cc02d7e2SAndroid Build Coastguard Worker      ;;
73*cc02d7e2SAndroid Build Coastguard Worker  esac
74*cc02d7e2SAndroid Build Coastguard Workerdone
75*cc02d7e2SAndroid Build Coastguard Worker
76*cc02d7e2SAndroid Build Coastguard Workerif [[ ! -z "$(git status --porcelain)" && ! -z "$PER_BACKPORT_COMMAND" ]]; then
77*cc02d7e2SAndroid Build Coastguard Worker  echo "Your working directory is not clean. Try running `git clean -xdff`. Warning: This is irreversible." > /dev/stderr
78*cc02d7e2SAndroid Build Coastguard Worker  exit 1
79*cc02d7e2SAndroid Build Coastguard Workerfi
80*cc02d7e2SAndroid Build Coastguard Worker
81*cc02d7e2SAndroid Build Coastguard Workerif [ -z "$GITHUB_TOKEN" ]; then
82*cc02d7e2SAndroid Build Coastguard Worker  echo "A GitHub token is required to run this script. See " \
83*cc02d7e2SAndroid Build Coastguard Worker         "https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token" \
84*cc02d7e2SAndroid Build Coastguard Worker         " for more information" >/dev/stderr
85*cc02d7e2SAndroid Build Coastguard Worker  exit 1
86*cc02d7e2SAndroid Build Coastguard Workerfi
87*cc02d7e2SAndroid Build Coastguard Worker
88*cc02d7e2SAndroid Build Coastguard Workerecho "This script will create a collection of backport PRs. You will probably " \
89*cc02d7e2SAndroid Build Coastguard Worker       "have to touch your gnubby a frustrating number of times. C'est la vie."
90*cc02d7e2SAndroid Build Coastguard Workerprintf "Press any key to continue."
91*cc02d7e2SAndroid Build Coastguard Workerread -r RESPONSE </dev/tty
92*cc02d7e2SAndroid Build Coastguard Workerprintf "\n"
93*cc02d7e2SAndroid Build Coastguard Worker
94*cc02d7e2SAndroid Build Coastguard Worker
95*cc02d7e2SAndroid Build Coastguard WorkerPR_DATA=$(curl -s -u "$GITHUB_USER:$GITHUB_TOKEN" \
96*cc02d7e2SAndroid Build Coastguard Worker          -H "Accept: application/vnd.github.v3+json" \
97*cc02d7e2SAndroid Build Coastguard Worker          "https://api.github.com/repos/grpc/grpc/pulls/$PR_ID")
98*cc02d7e2SAndroid Build Coastguard Worker
99*cc02d7e2SAndroid Build Coastguard WorkerSTATE=$(echo "$PR_DATA" | jq -r '.state')
100*cc02d7e2SAndroid Build Coastguard Workerif [ "$STATE" != "open" ]; then
101*cc02d7e2SAndroid Build Coastguard Worker  TARGET_COMMITS=$(echo "$PR_DATA" | jq -r '.merge_commit_sha')
102*cc02d7e2SAndroid Build Coastguard Worker  FETCH_HEAD_REF=$(echo "$PR_DATA" | jq -r '.base.ref')
103*cc02d7e2SAndroid Build Coastguard Worker  SOURCE_REPO=$(echo "$PR_DATA" | jq -r '.base.repo.full_name')
104*cc02d7e2SAndroid Build Coastguard Workerelse
105*cc02d7e2SAndroid Build Coastguard Worker  COMMITS_URL=$(echo "$PR_DATA" | jq -r '.commits_url')
106*cc02d7e2SAndroid Build Coastguard Worker  COMMITS_DATA=$(curl -s -u "$GITHUB_USER:$GITHUB_TOKEN" \
107*cc02d7e2SAndroid Build Coastguard Worker                 -H "Accept: application/vnd.github.v3+json" \
108*cc02d7e2SAndroid Build Coastguard Worker                 "$COMMITS_URL")
109*cc02d7e2SAndroid Build Coastguard Worker  TARGET_COMMITS=$(echo "$COMMITS_DATA" | jq -r '. | map(.sha) | join(" ")')
110*cc02d7e2SAndroid Build Coastguard Worker  FETCH_HEAD_REF=$(echo "$PR_DATA" | jq -r '.head.sha')
111*cc02d7e2SAndroid Build Coastguard Worker  SOURCE_REPO=$(echo "$PR_DATA" | jq -r '.head.repo.full_name')
112*cc02d7e2SAndroid Build Coastguard Workerfi
113*cc02d7e2SAndroid Build Coastguard WorkerPR_TITLE=$(echo "$PR_DATA" | jq -r '.title')
114*cc02d7e2SAndroid Build Coastguard WorkerPR_DESCRIPTION=$(echo "$PR_DATA" | jq -r '.body')
115*cc02d7e2SAndroid Build Coastguard WorkerLABELS=$(echo "$PR_DATA" | jq -r '.labels | map(.name) | join(",")')
116*cc02d7e2SAndroid Build Coastguard Worker
117*cc02d7e2SAndroid Build Coastguard Workerset -x
118*cc02d7e2SAndroid Build Coastguard Worker
119*cc02d7e2SAndroid Build Coastguard Workergit fetch "[email protected]:$SOURCE_REPO.git" "$FETCH_HEAD_REF"
120*cc02d7e2SAndroid Build Coastguard Worker
121*cc02d7e2SAndroid Build Coastguard WorkerBACKPORT_PRS=""
122*cc02d7e2SAndroid Build Coastguard Workerfor BACKPORT_BRANCH in $BACKPORT_BRANCHES; do
123*cc02d7e2SAndroid Build Coastguard Worker  echo "Backporting $TARGET_COMMITS to $BACKPORT_BRANCH."
124*cc02d7e2SAndroid Build Coastguard Worker
125*cc02d7e2SAndroid Build Coastguard Worker  git checkout "origin/$BACKPORT_BRANCH"
126*cc02d7e2SAndroid Build Coastguard Worker
127*cc02d7e2SAndroid Build Coastguard Worker  BRANCH_NAME="backport_${PR_ID}_to_${BACKPORT_BRANCH}"
128*cc02d7e2SAndroid Build Coastguard Worker
129*cc02d7e2SAndroid Build Coastguard Worker  # To make the script idempotent.
130*cc02d7e2SAndroid Build Coastguard Worker  git branch -D "$BRANCH_NAME" || true
131*cc02d7e2SAndroid Build Coastguard Worker  git checkout "$BACKPORT_BRANCH"
132*cc02d7e2SAndroid Build Coastguard Worker  git checkout -b "$BRANCH_NAME"
133*cc02d7e2SAndroid Build Coastguard Worker
134*cc02d7e2SAndroid Build Coastguard Worker  for TARGET_COMMIT in $TARGET_COMMITS; do
135*cc02d7e2SAndroid Build Coastguard Worker    git cherry-pick -m 1 "$TARGET_COMMIT"
136*cc02d7e2SAndroid Build Coastguard Worker  done
137*cc02d7e2SAndroid Build Coastguard Worker
138*cc02d7e2SAndroid Build Coastguard Worker  if [[ ! -z "$PER_BACKPORT_COMMAND" ]]; then
139*cc02d7e2SAndroid Build Coastguard Worker    git submodule update --init --recursive
140*cc02d7e2SAndroid Build Coastguard Worker
141*cc02d7e2SAndroid Build Coastguard Worker    # To remove dangling submodules.
142*cc02d7e2SAndroid Build Coastguard Worker    git clean -xdff
143*cc02d7e2SAndroid Build Coastguard Worker    eval "$PER_BACKPORT_COMMAND"
144*cc02d7e2SAndroid Build Coastguard Worker    git add -A
145*cc02d7e2SAndroid Build Coastguard Worker    git commit --amend --no-edit
146*cc02d7e2SAndroid Build Coastguard Worker  fi
147*cc02d7e2SAndroid Build Coastguard Worker
148*cc02d7e2SAndroid Build Coastguard Worker  BACKPORT_PR=$(hub pull-request -p -m "[Backport] $PR_TITLE" \
149*cc02d7e2SAndroid Build Coastguard Worker                  -m "*Beep boop. This is an automatically generated backport of #${PR_ID}.*" \
150*cc02d7e2SAndroid Build Coastguard Worker                  -m "$PR_DESCRIPTION" \
151*cc02d7e2SAndroid Build Coastguard Worker                  -l "$LABELS" \
152*cc02d7e2SAndroid Build Coastguard Worker                  -b "$GITHUB_USER:$BACKPORT_BRANCH" \
153*cc02d7e2SAndroid Build Coastguard Worker                  -r "$REVIEWERS" \
154*cc02d7e2SAndroid Build Coastguard Worker                  -a "$REVIEWERS" | tail -n 1)
155*cc02d7e2SAndroid Build Coastguard Worker  BACKPORT_PRS+="$BACKPORT_PR\n"
156*cc02d7e2SAndroid Build Coastguard Worker
157*cc02d7e2SAndroid Build Coastguard Worker  # TODO: Turn on automerge once the Github API allows it.
158*cc02d7e2SAndroid Build Coastguard Workerdone
159*cc02d7e2SAndroid Build Coastguard Worker
160*cc02d7e2SAndroid Build Coastguard Workerprintf "Your backport PRs have been created:\n$BACKPORT_PRS"
161