-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathghbot
executable file
·276 lines (254 loc) · 8.57 KB
/
ghbot
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
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
#!/bin/bash
# Bash OctoBot
if [[ -z "$personal_github_token" ]]; then
cat << EOF
Error: 'personal_github_token' environment variable not set.
To resolve this:
1. Generate a GitHub personal access token with the 'user:follow' and 'read:user' scopes at https://github.com/settings/tokens.
2. Set the token in your environment with:
export personal_github_token="your_token_here"
3. To make this change permanent, add it to your '~/.bashrc' with:
echo 'export personal_github_token="your_token_here"' >> ~/.bashrc
source ~/.bashrc
After setting up the token, you can run OctoBot commands with:
ghbot <command> [username]
For more details, visit the GitHub repository.
EOF
exit 1
fi
github_user=$(curl -s -H "Authorization: token $personal_github_token" https://api.github.com/user | jq -r '.login')
rate_limit_count_file=$(mktemp /tmp/rate_limit_count.XXXXXX)
handle_rate_limit() {
local count=$(cat "$rate_limit_count_file" 2>/dev/null || echo 0)
count=$((count + 1))
local delay=$((60 * count))
echo "Rate limit exceeded. Waiting for ${delay}s ..."
sleep "$delay"
echo "$count" > "$rate_limit_count_file"
}
rate_reset() {
rm -f "$rate_limit_count_file"
}
fetch_data() {
local url="$1"
local all_data=()
while [[ -n "$url" ]]; do
local response=$(curl -s -H "Authorization: token $personal_github_token" "$url")
local status_code=$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: token $personal_github_token" "$url")
if [[ "$status_code" -eq 429 ]]; then
handle_rate_limit
continue
fi
rate_reset
all_data+=($(echo "$response" | jq -r '.[] | .login'))
url=$(curl -sI -H "Authorization: token $personal_github_token" "$url" | grep -i '^Link:' | sed -e 's/.*<\(https:\/\/api.github.com\/[^\"]*\)>; rel="next".*/\1/')
done
echo "${all_data[@]}"
}
fetch_followers() {
local user="$1"
local page=1
local per_page=100
local all_followers=()
local followers_url="https://api.github.com/users/$user/followers?per_page=$per_page&page="
while :; do
local response=$(curl -s -H "Authorization: token $personal_github_token" "${followers_url}${page}")
if [[ "$response" == *"API rate limit exceeded"* ]]; then
handle_rate_limit
response=$(curl -s -H "Authorization: token $personal_github_token" "${followers_url}${page}")
fi
local followers=$(echo "$response" | jq -r '.[].login')
if [[ -z "$followers" ]]; then
break
fi
all_followers+=($followers)
if [[ $(echo "$response" | jq '. | length') -lt $per_page ]]; then
break
fi
page=$((page + 1))
done
rate_reset
echo "${all_followers[@]}"
}
fetch_following() {
local user="$1"
local page=1
local per_page=100
local all_following=()
local following_url="https://api.github.com/users/$user/following?per_page=$per_page&page="
while :; do
local response=$(curl -s -H "Authorization: token $personal_github_token" "${following_url}${page}")
if [[ "$response" == *"API rate limit exceeded"* ]]; then
handle_rate_limit
response=$(curl -s -H "Authorization: token $personal_github_token" "${following_url}${page}")
fi
local following=$(echo "$response" | jq -r '.[].login')
if [[ -z "$following" ]]; then
break
fi
all_following+=($following)
if [[ $(echo "$response" | jq '. | length') -lt $per_page ]]; then
break
fi
page=$((page + 1))
done
rate_reset
echo "${all_following[@]}"
}
follow_user() {
local user="$1"
local user_info=$(curl -s -H "Authorization: token $personal_github_token" "https://api.github.com/users/$user")
local followers=$(echo "$user_info" | jq -r '.followers')
local following=$(echo "$user_info" | jq -r '.following')
if [[ "$followers" == "null" || "$following" == "null" ]]; then
#echo "User $user not found or profile is private."
return
fi
if [[ "$followers" -eq 0 && "$following" -eq 0 ]]; then
#echo "User $user has 0 followers and 0 following. Possibly a private profile or new account."
return
fi
local response=$(curl -s -o /dev/null -w "%{http_code}" -X PUT -H "Authorization: token $personal_github_token" "https://api.github.com/user/following/$user")
case "$response" in
"204")
echo "User: $user has been followed!"
;;
"403"|"429"|"500")
echo "Error following $user: Forbidden. Handling rate limit..."
handle_rate_limit
follow_user "$user"
;;
"404")
echo "Error following $user: User not found or profile is private."
;;
"422")
echo "Error following $user: User already followed or invalid request."
;;
*)
echo "Error following $user: $response"
exit 1
;;
esac
rate_reset
}
unfollow_user() {
local user="$1"
local user_info=$(curl -s -H "Authorization: token $personal_github_token" "https://api.github.com/users/$user")
local followers=$(echo "$user_info" | jq -r '.followers')
local following=$(echo "$user_info" | jq -r '.following')
if [[ "$followers" == "null" || "$following" == "null" ]]; then
#echo "User $user not found or profile is private."
return
fi
if [[ "$followers" -eq 0 && "$following" -eq 0 ]]; then
#echo "User $user has 0 followers and 0 following. Possibly a private profile or new account."
return
fi
local response=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE -H "Authorization: token $personal_github_token" "https://api.github.com/user/following/$user")
case "$response" in
"204")
echo "User: $user has been unfollowed!"
;;
"403"|"429"|"500")
echo "Error unfollowing $user: Forbidden. Handling rate limit..."
handle_rate_limit
unfollow_user "$user"
;;
*)
echo "Error unfollowing $user: $response"
exit 1
;;
esac
rate_reset
}
process_users() {
local users=("$@")
local max_jobs=10
local job_count=0
for user in "${users[@]}"; do
if [[ "$command" == "unfollow" ]]; then
unfollow_user "$user"
elif [[ "$command" == "follow" ]]; then
follow_user "$user"
fi
((job_count++))
if [[ $job_count -ge $max_jobs ]]; then
wait -n
job_count=$((job_count - 1))
fi
done
wait
}
parse_blacklist() {
local blacklist_input="$1"
IFS=$'\n' read -r -d '' -a blacklist <<< "$(echo "$blacklist_input" | tr ',' '\n')"
}
cleanup() {
rate_reset
exit 0
}
trap cleanup SIGINT EXIT
command="$1"
shift
blacklist=()
case "$command" in
"unfollow")
if [[ ! -z "$1" ]]; then
blacklist_input="$1"
parse_blacklist "$blacklist_input"
fi
following=($(fetch_following "$github_user"))
followers=($(fetch_followers "$github_user"))
users_to_unfollow=()
for user in "${following[@]}"; do
if [[ ! " ${followers[@]} " =~ " $user " && "$user" != "$github_user" && ! " ${blacklist[@]} " =~ " $user " ]]; then
users_to_unfollow+=("$user")
fi
done
process_users "${users_to_unfollow[@]}"
;;
"followers")
followers=($(fetch_followers "$github_user"))
echo "You have ${#followers[@]} followers."
;;
"following")
following=($(fetch_following "$github_user"))
echo "You follow ${#following[@]} users."
;;
"follow")
if [[ ! -z "$1" ]]; then
target_user="$1"
shift
elif [[ -z "$target_user" ]]; then
read -p "User to fetch? " target_user
fi
if [[ ! -z "$1" ]]; then
blacklist_input="$1"
parse_blacklist "$blacklist_input"
fi
followers=($(fetch_followers "$target_user"))
following=($(fetch_following "$github_user"))
users_to_follow=()
for user in "${followers[@]}"; do
if [[ ! " ${following[@]} " =~ " $user " && "$user" != "$github_user" && ! " ${blacklist[@]} " =~ " $user " ]]; then
users_to_follow+=("$user")
fi
done
process_users "${users_to_follow[@]}"
;;
*)
cat << EOF
Invalid option: $command
Usage:
ghbot followers # Display the count of your followers
ghbot following # Display the count of users you follow
ghbot follow [username] [blacklist] # Follow users who follow the specified username
ghbot unfollow [blacklist] # Unfollow users who do not follow you back
Info:
blacklist -> \"usr0,usr1,..\" (Optional)
EOF
exit 1
;;
esac
echo -e "Operation completed!"
cleanup