Skip to content

Commit 0fbc83c

Browse files
committed
add some log & rename feature for join-issue
1 parent 9fdb114 commit 0fbc83c

File tree

4 files changed

+131
-18
lines changed

4 files changed

+131
-18
lines changed

src/components/scan_join_issues.py

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@
1515
add_user_to_team,
1616
is_user_in_team,
1717
list_open_join_issues,
18+
update_issue_title,
1819
)
1920
from libs.utils import load_simple_yaml
2021

21-
def scan():
22+
def scan(verbose=False):
2223
# Load configuration first
2324
config_path = Path(__file__).parent.parent / "config" / "join-config.yml"
2425
cfg = load_simple_yaml(str(config_path))
@@ -39,44 +40,98 @@ def scan():
3940

4041
teams_cfg = cfg.get("teams") or {}
4142

43+
if verbose:
44+
print(f"扫描仓库: {repo}")
45+
print(f"组织: {org}")
46+
print(f"配置的团队: {list(teams_cfg.keys())}")
47+
print()
48+
4249
issues = list_open_join_issues(token, repo)
4350

51+
if verbose:
52+
print(f"找到 {len(issues)} 个待处理的加入请求\n")
53+
4454
for it in issues:
4555
issue_number = it["number"]
4656
author = it["user"]["login"]
57+
issue_title = it["title"]
58+
59+
if verbose:
60+
print(f"处理 Issue #{issue_number} - 作者: @{author}")
61+
62+
# Replace @<your-username> with actual username in title
63+
if "@<your-username>" in issue_title:
64+
new_title = issue_title.replace("@<your-username>", f"@{author}")
65+
code, _ = update_issue_title(token, repo, issue_number, new_title)
66+
if code in (200, 201):
67+
if verbose:
68+
print(f" ✓ 更新标题: {issue_title}{new_title}")
69+
else:
70+
if verbose:
71+
print(f" ✗ 更新标题失败 (HTTP {code})")
4772

4873
target = get_target_from_labels(it)
4974
if not target or target not in teams_cfg:
75+
if verbose:
76+
print(f" ⊘ 跳过: 未找到有效的目标团队标签 (target={target})\n")
5077
continue
5178

5279
team_cfg = teams_cfg[target]
5380
team_slug = team_cfg.get("team_slug", "") or ""
5481

82+
if verbose:
83+
print(f" 目标团队: {target} (team_slug={team_slug})")
84+
5585
# If not org member yet, remind and keep open
5686
if not is_org_member(token, org, author):
87+
if verbose:
88+
print(f" ⊘ 跳过: @{author} 还不是 @{org} 成员")
5789
if has_label(it, "invited"):
90+
if verbose:
91+
print(f" → 发送提醒评论")
5892
comment(token, repo, issue_number,
5993
f"@{author} 温馨提示:你还未加入 **@{org}**。请在这里接受邀请:\n\nhttps://github.com/orgs/{org}/invitation")
94+
if verbose:
95+
print()
6096
continue
6197

98+
if verbose:
99+
print(f" ✓ @{author} 已是组织成员")
100+
62101
# If needs team, ensure team membership
63102
if team_slug:
64103
if not is_user_in_team(token, org, team_slug, author):
104+
if verbose:
105+
print(f" → 添加到团队 @{org}/{team_slug}")
65106
code, payload = add_user_to_team(token, org, team_slug, author)
66107
if code not in (200, 201):
67108
# Can't add team for some reason; leave a note and continue
109+
if verbose:
110+
print(f" ✗ 添加团队失败 (HTTP {code})")
68111
comment(token, repo, issue_number,
69112
f"@{author} 已检测到你已加入 **@{org}**,但加入 **@{org}/{team_slug}** 仍失败,将稍后重试。\n\n"
70113
f"HTTP {code}\n\n```json\n{json.dumps(payload, ensure_ascii=False, indent=2)}\n```")
114+
if verbose:
115+
print()
71116
continue
117+
if verbose:
118+
print(f" ✓ 成功添加到团队")
119+
else:
120+
if verbose:
121+
print(f" ✓ 已在团队 @{org}/{team_slug} 中")
72122

73123
# Now complete: comment + close
124+
if verbose:
125+
print(f" ✓ 处理完成,关闭 Issue")
74126
if team_slug:
75127
comment(token, repo, issue_number, f"@{author} ✅ 已确认你已加入 **@{org}** 并加入 **@{org}/{team_slug}**,本 Issue 将关闭。")
76128
else:
77129
comment(token, repo, issue_number, f"@{author} ✅ 已确认你已加入 **@{org}**,本 Issue 将关闭。")
78130

79131
close_issue(token, repo, issue_number)
80132

133+
if verbose:
134+
print()
135+
81136
if __name__ == "__main__":
82137
scan()

src/components/task_checker.py

