This initializes a very simple AGit helper script. Usage: ``` agit create ``` or ``` agit c ``` To create a new AGit Pr. Integrate Pulling from an AGit remote. Gitea doesn't expose an AGit endpoint in the api, or the `tea` cli. This makes pulling not feasible, since there is no robust way to query the AGit topic, which is the ref that need to be pulled. One possible solution currently could be scraping the gitea instructions for forking a pull request on an AGit PR.
206 lines
5.2 KiB
Python
206 lines
5.2 KiB
Python
import argparse
|
|
import subprocess
|
|
import sys
|
|
|
|
# push origin HEAD:refs/for/main
|
|
# HEAD: The target branch
|
|
# origin: The target repository (not a fork!)
|
|
# HEAD: The local branch containing the changes you are proposing
|
|
TARGET_REMOTE_REPOSITORY = "origin"
|
|
DEFAULT_TARGET_BRANCH = "main"
|
|
|
|
|
|
def run_git_command(command: list) -> tuple[int, str, str]:
|
|
"""Run a git command and return exit code, stdout, and stderr."""
|
|
try:
|
|
result = subprocess.run(command, capture_output=True, text=True, check=False)
|
|
return result.returncode, result.stdout.strip(), result.stderr.strip()
|
|
except Exception as e:
|
|
return 1, "", str(e)
|
|
|
|
|
|
def get_latest_commit_info() -> tuple[str, str]:
|
|
"""Get the title and body of the latest commit."""
|
|
exit_code, commit_msg, error = run_git_command(
|
|
["git", "log", "-1", "--pretty=format:%B"]
|
|
)
|
|
|
|
if exit_code != 0:
|
|
print(f"Error getting commit info: {error}")
|
|
sys.exit(1)
|
|
|
|
lines = commit_msg.strip().split("\n")
|
|
title = lines[0].strip() if lines else ""
|
|
|
|
body_lines = []
|
|
for line in lines[1:]:
|
|
if body_lines or line.strip():
|
|
body_lines.append(line)
|
|
|
|
body = "\n".join(body_lines).strip()
|
|
|
|
return title, body
|
|
|
|
|
|
def create_agit_push(
|
|
remote: str = "origin",
|
|
branch: str = "main",
|
|
topic: str | None = None,
|
|
title: str | None = None,
|
|
description: str | None = None,
|
|
force_push: bool = False,
|
|
local_branch: str = "HEAD",
|
|
) -> None:
|
|
if topic is None or title is None:
|
|
commit_title, _ = get_latest_commit_info()
|
|
|
|
if topic is None:
|
|
topic = commit_title
|
|
if title is None:
|
|
title = commit_title
|
|
|
|
refspec = f"{local_branch}:refs/for/{branch}"
|
|
push_cmd = ["git", "push", remote, refspec]
|
|
|
|
push_cmd.extend(["-o", f"topic={topic}"])
|
|
|
|
if title:
|
|
push_cmd.extend(["-o", f"title={title}"])
|
|
|
|
if description:
|
|
escaped_desc = description.replace('"', '\\"')
|
|
push_cmd.extend(["-o", f"description={escaped_desc}"])
|
|
|
|
if force_push:
|
|
push_cmd.extend(["-o", "force-push"])
|
|
|
|
if description:
|
|
print(
|
|
f" Description: {description[:50]}..."
|
|
if len(description) > 50
|
|
else f" Description: {description}"
|
|
)
|
|
print()
|
|
|
|
exit_code, stdout, stderr = run_git_command(push_cmd)
|
|
|
|
if stdout:
|
|
print(stdout)
|
|
if stderr:
|
|
print(stderr, file=sys.stderr)
|
|
|
|
if exit_code != 0:
|
|
print("\nPush failed!")
|
|
sys.exit(exit_code)
|
|
else:
|
|
print("\nPush successful!")
|
|
|
|
|
|
def cmd_create(args: argparse.Namespace) -> None:
|
|
"""Handle the create subcommand."""
|
|
create_agit_push(
|
|
remote=args.remote,
|
|
branch=args.branch,
|
|
topic=args.topic,
|
|
title=args.title,
|
|
description=args.description,
|
|
force_push=args.force,
|
|
local_branch=args.local_branch,
|
|
)
|
|
|
|
|
|
def create_parser() -> argparse.ArgumentParser:
|
|
parser = argparse.ArgumentParser(
|
|
prog="agit",
|
|
description="AGit utility for creating and pulling PRs",
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
epilog=f"""
|
|
The defaults that are assumed are:
|
|
TARGET_REMOTE_REPOSITORY = {TARGET_REMOTE_REPOSITORY}
|
|
DEFAULT_TARGET_BRANCH = {DEFAULT_TARGET_BRANCH}
|
|
|
|
Examples:
|
|
$ agit create
|
|
Will create an AGit Pr with the latest commit message title as it's topic.
|
|
|
|
$ agit create --topic "my-feature"
|
|
Set a custom topic.
|
|
|
|
$ agit create --force
|
|
Force push to a certain topic
|
|
""",
|
|
)
|
|
|
|
subparsers = parser.add_subparsers(dest="subcommand", help="Commands")
|
|
|
|
create_parser = subparsers.add_parser(
|
|
"create",
|
|
aliases=["c"],
|
|
help="Create an AGit PR",
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
epilog="""
|
|
Examples:
|
|
$ agit create
|
|
Will create an AGit Pr with the latest commit message title as it's topic.
|
|
|
|
$ agit create --topic "my-feature"
|
|
Set a custom topic.
|
|
|
|
$ agit create --force
|
|
Force push to a certain topic
|
|
""",
|
|
)
|
|
|
|
create_parser.add_argument(
|
|
"-r",
|
|
"--remote",
|
|
default=TARGET_REMOTE_REPOSITORY,
|
|
help=f"Git remote to push to (default: {TARGET_REMOTE_REPOSITORY})",
|
|
)
|
|
|
|
create_parser.add_argument(
|
|
"-b",
|
|
"--branch",
|
|
default=DEFAULT_TARGET_BRANCH,
|
|
help=f"Target branch for the PR (default: {DEFAULT_TARGET_BRANCH})",
|
|
)
|
|
|
|
create_parser.add_argument(
|
|
"-l",
|
|
"--local-branch",
|
|
default="HEAD",
|
|
help="Local branch to push (default: HEAD)",
|
|
)
|
|
|
|
create_parser.add_argument(
|
|
"-t", "--topic", help="Set PR topic (default: last commit title)"
|
|
)
|
|
|
|
create_parser.add_argument(
|
|
"--title", help="Set the PR title (default: last commit title)"
|
|
)
|
|
|
|
create_parser.add_argument(
|
|
"--description", help="Override the PR description (default: commit body)"
|
|
)
|
|
|
|
create_parser.add_argument(
|
|
"-f", "--force", action="store_true", help="Force push the changes"
|
|
)
|
|
|
|
create_parser.set_defaults(func=cmd_create)
|
|
return parser
|
|
|
|
|
|
def main() -> None:
|
|
parser = create_parser()
|
|
args = parser.parse_args()
|
|
if args.subcommand is None:
|
|
parser.print_help()
|
|
sys.exit(0)
|
|
args.func(args)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|