Repository navigation
Expand file tree
/
Copy pathscript.sh
More file actions
executable file
·255 lines (205 loc) · 7.93 KB
/
Copy pathscript.sh
File metadata and controls
executable file
·255 lines (205 loc) · 7.93 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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
#!/bin/bash
# Security helper functions
url_encode() {
local string="${1}"
# Use printf for URL encoding while preserving special characters needed for versions
printf '%s' "$string" | jq -sRr @uri
}
validate_ref_name() {
local ref="${1}"
# Allow version tags (v1.2.3), branch names, and commit SHAs
if [[ ! "$ref" =~ ^[a-zA-Z0-9._/-]+$ ]]; then
echo "Error: Invalid reference format: $ref"
echo "References can contain alphanumeric characters, dots, underscores, hyphens, and forward slashes"
exit 1
fi
}
sanitize_input() {
local input="${1}"
# Preserve valid characters for Git references, including version numbers
echo "${input}" | tr -cd 'a-zA-Z0-9._/-'
}
validate_branch_name() {
local branch="${1}"
if [[ ! "$branch" =~ ^[a-zA-Z0-9._-]+$ ]]; then
echo "Error: Invalid branch name format: $branch"
echo "Branch names can only contain alphanumeric characters, dots, underscores, and hyphens."
exit 1
fi
}
validate_repo_name() {
local repo="${1}"
if [[ ! "$repo" =~ ^[a-zA-Z0-9._-]+$ ]]; then
echo "Error: Invalid repository name format: $repo"
echo "Repository names can only contain alphanumeric characters, dots, underscores, and hyphens."
exit 1
fi
}
# GitHub repository owner
OWNER="${OWNER:-strapi}"
# GitHub repository name
REPO="${REPO:-strapi}"
# Base branch
BASE_BRANCH="${BASE_BRANCH:-develop}"
# Target branch
TARGET_BRANCH="${TARGET_BRANCH:-develop}"
# Validate inputs
validate_repo_name "$OWNER"
validate_repo_name "$REPO"
validate_ref_name "$BASE_BRANCH"
validate_ref_name "$TARGET_BRANCH"
# Set Authorization Header if GITHUB_TOKEN is available
AUTH_HEADER=""
if [ -n "$GITHUB_TOKEN" ]; then
AUTH_HEADER="Authorization: token $GITHUB_TOKEN"
fi
# URL encode components for API endpoint
ENCODED_OWNER=$(url_encode "$OWNER")
ENCODED_REPO=$(url_encode "$REPO")
ENCODED_BASE=$(url_encode "$BASE_BRANCH")
ENCODED_TARGET=$(url_encode "$TARGET_BRANCH")
# GitHub API endpoint for comparing commits with encoded parameters
COMPARE_API="https://api.github.com/repos/${ENCODED_OWNER}/${ENCODED_REPO}/compare/${ENCODED_BASE}...${ENCODED_TARGET}"
# Function to show progress bar
show_progress() {
local current="$1"
local total="$2"
local label="$3"
local width=50
local percent=$((current * 100 / total))
local filled=$((current * width / total))
local empty=$((width - filled))
# Build progress bar
printf "\r["
for ((i = 0; i < filled; i++)); do printf "="; done
for ((i = 0; i < empty; i++)); do printf " "; done
printf "] %d%% (%d/%d) - %s" "$percent" "$current" "$total" "$label"
}
# Function to make secure API calls
make_api_call() {
local url="$1"
local response
response=$(curl -s -w "%{http_code}" \
-H "${AUTH_HEADER}" \
"$url")
echo "$response"
}
echo "Comparing ${ENCODED_BASE} and ${ENCODED_TARGET} (${ENCODED_OWNER}/${ENCODED_REPO})"
# Get list of commits between the two branches
response=$(make_api_call "$COMPARE_API")
http_status="${response: -3}"
api_response="${response::-3}"
# Check for HTTP status and handle errors
if [ "$http_status" -ne 200 ]; then
error_message=$(echo "$api_response" | jq -r '.message // "Unknown error occurred"')
errors=$(echo "$api_response" | jq -r '.errors[]?.message // empty')
echo "Error: Failed to fetch commits. HTTP Status: $http_status"
echo "Reason: $error_message"
if [ -n "$errors" ]; then
echo "Details:"
echo "$errors"
fi
exit 1
fi
# Parse commits from the API response safely
echo "Fetching the list of commits..."
commits=$(echo "$api_response" | jq -r '.commits[].sha')
commit_count=$(echo "$commits" | wc -w)
if [ "$commit_count" -lt 1 ]; then
echo "No commits found between $BASE_BRANCH and $TARGET_BRANCH, or the API returned an empty response."
exit 1
else
echo "Found $commit_count commits between $BASE_BRANCH and $TARGET_BRANCH."
fi
# Initialize variables to collect merged PRs
prs="[]"
declare -A seen_prs # Track processed PRs to avoid duplicates
# Loop over each commit SHA and find associated pull requests
current_commit=0
echo "Processing commits and fetching associated PRs..."
for sha in $commits; do
current_commit=$((current_commit + 1))
# Validate SHA format
if [[ ! "$sha" =~ ^[0-9a-f]{40}$ ]]; then
echo "Warning: Invalid commit SHA format: $sha"
continue
fi
# Show progress bar with the current commit SHA
show_progress "$current_commit" "$commit_count" "$sha"
# Fetch pull requests linked to the commit with encoded SHA
encoded_sha=$(url_encode "$sha")
pr_url="https://api.github.com/repos/${ENCODED_OWNER}/${ENCODED_REPO}/commits/${encoded_sha}/pulls"
prs_response=$(make_api_call "$pr_url")
prs_http_status="${prs_response: -3}"
prs_api_response="${prs_response::-3}"
# Handle errors in PR fetching
if [ "$prs_http_status" -ne 200 ]; then
pr_error_message=$(echo "$prs_api_response" | jq -r '.message // "Unknown error occurred"')
pr_errors=$(echo "$prs_api_response" | jq -r '.errors[]?.message // empty')
echo "Warning: Failed to fetch PRs for commit $sha. HTTP Status: $prs_http_status"
echo "Reason: $pr_error_message"
if [ -n "$pr_errors" ]; then
echo "Details:"
echo "$pr_errors"
fi
continue
fi
# Process pull requests for the commit
while read -r pr; do
pr_number=$(echo "$pr" | jq -r '.number')
if [[ ! "$pr_number" =~ ^[0-9]+$ ]]; then
continue # Skip invalid PR numbers
fi
if [[ -n "${seen_prs[$pr_number]}" ]]; then
continue # Skip PR if processed already
fi
# Mark this PR as processed
seen_prs[$pr_number]=1
# Check if the pull request is merged
merged_at=$(echo "$pr" | jq -r '.merged_at')
if [ "$merged_at" != "null" ]; then
# Safely extract PR information using jq
pr_title=$(echo "$pr" | jq -r '.title // ""')
pr_url=$(echo "$pr" | jq -r '.html_url // ""')
pr_author=$(echo "$pr" | jq -r '.user.login // ""')
# Validate extracted data
if [[ -n "$pr_title" && -n "$pr_url" && -n "$pr_author" ]]; then
# Append PR to the prs array using proper JSON escaping
prs=$(echo "$prs" | jq \
--arg pr_number "$pr_number" \
--arg pr_title "$pr_title" \
--arg pr_author "$pr_author" \
--arg pr_url "$pr_url" \
'. += [{
"number": $pr_number,
"title": $pr_title,
"author": $pr_author,
"url": $pr_url
}]')
fi
fi
done < <(echo "$prs_api_response" | jq -c '.[]')
done
# Finish progress bar
printf "\n"
# Output the final merged PRs
echo "Final list of merged PRs:"
echo "$prs" | jq '.'
# Set the JSON-formatted PRs as the GitHub Action output
# Check if there are merged PRs
if [ "$(echo "$prs" | jq -r 'length')" -eq 0 ]; then
echo "No merged pull requests found." >> $GITHUB_STEP_SUMMARY
exit 0
fi
# Write the Markdown table to the GitHub Actions summary
echo "### Merged Pull Requests Between '${BASE_BRANCH}' and '${TARGET_BRANCH}'" >> $GITHUB_STEP_SUMMARY
echo "| PR Number | Title | Author | Link |" >> $GITHUB_STEP_SUMMARY
echo "|-----------|----------------------------|-------------|-----------------------------------|" >> $GITHUB_STEP_SUMMARY
echo "$prs" | jq -c '.[]' | while read -r pr; do
pr_number=$(echo "$pr" | jq -r '.number')
pr_title=$(echo "$pr" | jq -r '.title')
pr_author=$(echo "$pr" | jq -r '.author')
pr_link=$(echo "$pr" | jq -r '.url')
# Append each PR row to the summary table
echo "| #${pr_number} | ${pr_title} | ${pr_author} | [Link](${pr_link}) |" >> $GITHUB_STEP_SUMMARY
done