Lines changed: 58 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def get_hours_since_update(issue):
4646
return delta.total_seconds() / 3600
4747

4848

49-
def check_task_timeout(token, repo, issue, config):
49+
def check_task_timeout(token, repo, issue, config, verbose=False):
5050
"""
5151
Check if a task issue has timed out and send reminder if needed.
5252
@@ -55,24 +55,34 @@ def check_task_timeout(token, repo, issue, config):
5555
repo: Repository in "owner/name" format
5656
issue: Issue object from GitHub API
5757
config: Configuration dictionary
58+
verbose: Enable verbose logging
5859
5960
Returns:
6061
True if reminder was sent, False otherwise
6162
"""
6263
# Get priority from labels
6364
priority = get_label_value(issue, config.get("priority_pattern", r"^P([012])$"))
6465
if not priority:
66+
if verbose:
67+
print(f" ⊘ 跳过: 未找到优先级标签")
6568
return False
6669

6770
# Get timeout hours for this priority
6871
timeout_key = f"P{priority}"
6972
timeout_hours = config.get("timeout_hours", {}).get(timeout_key)
7073
if timeout_hours is None:
74+
if verbose:
75+
print(f" ⊘ 跳过: {timeout_key} 未配置超时时间")
7176
return False
7277

7378
# Check if issue has timed out
7479
hours_since_update = get_hours_since_update(issue)
80+
if verbose:
81+
print(f" 优先级: {timeout_key}, 超时阈值: {timeout_hours}h, 距上次更新: {hours_since_update:.1f}h")
82+
7583
if hours_since_update < timeout_hours:
84+
if verbose:
85+
print(f" ⊘ 跳过: 未超时")
7686
return False
7787

7888
# Get assignees to mention
@@ -112,6 +122,8 @@ def check_task_timeout(token, repo, issue, config):
112122
)
113123

114124
# Add comment
125+
if verbose:
126+
print(f" ✓ 发送超时提醒")
115127
comment(token, repo, issue_number, reminder_msg)
116128

117129
# Optional: Add a label to mark as reminded
@@ -122,14 +134,15 @@ def check_task_timeout(token, repo, issue, config):
122134
return True
123135

124136

125-
def scan_repo_tasks(token, repo, config):
137+
def scan_repo_tasks(token, repo, config, verbose=False):
126138
"""
127139
Scan a single repository for task issues that need reminders.
128140
129141
Args:
130142
token: GitHub API token
131143
repo: Repository in "owner/name" format
132144
config: Configuration dictionary
145+
verbose: Enable verbose logging
133146
134147
Returns:
135148
Number of reminders sent
@@ -153,33 +166,45 @@ def scan_repo_tasks(token, repo, config):
153166
print(f"Error searching {repo}: {e}")
154167
return 0
155168

169+
if verbose:
170+
print(f"找到 {len(issues)} 个待检查的任务 Issue\n")
171+
156172
# Filter issues by priority and check for timeouts
157173
priority_filter = config.get("priorities_to_check", ["P0", "P1", "P2"])
158174
priority_pattern = config.get("priority_pattern", r"^P([012])$")
159175

160176
reminders_sent = 0
161177
for issue in issues:
178+
if verbose:
179+
print(f"检查 Issue #{issue['number']}: {issue['title']}")
180+
162181
# Check if issue has one of the target priorities
163182
priority = get_label_value(issue, priority_pattern)
164183
if not priority or f"P{priority}" not in priority_filter:
184+
if verbose:
185+
print(f" ⊘ 跳过: 优先级 P{priority} 不在检查范围 {priority_filter}\n")
165186
continue
166187

167188
# Check if timeout and send reminder
168-
if check_task_timeout(token, repo, issue, config):
189+
if check_task_timeout(token, repo, issue, config, verbose=verbose):
169190
reminders_sent += 1
170-
print(f"Sent reminder for {repo}#{issue['number']}: {issue['title']}")
191+
print(f"✓ 发送提醒 {repo}#{issue['number']}: {issue['title']}")
192+
193+
if verbose:
194+
print()
171195

172196
return reminders_sent
173197

174198

175-
def scan_org_tasks(token, org, config):
199+
def scan_org_tasks(token, org, config, verbose=False):
176200
"""
177201
Scan all repositories in an organization for task issues.
178202
179203
Args:
180204
token: GitHub API token
181205
org: Organization name
182206
config: Configuration dictionary
207+
verbose: Enable verbose logging
183208
184209
Returns:
185210
Number of reminders sent
@@ -191,6 +216,9 @@ def scan_org_tasks(token, org, config):
191216
print(f"Error listing repos for {org}: {e}")
192217
return 0
193218

