1+ #! /bin/bash
2+ # Copyright 2026 Google LLC
3+ #
4+ # Licensed under the Apache License, Version 2.0 (the "License");
5+ # you may not use this file except in compliance with the License.
6+ # You may obtain a copy of the License at
7+ #
8+ # http://www.apache.org/licenses/LICENSE-2.0
9+ #
10+ # Unless required by applicable law or agreed to in writing, software
11+ # distributed under the License is distributed on an "AS IS" BASIS,
12+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ # See the License for the specific language governing permissions and
14+ # limitations under the License.
15+
16+ # migrate_issues.sh - Transfer open GitHub issues from one repo to another using gh CLI.
17+
18+ set -e
19+
20+ usage () {
21+ echo " Usage: $0 <source-repo> <target-repo> [--label <label>] [--dry-run]"
22+ echo " Example: $0 googleapis/python-storage googleapis/google-cloud-python --label 'api: storage'"
23+ exit 1
24+ }
25+
26+ if [[ $# -lt 2 ]]; then
27+ usage
28+ fi
29+
30+ SOURCE_REPO=$1
31+ TARGET_REPO=$2
32+ shift 2
33+
34+ DRY_RUN=false
35+ REQUIRED_LABEL=" "
36+
37+ while [[ " $# " -gt 0 ]]; do
38+ case $1 in
39+ --dry-run) DRY_RUN=true; shift ;;
40+ --label) REQUIRED_LABEL=" $2 " ; shift 2 ;;
41+ * ) echo " Unknown parameter passed: $1 " ; usage ;;
42+ esac
43+ done
44+
45+ # Check if gh is installed
46+ if ! command -v gh & > /dev/null; then
47+ echo " Error: gh (GitHub CLI) is not installed."
48+ exit 1
49+ fi
50+
51+ # Check if authenticated
52+ if ! gh auth status & > /dev/null; then
53+ echo " Error: gh is not authenticated. Run 'gh auth login' first."
54+ exit 1
55+ fi
56+
57+ echo " Transferring open issues from $SOURCE_REPO to $TARGET_REPO ..."
58+ if [ " $DRY_RUN " = true ]; then
59+ echo " --- DRY RUN MODE ---"
60+ fi
61+
62+ # Ensure label exists in target repo
63+ if [[ -n " $REQUIRED_LABEL " ]]; then
64+ echo " Ensuring label '$REQUIRED_LABEL ' exists in $TARGET_REPO ..."
65+ if ! gh label list --repo " $TARGET_REPO " --json name --jq ' .[].name' | grep -fxq " $REQUIRED_LABEL " ; then
66+ if [ " $DRY_RUN " = true ]; then
67+ echo " [DRY RUN] Would create label '$REQUIRED_LABEL ' in $TARGET_REPO "
68+ else
69+ echo " Creating label '$REQUIRED_LABEL ' in $TARGET_REPO ..."
70+ gh label create " $REQUIRED_LABEL " --repo " $TARGET_REPO " --color " ededed"
71+ fi
72+ else
73+ echo " Label '$REQUIRED_LABEL ' already exists."
74+ fi
75+ fi
76+
77+ # Fetch all open issues from source repo
78+ # We use --limit 1000 to get a reasonable amount of issues. Adjust if needed.
79+ ISSUE_NUMBERS=$( gh issue list --repo " $SOURCE_REPO " --state open --limit 1000 --json number --jq ' .[].number' )
80+
81+ if [[ -z " $ISSUE_NUMBERS " ]]; then
82+ echo " No open issues found in $SOURCE_REPO ."
83+ exit 0
84+ fi
85+
86+ # Extract short name from SOURCE_REPO (e.g., java-bigquery from googleapis/java-bigquery)
87+ REPO_SHORT_NAME=$( echo " $SOURCE_REPO " | cut -d' /' -f2)
88+
89+ # Process each issue
90+ for ISSUE_NUMBER in $ISSUE_NUMBERS ; do
91+ echo " Processing Issue #$ISSUE_NUMBER ..."
92+
93+ # Get the current title
94+ TITLE=$( gh issue view " $ISSUE_NUMBER " --repo " $SOURCE_REPO " --json title --jq ' .title' )
95+ NEW_TITLE=" [$REPO_SHORT_NAME ] $TITLE "
96+
97+ if [ " $DRY_RUN " = true ]; then
98+ echo " [DRY RUN] Would transfer #$ISSUE_NUMBER to $TARGET_REPO "
99+ echo " [DRY RUN] Would update title to: $NEW_TITLE "
100+ if [[ -n " $REQUIRED_LABEL " ]]; then
101+ echo " [DRY RUN] Would add label '$REQUIRED_LABEL ' to transferred issue"
102+ fi
103+ else
104+ echo " Transferring #$ISSUE_NUMBER ..."
105+ # Capture the output of transfer to get the new issue URL
106+ TRANSFER_OUTPUT=$( gh issue transfer " $ISSUE_NUMBER " " $TARGET_REPO " --repo " $SOURCE_REPO " )
107+
108+ # The output is typically something like: https://github.com/googleapis/google-cloud-java/issues/1234
109+ NEW_ISSUE_URL=$( echo " $TRANSFER_OUTPUT " | grep -o ' https://github.com/[^ ]*' )
110+ NEW_ISSUE_NUMBER=$( echo " $NEW_ISSUE_URL " | awk -F' /' ' {print $NF}' )
111+
112+ if [[ -n " $NEW_ISSUE_NUMBER " ]]; then
113+ echo " Transferred to $TARGET_REPO as #$NEW_ISSUE_NUMBER . Updating issue..."
114+
115+ # Prepare edit command arguments
116+ EDIT_ARGS=(" --title" " $NEW_TITLE " )
117+ if [[ -n " $REQUIRED_LABEL " ]]; then
118+ EDIT_ARGS+=(" --add-label" " $REQUIRED_LABEL " )
119+ fi
120+
121+ gh issue edit " $NEW_ISSUE_NUMBER " --repo " $TARGET_REPO " " ${EDIT_ARGS[@]} "
122+ echo " Issue updated."
123+ else
124+ echo " Warning: Could not determine new issue number from output: $TRANSFER_OUTPUT "
125+ fi
126+ fi
127+ done
128+
129+ echo " Transfer completed."
0 commit comments