Skip to content

Commit ea1d9c7

Browse files
committed
feat: Add GitHub repository API support for work reports
- Add GitHub repository detection and API functions - Implement repo_issues and repo_commits for GitHub repos - Update work_report command to support both GitHub and GitLab
1 parent 345d121 commit ea1d9c7

2 files changed

Lines changed: 152 additions & 7 deletions

File tree

community/github/git_api.py

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,12 @@ def get_current_repo():
4141
if not current_repo_dir:
4242
selected_data = IDEService().get_selected_range().dict()
4343
current_file = selected_data.get("abspath", None)
44+
4445
if not current_file:
4546
return None
4647
current_dir = os.path.dirname(current_file)
48+
if not os.path.exists(current_dir):
49+
current_dir = os.getcwd()
4750
try:
4851
# 获取仓库根目录
4952
current_repo_dir = (
@@ -585,3 +588,134 @@ def get_github_repo_issues(
585588
return response.json()
586589
else:
587590
return None
591+
592+
def get_repo_issues(
593+
repo: str,
594+
assignee_username: str = None,
595+
state: str = "open",
596+
created_after=None,
597+
created_before=None,
598+
):
599+
"""
600+
Get issues from a GitHub repository with optional filtering.
601+
602+
Args:
603+
repo (str): Repository name in the format 'owner/repo'
604+
assignee_username (str, optional): Filter issues by assignee username.
605+
Special values: '*' (any assigned), 'none' (unassigned)
606+
state (str, optional): Filter issues by state ('open', 'closed', 'all'). Default is 'open'.
607+
created_after (str, optional): ISO 8601 formatted timestamp to filter issues created after this date
608+
created_before (str, optional): ISO 8601 formatted timestamp to filter issues created before this date
609+
610+
Returns:
611+
list: List of issue objects from the GitHub API
612+
"""
613+
url = f"{GITHUB_API_URL}/repos/{repo}/issues"
614+
615+
params = {
616+
"state": state,
617+
}
618+
619+
# 处理assignee参数
620+
if assignee_username is not None:
621+
# 如果提供了assignee_username,则使用它
622+
params["assignee"] = assignee_username
623+
624+
# GitHub uses 'since' parameter for created_after
625+
if created_after:
626+
params["since"] = created_after
627+
628+
headers = {
629+
"Authorization": f"token {GITHUB_ACCESS_TOKEN}",
630+
"Accept": "application/vnd.github.v3+json",
631+
}
632+
633+
response = requests.get(url, headers=headers, params=params)
634+
635+
if response.status_code == 200:
636+
issues = response.json()
637+
638+
# Filter by created_before if specified
639+
if created_before:
640+
issues = [issue for issue in issues if issue["created_at"][:len(created_before)] <= created_before]
641+
642+
return issues
643+
else:
644+
print(f"Failed to get issues: {response.status_code}", file=sys.stderr)
645+
print(response.text, file=sys.stderr)
646+
return []
647+
648+
649+
def get_commit_author():
650+
cmd = ["git", "config", "user.email"]
651+
return subprocess_check_output(cmd).decode("utf-8").strip()
652+
653+
def get_repo_commits(repo: str, author=None, since=None, until=None):
654+
"""
655+
Get commits from a GitHub repository with optional filtering.
656+
657+
Args:
658+
repo (str): Repository name in the format 'owner/repo'
659+
author (str, optional): Filter commits by author
660+
since (str, optional): ISO 8601 formatted timestamp to filter commits after this date
661+
until (str, optional): ISO 8601 formatted timestamp to filter commits before this date
662+
663+
Returns:
664+
list: List of commit objects from the GitHub API
665+
"""
666+
url = f"{GITHUB_API_URL}/repos/{repo}/commits"
667+
668+
params = {}
669+
if author:
670+
params["author"] = author
671+
if since:
672+
params["since"] = since
673+
if until:
674+
params["until"] = until
675+
676+
headers = {
677+
"Authorization": f"token {GITHUB_ACCESS_TOKEN}",
678+
"Accept": "application/vnd.github.v3+json",
679+
}
680+
681+
response = requests.get(url, headers=headers, params=params)
682+
683+
if response.status_code == 200:
684+
return response.json()
685+
else:
686+
print(f"Failed to get commits: {response.status_code}")
687+
print(response.text)
688+
return None
689+
690+
def is_github_repo():
691+
"""
692+
Check if the current repository is a GitHub repository.
693+
694+
Tries to determine if the current git repository is hosted on GitHub by
695+
examining the remote URL.
696+
697+
Returns:
698+
bool: True if the repository is hosted on GitHub, False otherwise.
699+
"""
700+
try:
701+
# 使用git命令获取当前仓库的URL
702+
result = subprocess_check_output(
703+
["git", "remote", "get-url", "origin"], stderr=subprocess.STDOUT
704+
).strip()
705+
706+
# 将结果从bytes转换为str
707+
repo_url = result.decode("utf-8")
708+
709+
# 检查URL是否包含github.com
710+
is_github = "github.com" in repo_url.lower()
711+
712+
IDEService().ide_logging("debug", f"Repository is GitHub: {is_github}")
713+
return is_github
714+
except subprocess.CalledProcessError as e:
715+
print(e, flush=True)
716+
# 如果发生错误,打印错误信息
717+
return None
718+
except FileNotFoundError:
719+
# 如果未找到git命令,可能是没有安装git或者不在PATH中
720+
print("==> File not found...", flush=True)
721+
return None

community/work_report/command.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,24 @@
33

44
from devchat.llm import chat, chat_json
55

6-
from community.gitlab.git_api import (
7-
get_commit_author,
8-
get_repo,
9-
get_repo_commits,
10-
get_repo_issues,
11-
get_username,
12-
)
6+
from community.github.git_api import is_github_repo
7+
8+
if is_github_repo():
9+
from community.github.git_api import (
10+
get_commit_author,
11+
get_github_repo as get_repo,
12+
get_repo_commits,
13+
get_repo_issues,
14+
get_github_username as get_username,
15+
)
16+
else:
17+
from community.gitlab.git_api import (
18+
get_commit_author,
19+
get_repo,
20+
get_repo_commits,
21+
get_repo_issues,
22+
get_username,
23+
)
1324
from lib.workflow.decorators import check_input
1425

1526

0 commit comments

Comments
 (0)