219+
if verbose:
220+
print(f"组织 {org} 中找到 {len(repos)} 个仓库\n")
221+
194222
# Scan each repository
195223
total_reminders = 0
196224
for repo_obj in repos:
@@ -199,19 +227,27 @@ def scan_org_tasks(token, org, config):
199227
# Check if repo should be excluded
200228
exclude_repos = config.get("exclude_repos", [])
201229
if repo_full_name in exclude_repos or repo_obj["name"] in exclude_repos:
202-
print(f"Skipping excluded repo: {repo_full_name}")
230+
if verbose:
231+
print(f"⊘ 跳过排除的仓库: {repo_full_name}\n")
232+
else:
233+
print(f"Skipping excluded repo: {repo_full_name}")
203234
continue
204235

205-
print(f"Scanning {repo_full_name}...")
206-
reminders = scan_repo_tasks(token, repo_full_name, config)
236+
print(f"扫描仓库: {repo_full_name}")
237+
reminders = scan_repo_tasks(token, repo_full_name, config, verbose=verbose)
207238
total_reminders += reminders
239+
if verbose:
240+
print()
208241

209242
return total_reminders
210243

211244

212-
def check():
245+
def check(verbose=False):
213246
"""
214247
Main function to check tasks and send reminders based on configuration.
248+
249+
Args:
250+
verbose: Enable verbose logging
215251
"""
216252
# Load configuration
217253
config_path = Path(__file__).parent.parent / "config" / "task-checker.yml"
@@ -225,25 +261,32 @@ def check():
225261
# Get scan scope
226262
scan_mode = cfg.get("scan_mode", "repo") # "repo" or "org"
227263

264+
if verbose:
265+
print(f"扫描模式: {scan_mode}")
266+
print(f"任务标签: {cfg.get('task_label', 'Task')}")
267+
print(f"检查优先级: {cfg.get('priorities_to_check', ['P0', 'P1', 'P2'])}")
268+
print(f"超时配置: {cfg.get('timeout_hours', {})}")
269+
print()
270+
228271
if scan_mode == "org":
229272
# Scan entire organization
230273
org = cfg.get("org", "").strip()
231274
if not org:
232275
raise ValueError("Organization (org) must be set in config when scan_mode is 'org'")
233276

234-
print(f"Scanning organization: {org}")
235-
reminders_sent = scan_org_tasks(token, org, cfg)
236-
print(f"\nTotal reminders sent: {reminders_sent}")
277+
print(f"扫描组织: {org}")
278+
reminders_sent = scan_org_tasks(token, org, cfg, verbose=verbose)
279+
print(f"\n总计发送提醒: {reminders_sent}")
237280

238281
elif scan_mode == "repo":
239282
# Scan single repository
240283
repo = cfg.get("repo", "").strip()
241284
if not repo:
242285
raise ValueError("Repository (repo) must be set in config when scan_mode is 'repo'")
243286

244-
print(f"Scanning repository: {repo}")
245-
reminders_sent = scan_repo_tasks(token, repo, cfg)
246-
print(f"\nTotal reminders sent: {reminders_sent}")
287+
print(f"扫描仓库: {repo}")
288+
reminders_sent = scan_repo_tasks(token, repo, cfg, verbose=verbose)
289+
print(f"\n总计发送提醒: {reminders_sent}")
247290

248291
else:
249292
raise ValueError(f"Invalid scan_mode: {scan_mode}. Must be 'repo' or 'org'")

src/libs/github_client.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,21 @@ def close_issue(token, repo, issue_number):
6565
"""
6666
gh("PATCH", f"repos/{repo}/issues/{issue_number}", token, {"state": "closed"})
6767

68+
def update_issue_title(token, repo, issue_number, new_title):
69+
"""
70+
Update the title of a GitHub issue.
71+
72+
Args:
73+
token: GitHub API token
74+
repo: Repository in "owner/name" format
75+
issue_number: Issue number
76+
new_title: New title for the issue
77+
78+
Returns:
79+
Tuple of (status_code, response_payload)
80+
"""
81+
return gh("PATCH", f"repos/{repo}/issues/{issue_number}", token, {"title": new_title})
82+
6883
def has_label(issue, name):
6984
"""
7085
Check if an issue has a specific label.

src/main.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def main():
7373
print("\n[1/2] Running Join Issues Scanner...")
7474
print("-" * 60)
7575
try:
76-
scan_join_issues()
76+
scan_join_issues(verbose=args.verbose)
7777
print("✓ Join Issues Scanner completed successfully")
7878
except Exception as e:
7979
error_msg = f"✗ Join Issues Scanner failed: {e}"
@@ -87,7 +87,7 @@ def main():
8787
print("\n[2/2] Running Task Checker...")
8888
print("-" * 60)
8989
try:
90-
check_tasks()
90+
check_tasks(verbose=args.verbose)
9191
print("✓ Task Checker completed successfully")
9292
except Exception as e:
9393
error_msg = f"✗ Task Checker failed: {e}"

0 commit comments

Comments
 (0)