feat: Add GitHub issue selection and auto-close functionality

- Implement `get_selected_issue_ids()` to allow users to select and close GitHub issues during commit
- Add support for automatically appending "Closes #IssueNumber" to commit messages
- Enhance commit workflow with dynamic issue tracking and resolution
- Integrate new GitHub API functions to retrieve user's assigned open issues
This commit is contained in:
long2ice 2025-03-10 13:15:03 +08:00
parent 99b55db6ff
commit e786d16bbb
2 changed files with 100 additions and 8 deletions

View File

@ -12,7 +12,14 @@ from lib.ide_service import IDEService
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
from common_util import assert_exit # noqa: E402
from git_api import get_issue_info, subprocess_check_output, subprocess_run
from git_api import (
get_git_username,
get_github_repo,
get_github_repo_issues,
get_issue_info,
subprocess_check_output,
subprocess_run,
)
diff_too_large_message_en = (
"Commit failed. The modified content is too long "
@ -410,17 +417,45 @@ def push_changes():
print(f"Push failed: {str(e)}", end="\n\n", file=sys.stderr, flush=True)
return False
except Exception as e:
print(f"An unexpected error occurred: {str(e)}", end="\n\n", file=sys.stderr, flush=True)
print(
f"An unexpected error occurred: {str(e)}",
end="\n\n",
file=sys.stderr,
flush=True,
)
return False
def get_selected_issue_ids():
"""
获取用户选中的issue id
"""
name = get_git_username()
if not name:
return []
owner_repo = get_github_repo()
issues = get_github_repo_issues(owner_repo, assignee=name, state="open")
if issues:
checkbox = Checkbox(
[f"#{issue['number']}: {issue['title']}" for issue in issues],
title="Select the issues you want to close",
)
checkbox.render()
return [issues[idx]["number"] for idx in checkbox.selections]
return []
def main():
global language
try:
print("Let's follow the steps below.\n\n")
# Ensure enough command line arguments are provided
if len(sys.argv) < 2:
print("Usage: python script.py <user_input> <language>", file=sys.stderr, flush=True)
print(
"Usage: python script.py <user_input> <language>",
file=sys.stderr,
flush=True,
)
sys.exit(-1)
user_input = sys.argv[1]
@ -472,7 +507,11 @@ def main():
.replace("No specific issue to close", "")
.replace("No specific issue mentioned.", "")
)
# add closes #IssueNumber in commit message from issues from user selected
issue_ids = get_selected_issue_ids()
if issue_ids:
for issue_id in issue_ids:
commit_message["content"] += f"\n\nCloses #{issue_id}"
commit_result = display_commit_message_and_commit(commit_message["content"])
if not commit_result:
print("Commit aborted.", flush=True)

View File

@ -203,7 +203,10 @@ def check_git_installed():
"""
try:
subprocess_run(
["git", "--version"], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE
["git", "--version"],
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
return True
except subprocess.CalledProcessError:
@ -304,7 +307,8 @@ def get_parent_branch():
try:
# 使用git命令获取当前分支的父分支引用
result = subprocess_check_output(
["git", "rev-parse", "--abbrev-ref", f"{current_branch}@{1}"], stderr=subprocess.STDOUT
["git", "rev-parse", "--abbrev-ref", f"{current_branch}@{1}"],
stderr=subprocess.STDOUT,
).strip()
# 将结果从bytes转换为str
parent_branch_ref = result.decode("utf-8")
@ -394,7 +398,10 @@ def get_commit_messages(base_branch):
def create_pull_request(title, body, head, base, repo_name):
url = f"{GITHUB_API_URL}/repos/{repo_name}/pulls"
print("url:", url, end="\n\n")
headers = {"Authorization": f"token {GITHUB_ACCESS_TOKEN}", "Content-Type": "application/json"}
headers = {
"Authorization": f"token {GITHUB_ACCESS_TOKEN}",
"Content-Type": "application/json",
}
payload = {"title": title, "body": body, "head": head, "base": base}
response = requests.post(url, headers=headers, data=json.dumps(payload))
if response.status_code == 201:
@ -479,7 +486,10 @@ def get_recently_pr(repo):
def update_pr(pr_number, title, body, repo_name):
url = f"{GITHUB_API_URL}/repos/{repo_name}/pulls/{pr_number}"
headers = {"Authorization": f"token {GITHUB_ACCESS_TOKEN}", "Content-Type": "application/json"}
headers = {
"Authorization": f"token {GITHUB_ACCESS_TOKEN}",
"Content-Type": "application/json",
}
payload = {"title": title, "body": body}
response = requests.patch(url, headers=headers, data=json.dumps(payload))
@ -526,3 +536,46 @@ def save_last_base_branch(base_branch=None):
base_branch = get_current_branch()
project_config_path = os.path.join(os.getcwd(), ".chat", ".workflow_config.json")
save_config_item(project_config_path, "last_base_branch", base_branch)
def get_git_username():
return subprocess_check_output(["git", "config", "--get", "user.name"]).decode("utf-8").strip()
def get_github_repo_issues(
owner_repo,
milestone=None,
state=None,
assignee=None,
creator=None,
mentioned=None,
labels=None,
sort=None,
direction=None,
since=None,
per_page=None,
page=None,
):
url = f"{GITHUB_API_URL}/repos/{owner_repo}/issues"
headers = {
"Authorization": f"token {GITHUB_ACCESS_TOKEN}",
"Accept": "application/vnd.github.v3+json",
}
params = {
"milestone": milestone,
"state": state,
"assignee": assignee,
"creator": creator,
"mentioned": mentioned,
"labels": labels,
"sort": sort,
"direction": direction,
"since": since,
"per_page": per_page,
"page": page,
}
response = requests.get(url, headers=headers, params=params)
if response.status_code == 200:
return response.json()
else:
return None