
























@@ -0,0 +1,180 @@
1+#!/usr/bin/env bash
2+set -euo pipefail
3+4+repo="openclaw/openclaw"
5+months="12"
6+include_global="0"
7+8+usage() {
9+printf 'Usage: %s [--repo owner/repo] [--months N] [--global] <github-login> [login...]\n' "$0"
10+}
11+12+die() {
13+printf 'error: %s\n' "$*" >&2
14+exit 1
15+}
16+17+need() {
18+command -v "$1" >/dev/null 2>&1 || die "missing required command: $1"
19+}
20+21+date_utc_relative_months() {
22+local count="$1"
23+if date -u -v-"${count}"m +%Y-%m-%dT%H:%M:%SZ >/dev/null 2>&1; then
24+ date -u -v-"${count}"m +%Y-%m-%dT%H:%M:%SZ
25+return
26+fi
27+ date -u -d "${count} months ago" +%Y-%m-%dT%H:%M:%SZ
28+}
29+30+date_to_epoch() {
31+local value="$1"
32+if date -u -j -f '%Y-%m-%dT%H:%M:%SZ' "$value" +%s >/dev/null 2>&1; then
33+ date -u -j -f '%Y-%m-%dT%H:%M:%SZ' "$value" +%s
34+return
35+fi
36+ date -u -d "$value" +%s
37+}
38+39+rough_age() {
40+local created_at="$1"
41+local now_s created_s days
42+ now_s=$(date -u +%s)
43+ created_s=$(date_to_epoch "$created_at")
44+ days=$(( (now_s - created_s) / 86400 ))
45+if (( days < 120 )); then
46+printf '~%dd old' "$days"
47+return
48+fi
49+ awk -v days="$days" 'BEGIN { printf "~%.1fy old", days / 365.2425 }'
50+}
51+52+count_threads() {
53+local kind="$1"
54+local login="$2"
55+local since_ts="$3"
56+local kind_filter
57+if [[ "$kind" == "prs" ]]; then
58+ kind_filter='has("pull_request")'
59+else
60+ kind_filter='has("pull_request") | not'
61+fi
62+ gh api --paginate "repos/${repo}/issues?state=all&creator=${login}&since=${since_ts}&per_page=100" \
63+ --jq ".[] | select(.created_at >= \"${since_ts}\") | select(${kind_filter}) | .number" |
64+ wc -l |
65+ tr -d '[:space:]'
66+}
67+68+count_commits() {
69+local login="$1"
70+local since_ts="$2"
71+ gh api --paginate "repos/${repo}/commits?author=${login}&since=${since_ts}&per_page=100" \
72+ --jq '.[].sha' | wc -l | tr -d '[:space:]'
73+}
74+75+global_activity() {
76+local login="$1"
77+local since_ts="$2"
78+local now_ts="$3"
79+# shellcheck disable=SC2016
80+ gh api graphql \
81+ -f login="$login" \
82+ -f from="$since_ts" \
83+ -f to="$now_ts" \
84+ -f query='
85+query($login: String!, $from: DateTime!, $to: DateTime!) {
86+ user(login: $login) {
87+ contributionsCollection(from: $from, to: $to) {
88+ totalCommitContributions
89+ totalIssueContributions
90+ totalPullRequestContributions
91+ totalPullRequestReviewContributions
92+ }
93+ }
94+}' \
95+ --jq '.data.user.contributionsCollection // empty'
96+}
97+98+while [[ $# -gt 0 ]]; do
99+case "$1" in
100+ --repo)
101+ [[ $# -ge 2 ]] || die "--repo requires owner/repo"
102+ repo="$2"
103+shift 2
104+ ;;
105+ --months)
106+ [[ $# -ge 2 ]] || die "--months requires a positive integer"
107+ months="$2"
108+ [[ "$months" =~ ^[0-9]+$ && "$months" != "0" ]] || die "--months must be a positive integer"
109+shift 2
110+ ;;
111+ --global)
112+ include_global="1"
113+shift
114+ ;;
115+ -h|--help)
116+ usage
117+exit 0
118+ ;;
119+ --)
120+shift
121+break
122+ ;;
123+ -*)
124+ die "unknown option: $1"
125+ ;;
126+*)
127+break
128+ ;;
129+esac
130+done
131+132+[[ $# -gt 0 ]] || {
133+ usage >&2
134+exit 2
135+}
136+137+need gh
138+need jq
139+140+since_ts=$(date_utc_relative_months "$months")
141+now_ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
142+143+for login in "$@"; do
144+ profile=$(gh api "users/${login}" --jq '{login,name,created_at,type}')
145+ display_login=$(jq -r '.login' <<<"$profile")
146+ name=$(jq -r '.name // empty' <<<"$profile")
147+ created_at=$(jq -r '.created_at' <<<"$profile")
148+ type=$(jq -r '.type' <<<"$profile")
149+ created_day=${created_at%%T*}
150+151+ prs=$(count_threads prs "$display_login" "$since_ts")
152+ issues=$(count_threads issues "$display_login" "$since_ts")
153+ commits=$(count_commits "$display_login" "$since_ts")
154+155+if [[ -n "$name" ]]; then
156+printf '%s (@%s, %s, account created %s, %s)\n' \
157+"$name" "$display_login" "$type" "$created_day" "$(rough_age "$created_at")"
158+else
159+printf '@%s (%s, account created %s, %s)\n' \
160+"$display_login" "$type" "$created_day" "$(rough_age "$created_at")"
161+fi
162+printf '%s last %smo: %s PRs, %s issues, %s commits\n' "$repo" "$months" "$prs" "$issues" "$commits"
163+164+if [[ "$include_global" == "1" ]]; then
165+if global_json=$(global_activity "$display_login" "$since_ts" "$now_ts" 2>/dev/null); then
166+if [[ -n "$global_json" ]]; then
167+ global_commits=$(jq -r '.totalCommitContributions' <<<"$global_json")
168+ global_issues=$(jq -r '.totalIssueContributions' <<<"$global_json")
169+ global_prs=$(jq -r '.totalPullRequestContributions' <<<"$global_json")
170+ global_reviews=$(jq -r '.totalPullRequestReviewContributions' <<<"$global_json")
171+printf 'GitHub public last %smo: %s commits, %s PRs, %s issues, %s reviews\n' \
172+"$months" "$global_commits" "$global_prs" "$global_issues" "$global_reviews"
173+else
174+printf 'GitHub public last %smo: unavailable\n' "$months"
175+fi
176+else
177+printf 'GitHub public last %smo: unavailable\n' "$months"
178+fi
179+fi
180+done
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。