-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgithub-issue-copy.sh
More file actions
233 lines (201 loc) · 6.69 KB
/
github-issue-copy.sh
File metadata and controls
233 lines (201 loc) · 6.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
#!/bin/bash
# Default repositories
SOURCE_REPO="OWNER/REPO"
DEST_REPO="OWNER/REPO"
# Function to show usage
usage() {
echo "Usage: $0 <issue_number> [OPTIONS]"
echo "Options:"
echo " -s, --source-repo <owner/repo> Specify source repository"
echo " -d, --dest-repo <owner/repo> Specify destination repository"
echo " -r, --relationship Create parent-child relationship"
echo " -q, --quiet Quiet mode - suppress non-essential output"
echo "Examples:"
echo " $0 123"
echo " $0 123 -s owner/repo -d owner/another-repo"
echo " $0 123 -r"
exit 1
}
# Default flags
CREATE_RELATIONSHIP=false
QUIET_MODE=false
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
-s|--source-repo)
SOURCE_REPO="$2"
shift 2
;;
-d|--dest-repo)
DEST_REPO="$2"
shift 2
;;
-r|--relationship)
CREATE_RELATIONSHIP=true
shift
;;
-q|--quiet)
QUIET_MODE=true
shift
;;
-*)
echo "Unknown option: $1"
usage
;;
*)
if [ -z "$ISSUE_NUMBER" ]; then
ISSUE_NUMBER=$1
else
usage
fi
shift
;;
esac
done
# Modify echo statements to use a log function
log() {
if [ "$QUIET_MODE" = false ]; then
echo "$@"
fi
}
# Check if issue number is provided
if [ -z "$ISSUE_NUMBER" ]; then
log "No issue number provided. Using hardcoded repositories."
log "Source Repository: $SOURCE_REPO"
log "Destination Repository: $DEST_REPO"
read -p "Enter the issue number: " ISSUE_NUMBER
fi
# Construct the source URL
SOURCE_URL="https://github.com/$SOURCE_REPO/issues/$ISSUE_NUMBER"
# Verify gh cli is installed
if ! command -v gh &> /dev/null; then
echo "Error: GitHub CLI (gh) is not installed"
echo "Please install it from: https://cli.github.com/"
exit 1
fi
# Verify jq is installed
if ! command -v jq &> /dev/null; then
echo "Error: jq is not installed"
echo "Please install jq using your package manager"
exit 1
fi
log "Copying issue #$ISSUE_NUMBER from $SOURCE_REPO to $DEST_REPO..."
# Get full issue data including comments
issue_data=$(gh issue view $ISSUE_NUMBER -R $SOURCE_REPO --json title,body,labels,assignees,comments)
if [ $? -ne 0 ]; then
echo "Error: Failed to fetch issue data. Please check if:"
echo "1. The issue number is correct"
echo "2. You have access to the repository"
echo "3. You are authenticated with gh cli"
exit 1
fi
# Extract components using jq
title=$(echo "$issue_data" | jq -r .title)
body=$(echo "$issue_data" | jq -r .body)
# Handle labels
log "Processing labels..."
# Get list of existing labels in destination repo (fetch all pages)
existing_labels=$(gh label list -R $DEST_REPO --json name --limit 1000 | jq -r '.[].name')
# Function to normalize strings by trimming whitespace and converting to lowercase
normalize() {
echo "$1" | sed 's/^[ \t]*//;s/[ \t]*$//' | tr '[:upper:]' '[:lower:]'
}
# Create array to store labels for the new issue
label_names=()
# Process each label name from the source issue
while IFS= read -r name; do
if [ ! -z "$name" ]; then
# Normalize the label name
name=$(normalize "$name")
# Check if label exists in destination
if ! echo "$existing_labels" | tr '[:upper:]' '[:lower:]' | grep -q "^$(normalize "$name")$"; then
log "Creating missing label: $name"
# Create label with default color (using gray as fallback)
gh label create "$name" -R $DEST_REPO --color "cccccc" >/dev/null 2>&1 || echo "Failed to create label: $name"
else
log "Label already exists: $name"
fi
label_names+=("$name")
fi
done < <(echo "$issue_data" | jq -r '.labels[].name')
# Format comments
comments_text=$(echo "$issue_data" | jq -r '.comments[] | "### Comment by @\(.author.login) on \(.createdAt)\n\n\(.body)\n"')
# Add reference to original issue and include comments in the body
new_body="$body
---
### Original Comments from $SOURCE_URL
$comments_text
---
*Copied from original issue: $SOURCE_URL*"
# Create new issue with extracted data
log "Creating new issue in $DEST_REPO..."
new_issue_url=$(gh issue create -R $DEST_REPO \
--title "$title" \
--body "$new_body" | grep -Eo 'https://github.com/[^ ]+')
if [ $? -eq 0 ]; then
echo "Successfully created new issue: $new_issue_url"
else
echo "Error: Failed to create new issue"
exit 1
fi
# Add labels to the newly created issue
for label in "${label_names[@]}"; do
log "Adding label: $label"
gh issue edit "$new_issue_url" -R $DEST_REPO --add-label "$label" >/dev/null 2>&1 || echo "Failed to add label: $label"
done
if [ $? -eq 0 ]; then
log "Successfully added labels to the issue!"
else
echo "Error: Failed to add some labels"
fi
# Create relationship only if flag is set
if [ "$CREATE_RELATIONSHIP" = true ]; then
# Extract issue numbers from URLs
SOURCE_ISSUE_NUMBER=$(echo "$SOURCE_URL" | grep -o '[0-9]*$')
DEST_ISSUE_NUMBER=$(echo "$new_issue_url" | grep -o '[0-9]*$')
# Get the GraphQL Node IDs for the source and destination issues
log "Fetching Node IDs for the source and destination issues..."
SOURCE_NODE_ID=$(gh api graphql -F query='
query ($owner: String!, $repo: String!, $number: Int!) {
repository(owner: $owner, name: $repo) {
issue(number: $number) {
id
}
}
}
' -F owner="$(echo $SOURCE_REPO | cut -d'/' -f1)" \
-F repo="$(echo $SOURCE_REPO | cut -d'/' -f2)" \
-F number="$ISSUE_NUMBER" \
-q '.data.repository.issue.id')
DEST_NODE_ID=$(gh api graphql -F query='
query ($owner: String!, $repo: String!, $number: Int!) {
repository(owner: $owner, name: $repo) {
issue(number: $number) {
id
}
}
}
' -F owner="$(echo $DEST_REPO | cut -d'/' -f1)" \
-F repo="$(echo $DEST_REPO | cut -d'/' -f2)" \
-F number="$(echo $new_issue_url | grep -o '[0-9]*$')" \
-q '.data.repository.issue.id')
# Add the relationship to the relationships section
log "Setting parent relationship..."
gh api graphql -f query='
mutation {
addSubIssue(input: {
issueId: "'"$SOURCE_NODE_ID"'",
subIssueId: "'"$DEST_NODE_ID"'"
}) {
subIssue {
id
}
}
}
' >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo "Successfully set parent relationship between issues!"
else
echo "Error: Failed to set parent relationship between issues."
fi
fi