1
0
mirror of https://github.com/openSUSE/osc.git synced 2026-02-06 04:45:57 +01:00

Merge pull request #1744 from dmach/osc-fork-project

Improve 'osc fork' command to support also forking projects managed in git
This commit is contained in:
2025-03-19 20:03:28 +01:00
committed by GitHub
2 changed files with 59 additions and 15 deletions

View File

@@ -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,9 +28,20 @@ class ForkCommand(osc.commandline.OscCommand):
self.add_argument(
"package",
nargs="?",
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):
@@ -39,18 +50,31 @@ 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
is_package = args.package is not None
# 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 <scmsync> element must be set in the package meta)"
)
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 <scmsync> 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 <scmsync> 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
@@ -95,13 +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}")
status = obs_api.Package.cmd_fork(args.apiurl, args.project, args.package, scmsync=fork_scmsync)
target_project = status.data["targetproject"]
target_package = status.data["targetpackage"]
# 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 if is_package else "_project",
scmsync=fork_scmsync,
target_project=args.target_project,
target_package=args.target_package if is_package else None,
)
# 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

View File

@@ -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)