1- #! /bin/bash
1+ #! /usr/ bin/env bash
22set -euo pipefail
33
4- # 1. Define Helper Functions First
4+ # ######################################
5+ # Logging helper
6+ # ######################################
57log () {
68 echo " [advanced-check] $1 "
79}
810
9- # 2. Validate required environment variables
10- if [[ -z " ${REPO:- } " ]] || [[ -z " ${ISSUE_NUMBER:- } " ]] || [[ -z " ${GH_TOKEN:- } " ]]; then
11- log " ERROR: Required environment variables (REPO, ISSUE_NUMBER, GH_TOKEN) must be set"
11+ # ######################################
12+ # Validate required environment variables
13+ # ######################################
14+ if [[ -z " ${REPO:- } " ]]; then
15+ log " ERROR: REPO must be set (e.g. owner/name)"
1216 exit 1
1317fi
1418
15- # 3. Function to check a single user
19+ OWNER=" ${REPO%%/* } "
20+ NAME=" ${REPO##*/ } "
21+
22+ # ######################################
23+ # GraphQL count helper (INTERMEDIATE ONLY)
24+ # ######################################
25+ get_intermediate_count () {
26+ local user=$1
27+
28+ gh api graphql -f query="
29+ {
30+ repository(owner: \" $OWNER \" , name: \" $NAME \" ) {
31+ intermediate: issues(
32+ first: 1
33+ states: CLOSED
34+ filterBy: {
35+ assignee: \" $user \"
36+ labels: [\" intermediate\" ]
37+ }
38+ ) {
39+ totalCount
40+ }
41+ }
42+ }"
43+ }
44+
45+ # ######################################
46+ # Helper: has bot already commented for user?
47+ # ######################################
48+ already_commented () {
49+ local user=$1
50+
51+ gh issue view " $ISSUE_NUMBER " --repo " $REPO " \
52+ --json comments \
53+ --jq --arg user " @$user " '
54+ .comments[].body
55+ | select(test("Hi " + $user + ", I cannot assign you to this issue yet."))
56+ ' | grep -q .
57+ }
58+
59+ # ######################################
60+ # Helper: is user currently assigned?
61+ # ######################################
62+ is_assigned () {
63+ local user=$1
64+
65+ gh issue view " $ISSUE_NUMBER " --repo " $REPO " \
66+ --json assignees \
67+ --jq --arg user " $user " '
68+ .assignees[].login | select(. == $user)
69+ ' | grep -q .
70+ }
71+
72+ # ######################################
73+ # DRY RUN MODE
74+ # ######################################
75+ if [[ " ${DRY_RUN:- false} " == " true" ]]; then
76+ if [[ -z " ${DRY_RUN_USER:- } " ]]; then
77+ log " ERROR: DRY_RUN_USER must be set when DRY_RUN=true"
78+ exit 1
79+ fi
80+
81+ USER=" $DRY_RUN_USER "
82+ log " DRY RUN MODE ENABLED"
83+ log " Repository: $REPO "
84+ log " User: @$USER "
85+
86+ COUNTS=$( get_intermediate_count " $USER " )
87+ INT_COUNT=$( jq ' .data.repository.intermediate.totalCount' <<< " $COUNTS" )
88+
89+ echo
90+ log " Intermediate Issues (closed): $INT_COUNT "
91+
92+ if (( INT_COUNT >= 1 )) ; then
93+ log " Result: USER QUALIFIED"
94+ else
95+ log " Result: USER NOT QUALIFIED"
96+ fi
97+
98+ exit 0
99+ fi
100+
101+ # ######################################
102+ # NORMAL MODE (ENFORCEMENT)
103+ # ######################################
104+ if [[ -z " ${ISSUE_NUMBER:- } " ]]; then
105+ log " ERROR: ISSUE_NUMBER must be set in normal mode"
106+ exit 1
107+ fi
108+
109+ # ######################################
110+ # Check a single user
111+ # ######################################
16112check_user () {
17113 local user=$1
18114 log " Checking qualification for @$user ..."
19115
20116 # Permission exemption
21- PERM_JSON=$( gh api " repos/$REPO /collaborators/$user /permission" 2> /dev/null || echo ' {"permission":"none"}' )
22- PERMISSION=$( echo " $PERM_JSON " | jq -r ' .permission // "none"' )
117+ PERMISSION=$(
118+ gh api " repos/$REPO /collaborators/$user /permission" \
119+ --jq ' .permission // "none"' 2> /dev/null || echo " none"
120+ )
23121
24122 if [[ " $PERMISSION " =~ ^(admin| write| triage)$ ]]; then
25- log " User @$user is core member ($PERMISSION ). Qualification check skipped ."
123+ log " User @$user is core member ($PERMISSION ). Skipping ."
26124 return 0
27125 fi
28126
29- # 2. Get counts
30- # Using exact repository label names ("Good First Issue" and "intermediate")
31- GFI_QUERY=" repo:$REPO is:issue is:closed assignee:$user -reason:\" not planned\" label:\" Good First Issue\" "
32- INT_QUERY=" repo:$REPO is:issue is:closed assignee:$user -reason:\" not planned\" label:\" intermediate\" "
33-
34- GFI_COUNT=$( gh api " search/issues" -f q=" $GFI_QUERY " --jq ' .total_count' || echo " 0" )
35- INT_COUNT=$( gh api " search/issues" -f q=" $INT_QUERY " --jq ' .total_count' || echo " 0" )
127+ COUNTS=$( get_intermediate_count " $user " )
128+ INT_COUNT=$( jq ' .data.repository.intermediate.totalCount' <<< " $COUNTS" )
36129
37- # Numeric validation
38- if ! [[ " $GFI_COUNT " =~ ^[0-9]+$ ]]; then GFI_COUNT=0; fi
39- if ! [[ " $INT_COUNT " =~ ^[0-9]+$ ]]; then INT_COUNT=0; fi
130+ log " Counts → Intermediate: $INT_COUNT "
40131
41- # Validation Logic
42- if (( GFI_COUNT >= 1 )) && (( INT_COUNT >= 1 )) ; then
132+ if (( INT_COUNT >= 1 )) ; then
43133 log " User @$user qualified."
44134 return 0
45- else
46- log " User @$user failed. Unassigning..."
135+ fi
47136
48- # Tailor the suggestion based on what is missing
49- # Links and names now match exact repository labels
50- if (( GFI_COUNT == 0 )) ; then
51- SUGGESTION=" [Good First Issue](https://github.com/$REPO /labels/Good%20First%20Issue)"
52- else
53- SUGGESTION=" [intermediate issue](https://github.com/$REPO /labels/intermediate)"
54- fi
137+ # ##################################
138+ # Failure path (duplicate-safe)
139+ # ##################################
140+ log " User @$user NOT qualified."
55141
56- # Post the message FIRST, then unassign.
57- MSG=" Hi @$user , I cannot assign you to this issue yet.
142+ SUGGESTION=" [intermediate issues](https://github.com/$REPO /labels/intermediate)"
143+
144+ MSG=" Hi @$user , I cannot assign you to this issue yet.
58145
59146**Why?**
60- Advanced issues involve high-risk changes to the core codebase. They require significant testing and can impact automation and CI behavior .
147+ Advanced issues involve high-risk changes to the core codebase and require prior experience in this repository .
61148
62149**Requirement:**
63- - Complete at least **1** 'Good First Issue' (You have: **$GFI_COUNT **)
64150- Complete at least **1** 'intermediate' issue (You have: **$INT_COUNT **)
65151
66- Please check out our **$SUGGESTION ** tasks to build your experience first!"
152+ Please check out our **$SUGGESTION ** to build your experience first!"
67153
154+ if already_commented " $user " ; then
155+ log " Comment already exists for @$user . Skipping comment."
156+ else
157+ log " Posting comment for @$user ."
68158 gh issue comment " $ISSUE_NUMBER " --repo " $REPO " --body " $MSG "
159+ fi
160+
161+ if is_assigned " $user " ; then
162+ log " Unassigning @$user ."
69163 gh issue edit " $ISSUE_NUMBER " --repo " $REPO " --remove-assignee " $user "
164+ else
165+ log " User @$user already unassigned. Skipping."
70166 fi
71167}
72168
73- # --- Main Logic ---
169+ # ######################################
170+ # Main execution
171+ # ######################################
172+ log " Normal enforcement mode enabled"
173+ log " Repository: $REPO "
174+ log " Issue: #$ISSUE_NUMBER "
74175
75176if [[ -n " ${TRIGGER_ASSIGNEE:- } " ]]; then
76177 check_user " $TRIGGER_ASSIGNEE "
77178else
78- log " Checking all current assignees..."
79-
80- # Fetch assignees into a variable first.
81- ASSIGNEE_LIST=$( gh issue view " $ISSUE_NUMBER " --repo " $REPO " --json assignees --jq ' .assignees[].login' )
179+ log " Checking all assignees..."
82180
83- if [[ -z " $ASSIGNEE_LIST " ]]; then
84- log " No assignees found to check."
85- else
86- # Use a here-string (<<<) to iterate over the variable safely.
87- while read -r user; do
88- if [[ -n " $user " ]]; then
89- check_user " $user "
90- fi
91- done <<< " $ASSIGNEE_LIST"
181+ ASSIGNEES=$(
182+ gh issue view " $ISSUE_NUMBER " --repo " $REPO " \
183+ --json assignees --jq ' .assignees[].login'
184+ )
185+
186+ if [[ -z " $ASSIGNEES " ]]; then
187+ log " No assignees found."
188+ exit 0
92189 fi
93- fi
190+
191+ while read -r user; do
192+ [[ -n " $user " ]] && check_user " $user "
193+ done <<< " $ASSIGNEES"
194+ fi
0 commit comments