From 989121b271ed3519a7974bb977ed00a74dd42e62 Mon Sep 17 00:00:00 2001 From: Daniel Mach Date: Tue, 18 Mar 2025 14:49:14 +0100 Subject: [PATCH 1/3] Extend 'osc fork' command with '--target-project' and '--target-package' options --- osc/commands/fork.py | 19 ++++++++++++++++++- osc/obs_api/package.py | 6 ++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/osc/commands/fork.py b/osc/commands/fork.py index 4cd9d2b9..c7d3e1a8 100644 --- a/osc/commands/fork.py +++ b/osc/commands/fork.py @@ -31,6 +31,16 @@ class ForkCommand(osc.commandline.OscCommand): help="Name of the package", ) + self.add_argument( + "--target-project", + help="Name of the target project (defaults to home:$user:branches)", + ) + + self.add_argument( + "--target-package", + help="Name of the package (defaults to $package)", + ) + self.add_argument_new_repo_name() def run(self, args): @@ -97,7 +107,14 @@ class ForkCommand(osc.commandline.OscCommand): print() print(f"Forking OBS package {args.project}/{args.package} ...") print(f" * OBS apiurl: {args.apiurl}") - status = obs_api.Package.cmd_fork(args.apiurl, args.project, args.package, scmsync=fork_scmsync) + status = obs_api.Package.cmd_fork( + args.apiurl, + args.project, + args.package, + scmsync=fork_scmsync, + target_project=args.target_project, + target_package=args.target_package, + ) target_project = status.data["targetproject"] target_package = status.data["targetpackage"] # XXX: the current OBS API is not ideal; we don't get any info whether the new package exists already; 404 would be probably nicer diff --git a/osc/obs_api/package.py b/osc/obs_api/package.py index 6a9d5325..5cc085e3 100644 --- a/osc/obs_api/package.py +++ b/osc/obs_api/package.py @@ -96,6 +96,8 @@ class Package(XmlModel): package: str, *, scmsync: str, + target_project: Optional[str] = None, + target_package: Optional[str] = None, ): """ POST /source/{project}/{package}?cmd=fork&scmsync={scmsync} @@ -105,12 +107,16 @@ class Package(XmlModel): :param project: Project name. :param package: Package name. :param scmsync: Checkout Git URL. Example: https://src.example.com/owner/repo#branch + :param target_project: Target project name (defaults to home:$user:branches) + :param target_package: Target package name (defaults to $package) """ url_path = ["source", project, package] url_query = { "cmd": "fork", "scmsync": scmsync, + "target_project": target_project, + "target_package": target_package, } response = cls.xml_request("POST", apiurl, url_path, url_query) return Status.from_file(response, apiurl=apiurl) From 27852f84c1a1baffeacd4ebbea4ba03af91a7053 Mon Sep 17 00:00:00 2001 From: Daniel Mach Date: Tue, 18 Mar 2025 14:49:46 +0100 Subject: [PATCH 2/3] Remove superfluous setting of apiurl from 'osc fork' --- osc/commands/fork.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/osc/commands/fork.py b/osc/commands/fork.py index c7d3e1a8..cb9ea78c 100644 --- a/osc/commands/fork.py +++ b/osc/commands/fork.py @@ -49,9 +49,6 @@ class ForkCommand(osc.commandline.OscCommand): from osc import obs_api from osc.output import tty - osc_conf.get_config(override_apiurl=args.apiurl) - args.apiurl = osc_conf.config.apiurl - # get the package meta from the OBS API first package = obs_api.Package.from_api(args.apiurl, args.project, args.package) if not package.scmsync: From d16197b6c5d6d6d5dd6e5e82dd849a17dea41683 Mon Sep 17 00:00:00 2001 From: Daniel Mach Date: Tue, 18 Mar 2025 15:05:02 +0100 Subject: [PATCH 3/3] Improve 'osc fork' command to support also forking projects managed in git --- osc/commands/fork.py | 52 ++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/osc/commands/fork.py b/osc/commands/fork.py index cb9ea78c..1a1e3030 100644 --- a/osc/commands/fork.py +++ b/osc/commands/fork.py @@ -7,7 +7,7 @@ import osc.commandline_git class ForkCommand(osc.commandline.OscCommand): """ - Fork a package with sources managed in Gitea + Fork a project or a package with sources managed in Gitea """ name = "fork" @@ -28,6 +28,7 @@ class ForkCommand(osc.commandline.OscCommand): self.add_argument( "package", + nargs="?", help="Name of the package", ) @@ -49,15 +50,31 @@ class ForkCommand(osc.commandline.OscCommand): from osc import obs_api from osc.output import tty - # get the package meta from the OBS API first - package = obs_api.Package.from_api(args.apiurl, args.project, args.package) - if not package.scmsync: - raise RuntimeError( - "Forking is possible only with packages managed in Git (the element must be set in the package meta)" - ) + is_package = args.package is not None + + if not is_package and args.target_package: + self.parser.error("The '--target-package' option requires the 'package' argument to be set") + + if is_package: + # get the package meta from the OBS API first + package = obs_api.Package.from_api(args.apiurl, args.project, args.package) + if not package.scmsync: + raise RuntimeError( + "Forking is possible only with packages managed in Git (the element must be set in the package meta)" + ) + else: + # get the project meta from the OBS API first + project = obs_api.Project.from_api(args.apiurl, args.project) + if not project.scmsync: + raise RuntimeError( + "Forking is possible only with projects managed in Git (the element must be set in the project meta)" + ) # parse gitea url, owner, repo and branch from the scmsync url - parsed_scmsync_url = urllib.parse.urlparse(package.scmsync, scheme="https") + if is_package: + parsed_scmsync_url = urllib.parse.urlparse(package.scmsync, scheme="https") + else: + parsed_scmsync_url = urllib.parse.urlparse(project.scmsync, scheme="https") url = urllib.parse.urlunparse((parsed_scmsync_url.scheme, parsed_scmsync_url.netloc, "", "", "", "")) owner, repo = parsed_scmsync_url.path.strip("/").split("/") branch = parsed_scmsync_url.fragment or None @@ -102,20 +119,27 @@ class ForkCommand(osc.commandline.OscCommand): ) print() - print(f"Forking OBS package {args.project}/{args.package} ...") + if is_package: + print(f"Forking OBS package {args.project}/{args.package} ...") + else: + print(f"Forking OBS project {args.project} ...") print(f" * OBS apiurl: {args.apiurl}") + # we use a single API endpoint for forking both projects and packages (project requires setting package to "_project") status = obs_api.Package.cmd_fork( args.apiurl, args.project, - args.package, + args.package if is_package else "_project", scmsync=fork_scmsync, target_project=args.target_project, - target_package=args.target_package, + target_package=args.target_package if is_package else None, ) - target_project = status.data["targetproject"] - target_package = status.data["targetpackage"] # XXX: the current OBS API is not ideal; we don't get any info whether the new package exists already; 404 would be probably nicer - print(f" * Fork created: {target_project}/{target_package}") + target_project = status.data["targetproject"] + if is_package: + target_package = status.data["targetpackage"] + print(f" * Fork created: {target_project}/{target_package}") + else: + print(f" * Fork created: {target_project}") print(f" * scmsync URL: {fork_scmsync}") # check if the scmsync branch exists in the forked repo