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:
parent
99b55db6ff
commit
e786d16bbb
@ -12,7 +12,14 @@ from lib.ide_service import IDEService
|
|||||||
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
|
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
|
||||||
|
|
||||||
from common_util import assert_exit # noqa: E402
|
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 = (
|
diff_too_large_message_en = (
|
||||||
"Commit failed. The modified content is too long "
|
"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)
|
print(f"Push failed: {str(e)}", end="\n\n", file=sys.stderr, flush=True)
|
||||||
return False
|
return False
|
||||||
except Exception as e:
|
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
|
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():
|
def main():
|
||||||
global language
|
global language
|
||||||
try:
|
try:
|
||||||
print("Let's follow the steps below.\n\n")
|
print("Let's follow the steps below.\n\n")
|
||||||
# Ensure enough command line arguments are provided
|
# Ensure enough command line arguments are provided
|
||||||
if len(sys.argv) < 2:
|
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)
|
sys.exit(-1)
|
||||||
|
|
||||||
user_input = sys.argv[1]
|
user_input = sys.argv[1]
|
||||||
@ -472,7 +507,11 @@ def main():
|
|||||||
.replace("No specific issue to close", "")
|
.replace("No specific issue to close", "")
|
||||||
.replace("No specific issue mentioned.", "")
|
.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"])
|
commit_result = display_commit_message_and_commit(commit_message["content"])
|
||||||
if not commit_result:
|
if not commit_result:
|
||||||
print("Commit aborted.", flush=True)
|
print("Commit aborted.", flush=True)
|
||||||
|
@ -203,7 +203,10 @@ def check_git_installed():
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
subprocess_run(
|
subprocess_run(
|
||||||
["git", "--version"], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
["git", "--version"],
|
||||||
|
check=True,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
)
|
)
|
||||||
return True
|
return True
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
@ -304,7 +307,8 @@ def get_parent_branch():
|
|||||||
try:
|
try:
|
||||||
# 使用git命令获取当前分支的父分支引用
|
# 使用git命令获取当前分支的父分支引用
|
||||||
result = subprocess_check_output(
|
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()
|
).strip()
|
||||||
# 将结果从bytes转换为str
|
# 将结果从bytes转换为str
|
||||||
parent_branch_ref = result.decode("utf-8")
|
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):
|
def create_pull_request(title, body, head, base, repo_name):
|
||||||
url = f"{GITHUB_API_URL}/repos/{repo_name}/pulls"
|
url = f"{GITHUB_API_URL}/repos/{repo_name}/pulls"
|
||||||
print("url:", url, end="\n\n")
|
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}
|
payload = {"title": title, "body": body, "head": head, "base": base}
|
||||||
response = requests.post(url, headers=headers, data=json.dumps(payload))
|
response = requests.post(url, headers=headers, data=json.dumps(payload))
|
||||||
if response.status_code == 201:
|
if response.status_code == 201:
|
||||||
@ -479,7 +486,10 @@ def get_recently_pr(repo):
|
|||||||
|
|
||||||
def update_pr(pr_number, title, body, repo_name):
|
def update_pr(pr_number, title, body, repo_name):
|
||||||
url = f"{GITHUB_API_URL}/repos/{repo_name}/pulls/{pr_number}"
|
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}
|
payload = {"title": title, "body": body}
|
||||||
response = requests.patch(url, headers=headers, data=json.dumps(payload))
|
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()
|
base_branch = get_current_branch()
|
||||||
project_config_path = os.path.join(os.getcwd(), ".chat", ".workflow_config.json")
|
project_config_path = os.path.join(os.getcwd(), ".chat", ".workflow_config.json")
|
||||||
save_config_item(project_config_path, "last_base_branch", base_branch)
|
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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user