Skip to content

Commit 3ea443a

Browse files
committed
[FLINK-38329][GithubAction] Add target release label for back port PRs
Signed-off-by: davidradl <[email protected]>
1 parent 3ffbe56 commit 3ea443a

File tree

1 file changed

+111
-17
lines changed

1 file changed

+111
-17
lines changed

.github/workflows/community-review.sh

Lines changed: 111 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
#
2020
# Community review GitHub Action - sets the community review labels on PRs to show case
2121
# community review activity. See Flip-518 for details
22+
# This github action also sets the target version as a label on PRs.
23+
#
24+
# If more capabilities are added to this script we should consider renaming it to have a
25+
# more generic name.
2226
set -e
2327

2428
# =============================================================================
@@ -29,6 +33,7 @@ REPO_NAME=flink
2933
LGTM_LABEL="community-reviewed-LGTM"
3034
COMMUNITY_REVIEW_LABEL="community-reviewed"
3135
USER_CACHE_FILENAME="user_cache.txt"
36+
PR_CACHE_FILENAME="pr_number_cache.txt"
3237

3338
# =============================================================================
3439
# Community review script - is passed a github token that it uses for authentication
@@ -40,6 +45,8 @@ USER_CACHE_FILENAME="user_cache.txt"
4045
# no changes requested
4146
# - community-reviewed - set if a non-committer has reviewed the PR.
4247
# Note only one of the above labels should be present on a PR.
48+
#
49+
# Additionally this script adds the target branch as a label to each PR.
4350
# =============================================================================
4451
main() {
4552
local token="${1?missing token}"
@@ -52,6 +59,9 @@ main() {
5259
node {
5360
number
5461
isDraft
62+
baseRef {
63+
name
64+
}
5565
timelineItems(first: 100, itemTypes: [PULL_REQUEST_REVIEW]) {
5666
nodes {
5767
... on PullRequestReview {
@@ -99,10 +109,11 @@ main() {
99109
fi
100110
restResponse="$(call_github_graphql_api "$token" "$payload")"
101111
check_github_graphql_response "$restResponse"
102-
receivedPullRequests="$(jq '.data.repository.pullRequests.edges' <<< "$restResponse")"
112+
local receivedPullRequests="$(jq '.data.repository.pullRequests.edges' <<< "$restResponse")"
103113

104114
printf "Filtering %4s received pull requests... " "$(JSONArrayLength "$receivedPullRequests")"
105-
receivedPullRequests=$(jq '[.[] | select((.node.isDraft = false) and (.node.timelineItems.nodes | type != "array" or length > 0))]' <<< "$receivedPullRequests")
115+
116+
receivedPullRequests=$(jq '[.[] | select((.node.isDraft = false))]' <<< "$receivedPullRequests")
106117
printf " %2s PR retained" "$(JSONArrayLength "$receivedPullRequests")"
107118

108119
pullRequests=$(jq --argjson a1 "$pullRequests" --argjson a2 "$receivedPullRequests" '$a1 + $a2' <<< '{}')
@@ -147,23 +158,76 @@ process_each_pr() {
147158

148159
printf "\n(%s/%s) PR %s - " "$counter" "$prCount" "$pr_number"
149160

150-
# find the node for our pr
151-
local pr_reviews
152-
if [[ "$hasNextPage" == "false" ]]; then
153-
all_reviews="$(jq --argjson number "$pr_number" -r '.[] | select(.node.number==$number) | .node.timelineItems.nodes' <<< "$pullRequests")"
154-
else
155-
all_reviews="$(get_all_reviews_for_pr "$token" "$pr_number")"
161+
# Add target branch as label
162+
local target_branch=$(jq --argjson number "$pr_number" -r '.[] | select(.node.number==$number) | .node.baseRef.name' <<< "$pullRequests")
163+
process_target_branch_label "$token" "$pr_number" "$target_branch"
164+
165+
# Add review orientated labels
166+
local has_timeline_items=$(jq --argjson number "$pr_number" -r '.[] | select(.node.number==$number) | (.node.timelineItems.nodes | type != "array" or length > 0)' <<< "$pullRequests")
167+
# Only process reviews if there are timeline items
168+
if [[ "$has_timeline_items" == "true" ]]; then
169+
local all_reviews
170+
if [[ "$hasNextPage" == "false" ]]; then
171+
all_reviews="$(jq --argjson number "$pr_number" -r '.[] | select(.node.number==$number) | .node.timelineItems.nodes' <<< "$pullRequests")"
172+
else
173+
all_reviews="$(get_all_reviews_for_pr "$token" "$pr_number")"
174+
fi
175+
# leave only the latest reviews per reviewer in a comma separated form
176+
pr_reviewers="$(jq '. | sort_by([.author.login, .createdAt]) | reverse | unique_by(.author.login) | .[] | [.author.login, .state, .createdAt] | join(",")' <<< "$all_reviews")"
177+
178+
printf "Reviews %s Reviewers %s\n" "$(JSONArrayLength "$all_reviews")" "$(wc -l <<< "$pr_reviewers" | xargs)"
179+
180+
process_pr_reviews "$token" "$pr_number" "$pr_reviewers" || exit
156181
fi
157-
# leave only the latest reviews per reviewer in a comma separated form
158-
pr_reviewers="$(jq '. | sort_by([.author.login, .createdAt]) | reverse | unique_by(.author.login) | .[] | [.author.login, .state, .createdAt] | join(",")' <<< "$all_reviews")"
159-
160-
printf "Reviews %s Reviewers %s\n" "$(JSONArrayLength "$all_reviews")" "$(wc -l <<< "$pr_reviewers" | xargs)"
161-
162-
process_pr_reviews "$token" "$pr_number" "$pr_reviewers" || exit
163182
((counter++))
164183
done <<< "$prNumbersAndPaging" || exit
165184
}
166185

186+
# =============================================================================
187+
# Process target branch label for a PR
188+
# Arguments:
189+
# $1 - GitHub API token for authentication
190+
# $2 - PR number
191+
# $3 - Target branch name
192+
# =============================================================================
193+
process_target_branch_label() {
194+
local token="${1?missing token}"
195+
local pr_number="${2?missing pr number}"
196+
local target_branch="${3?missing target branch}"
197+
198+
local file_name=$PR_CACHE_FILENAME
199+
200+
local pr_found=false
201+
if [[ -e "$file_name" ]]; then
202+
203+
while IFS=, read -r pr_number_from_file; do
204+
if [[ "$pr_number_from_file" == "$pr_number" ]]; then
205+
pr_found=true
206+
break
207+
fi
208+
done < $file_name
209+
fi
210+
211+
# Only process labels for release branches.
212+
if [[ "$target_branch" == release-* && "$pr_found" == "false" ]]; then
213+
local target_branch_label="target:${target_branch}"
214+
215+
# Ensure the target branch label exists before trying to add it to the PR
216+
ensure_label_exists "$token" "$target_branch_label"
217+
218+
# Get existing labels
219+
local existing_labels=$(call_github_get_labels_api "$pr_number")
220+
221+
# Add target branch label if it doesn't exist on the PR
222+
if [[ ! "$existing_labels" =~ (^|[[:space:]])"$target_branch_label"($|[[:space:]]) ]]; then
223+
call_github_mutate_label_api "$token" "$target_branch_label" "POST" "$pr_number" || exit
224+
printf "Added target branch label %s to PR %s\n" "$target_branch_label" "$pr_number"
225+
local line="$pr_number"
226+
echo "$line">>$file_name
227+
fi
228+
fi
229+
}
230+
167231
# =============================================================================
168232
# Process pr reviews for a pr
169233
# The pr reviews a line for each review, with the user, creation time and review state
@@ -313,8 +377,7 @@ get_all_reviews_for_pr() {
313377
fi
314378
restResponse="$(call_github_graphql_api "$token" "$payload")"
315379
check_github_graphql_response "$restResponse"
316-
local cutdownRestResponse
317-
cutdownRestResponse="$(jq '.data.repository.pullRequest.timelineItems.nodes' <<< "$restResponse")"
380+
local cutdownRestResponse="$(jq '.data.repository.pullRequest.timelineItems.nodes' <<< "$restResponse")"
318381
hasNextPage=$(jq '.data.repository.pullRequest.timelineItems.pageInfo.hasNextPage' <<< "$restResponse")
319382
cursor=$(jq '.data.repository.pullRequest.timelineItems.pageInfo.endCursor' <<< "$restResponse")
320383
# remove quotes from cursor
@@ -352,6 +415,37 @@ call_github_graphql_api() {
352415
"https://api.github.com/graphql"
353416
}
354417

418+
# =============================================================================
419+
# Check if a label exists in the repository and create it if it doesn't
420+
# Arguments:
421+
# $1 - GitHub API token for authentication
422+
# $2 - Label name to check/create
423+
# =============================================================================
424+
ensure_label_exists() {
425+
local token="${1?missing token}"
426+
local label_name="${2?missing label name}"
427+
428+
local color="90EE90"
429+
430+
# Check if the label exists
431+
local label_exists=$(curl --fail --no-progress-meter -s \
432+
-H "Accept: application/json" \
433+
-H "Authorization: Bearer $token" \
434+
"https://api.github.com/repos/$REPO_OWNER/$REPO_NAME/labels/$label_name" \
435+
-w "%{http_code}" -o /dev/null || echo "404")
436+
437+
# If label doesn't exist (404), create it
438+
if [[ "$label_exists" == "404" ]]; then
439+
sprintf "Creating label %s" "$label_name"
440+
curl --fail --no-progress-meter -s \
441+
-H "Content-Type: application/json" \
442+
-H "Authorization: Bearer $token" \
443+
-X POST \
444+
-d "{\"name\":\"$label_name\",\"color\":\"$color\"}" \
445+
"https://api.github.com/repos/$REPO_OWNER/$REPO_NAME/labels"
446+
fi
447+
}
448+
355449
# =============================================================================
356450
# Check the response of the cURL request. Exit in case of error.
357451
# Arguments:
@@ -475,7 +569,7 @@ call_github_get_user_push_permission() {
475569
"https://api.github.com/repos/$REPO_OWNER/$REPO_NAME/collaborators/$user_name/permission") || exit
476570
push_permission=$(jq -r '.user.permissions.push' <<< "$permissions")
477571
# write line to file
478-
line="$user_name,$push_permission"
572+
local line="$user_name,$push_permission"
479573
echo "$line">>$file_name
480574
fi
481575
# echo out the permissions

0 commit comments

Comments
 (0)