1
0
mirror of https://github.com/openSUSE/osc.git synced 2025-11-03 04:52:16 +01:00

Change 'git-obs' to use owner/repo[#pull] arguments consistently

This commit is contained in:
2025-01-15 17:01:47 +01:00
parent 99dcb4e10a
commit e23c566b0d
11 changed files with 172 additions and 63 deletions

View File

@@ -3,8 +3,8 @@ Feature: `git-obs pr` command
Background:
Given I set working directory to "{context.osc.temp}"
And I execute git-obs with args "repo fork pool test-GitPkgA"
And I execute git-obs with args "repo clone Admin test-GitPkgA --no-ssh-strict-host-key-checking"
And I execute git-obs with args "repo fork pool/test-GitPkgA"
And I execute git-obs with args "repo clone Admin/test-GitPkgA --no-ssh-strict-host-key-checking"
And I set working directory to "{context.osc.temp}/test-GitPkgA"
And I execute "sed -i 's@^\(Version.*\)@\1.1@' *.spec"
And I execute "git commit -m 'Change version' -a"
@@ -14,7 +14,7 @@ Background:
@destructive
Scenario: List pull requests
When I execute git-obs with args "pr list pool test-GitPkgA"
When I execute git-obs with args "pr list pool/test-GitPkgA"
Then the exit code is 0
And stdout matches
"""

View File

@@ -7,7 +7,7 @@ Background:
@destructive
Scenario: Clone a git repo
When I execute git-obs with args "repo clone pool test-GitPkgA --no-ssh-strict-host-key-checking"
When I execute git-obs with args "repo clone pool/test-GitPkgA --no-ssh-strict-host-key-checking"
Then the exit code is 0
And stdout is
"""
@@ -20,5 +20,8 @@ Scenario: Clone a git repo
* URL: http://localhost:{context.podman.container.ports[gitea_http]}
* User: Admin
Cloning git repo pool/test-GitPkgA ...
Cloning into 'test-GitPkgA'...
Total cloned repos: 1
"""

View File

@@ -7,7 +7,7 @@ Background:
@destructive
Scenario: Fork a git repo
When I execute git-obs with args "repo fork pool test-GitPkgA"
When I execute git-obs with args "repo fork pool/test-GitPkgA"
Then the exit code is 0
And stdout is
"""
@@ -22,12 +22,14 @@ Scenario: Fork a git repo
Forking git repo pool/test-GitPkgA ...
* Fork created: Admin/test-GitPkgA
Total forked repos: 1
"""
@destructive
Scenario: Fork a git repo twice under different names
When I execute git-obs with args "repo fork pool test-GitPkgA"
When I execute git-obs with args "repo fork pool/test-GitPkgA"
Then the exit code is 0
And stdout is
"""
@@ -42,8 +44,10 @@ Scenario: Fork a git repo twice under different names
Forking git repo pool/test-GitPkgA ...
* Fork created: Admin/test-GitPkgA
Total forked repos: 1
"""
When I execute git-obs with args "repo fork pool test-GitPkgA --new-repo-name=new-package"
When I execute git-obs with args "repo fork pool/test-GitPkgA --new-repo-name=new-package"
Then the exit code is 0
And stdout is
"""
@@ -59,12 +63,14 @@ Scenario: Fork a git repo twice under different names
Forking git repo pool/test-GitPkgA ...
* Fork already exists: Admin/test-GitPkgA
* WARNING: Using an existing fork with a different name than requested
Total forked repos: 1
"""
@destructive
Scenario: Fork a git repo from pool and fork someone else's fork of the same repo
When I execute git-obs with args "repo fork pool test-GitPkgA"
When I execute git-obs with args "repo fork pool/test-GitPkgA"
Then the exit code is 0
And stdout is
"""
@@ -79,8 +85,10 @@ Scenario: Fork a git repo from pool and fork someone else's fork of the same rep
Forking git repo pool/test-GitPkgA ...
* Fork created: Admin/test-GitPkgA
Total forked repos: 1
"""
When I execute git-obs with args "repo fork -G alice pool test-GitPkgA --new-repo-name=test-GitPkgA-alice"
When I execute git-obs with args "repo fork -G alice pool/test-GitPkgA --new-repo-name=test-GitPkgA-alice"
Then the exit code is 0
And stdout is
"""
@@ -95,9 +103,11 @@ Scenario: Fork a git repo from pool and fork someone else's fork of the same rep
Forking git repo pool/test-GitPkgA ...
* Fork created: Alice/test-GitPkgA-alice
Total forked repos: 1
"""
# this succeeds with 202 and the requested fork is NOT created
When I execute git-obs with args "repo fork Alice test-GitPkgA-alice"
When I execute git-obs with args "repo fork Alice/test-GitPkgA-alice"
Then the exit code is 0
And stdout is
"""
@@ -112,6 +122,8 @@ Scenario: Fork a git repo from pool and fork someone else's fork of the same rep
Forking git repo Alice/test-GitPkgA-alice ...
* Fork created: Admin/test-GitPkgA-alice
Total forked repos: 1
"""
When I execute git-obs with args "repo clone Admin test-GitPkgA-alice --no-ssh-strict-host-key-checking"
When I execute git-obs with args "repo clone Admin/test-GitPkgA-alice --no-ssh-strict-host-key-checking"
Then the exit code is 0

View File

@@ -1,3 +1,4 @@
import argparse
import os
import subprocess
import sys
@@ -8,6 +9,36 @@ from . import oscerr
from .output import print_msg
class OwnerRepoAction(argparse.Action):
def __call__(self, parser, namespace, value, option_string=None):
from . import gitea_api
try:
if isinstance(value, list):
namespace_value = [gitea_api.Repo.split_id(i) for i in value]
else:
namespace_value = gitea_api.Repo.split_id(value)
except ValueError as e:
raise argparse.ArgumentError(self, str(e))
setattr(namespace, self.dest, namespace_value)
class OwnerRepoPullAction(argparse.Action):
def __call__(self, parser, namespace, value, option_string=None):
from . import gitea_api
try:
if isinstance(value, list):
namespace_value = [gitea_api.PullRequest.split_id(i) for i in value]
else:
namespace_value = gitea_api.PullRequest.split_id(value)
except ValueError as e:
raise argparse.ArgumentError(self, str(e))
setattr(namespace, self.dest, namespace_value)
class GitObsCommand(osc.commandline_common.Command):
@property
def gitea_conf(self):
@@ -29,16 +60,20 @@ class GitObsCommand(osc.commandline_common.Command):
print(f" * User: {self.gitea_login.user}", file=sys.stderr)
print("", file=sys.stderr)
def add_argument_owner(self):
def add_argument_owner_repo(self, **kwargs):
self.add_argument(
"owner",
help="Name of the repository owner (login, org)",
"owner_repo",
action=OwnerRepoAction,
help="Owner and repo: (format: <owner>/<repo>)",
**kwargs,
)
def add_argument_repo(self):
def add_argument_owner_repo_pull(self, **kwargs):
self.add_argument(
"repo",
help="Name of the repository",
"owner_repo_pull",
action=OwnerRepoPullAction,
help="Owner, repo and pull request number (format: <owner>/<repo>#<pull-request-number>)",
**kwargs,
)
def add_argument_new_repo_name(self):

View File

@@ -13,11 +13,7 @@ class PullRequestGetCommand(osc.commandline_git.GitObsCommand):
parent = "PullRequestCommand"
def init_arguments(self):
self.add_argument(
"id",
nargs="+",
help="Pull request ID in <owner>/<repo>#<number> format",
)
self.add_argument_owner_repo_pull(nargs="+")
self.add_argument(
"-p",
"--patch",
@@ -34,14 +30,13 @@ class PullRequestGetCommand(osc.commandline_git.GitObsCommand):
num_entries = 0
failed_entries = []
for pr_id in args.id:
owner, repo, number = gitea_api.PullRequest.split_id(pr_id)
for owner, repo, pull in args.owner_repo_pull:
try:
pr = gitea_api.PullRequest.get(self.gitea_conn, owner, repo, number).json()
pr = gitea_api.PullRequest.get(self.gitea_conn, owner, repo, pull).json()
num_entries += 1
except gitea_api.GiteaException as e:
if e.status == 404:
failed_entries.append(pr_id)
failed_entries.append(f"{owner}/{repo}#{pull}")
continue
raise
print(gitea_api.PullRequest.to_human_readable_string(pr))
@@ -49,10 +44,12 @@ class PullRequestGetCommand(osc.commandline_git.GitObsCommand):
if args.patch:
print("")
print(tty.colorize("Patch:", "bold"))
patch = gitea_api.PullRequest.get_patch(self.gitea_conn, owner, repo, number).data
patch = gitea_api.PullRequest.get_patch(self.gitea_conn, owner, repo, pull).data
patch = highlight_diff(patch)
print(patch.decode("utf-8"))
print()
print(f"Total entries: {num_entries}", file=sys.stderr)
if failed_entries:
print(

View File

@@ -12,8 +12,7 @@ class PullRequestListCommand(osc.commandline_git.GitObsCommand):
parent = "PullRequestCommand"
def init_arguments(self):
self.add_argument_owner()
self.add_argument_repo()
self.add_argument_owner_repo(nargs="+")
self.add_argument(
"--state",
choices=["open", "closed", "all"],
@@ -26,11 +25,14 @@ class PullRequestListCommand(osc.commandline_git.GitObsCommand):
self.print_gitea_settings()
data = gitea_api.PullRequest.list(self.gitea_conn, args.owner, args.repo, state=args.state).json()
total_entries = 0
for owner, repo in args.owner_repo:
data = gitea_api.PullRequest.list(self.gitea_conn, owner, repo, state=args.state).json()
total_entries += len(data)
text = gitea_api.PullRequest.list_to_human_readable_string(data, sort=True)
if text:
print(text)
print("", file=sys.stderr)
text = gitea_api.PullRequest.list_to_human_readable_string(data, sort=True)
if text:
print(text)
print("", file=sys.stderr)
print(f"Total entries: {len(data)}", file=sys.stderr)
print(f"Total entries: {total_entries}", file=sys.stderr)

View File

@@ -1,3 +1,6 @@
import subprocess
import sys
import osc.commandline_git
@@ -13,8 +16,7 @@ class RepoCloneCommand(osc.commandline_git.GitObsCommand):
parent = "RepoCommand"
def init_arguments(self):
self.add_argument_owner()
self.add_argument_repo()
self.add_argument_owner_repo(nargs="+")
self.add_argument(
"-a",
@@ -45,15 +47,42 @@ class RepoCloneCommand(osc.commandline_git.GitObsCommand):
def run(self, args):
from osc import gitea_api
from osc.output import tty
self.print_gitea_settings()
gitea_api.Repo.clone(
self.gitea_conn,
args.owner,
args.repo,
directory=args.directory,
anonymous=args.anonymous,
add_remotes=True,
ssh_private_key_path=args.ssh_key or self.gitea_login.ssh_key,
ssh_strict_host_key_checking=not(args.no_ssh_strict_host_key_checking),
)
if len(args.owner_repo) > 1 and args.directory:
self.parser.error("The --directory option cannot be used with multiple repos")
num_entries = 0
failed_entries = []
for owner, repo in args.owner_repo:
print(f"Cloning git repo {owner}/{repo} ...", file=sys.stderr)
try:
gitea_api.Repo.clone(
self.gitea_conn,
owner,
repo,
directory=args.directory,
anonymous=args.anonymous,
add_remotes=True,
ssh_private_key_path=args.ssh_key or self.gitea_login.ssh_key,
ssh_strict_host_key_checking=not(args.no_ssh_strict_host_key_checking),
)
num_entries += 1
except gitea_api.GiteaException as e:
if e.status == 404:
print(f" * {tty.colorize('ERROR', 'red,bold')}: Repo doesn't exist: {owner}/{repo}", file=sys.stderr)
failed_entries.append(f"{owner}/{repo}")
continue
raise
except subprocess.CalledProcessError as e:
print(f" * {tty.colorize('ERROR', 'red,bold')}: git clone failed", file=sys.stderr)
failed_entries.append(f"{owner}/{repo}")
continue
print("", file=sys.stderr)
print(f"Total cloned repos: {num_entries}", file=sys.stderr)
if failed_entries:
print(f"{tty.colorize('ERROR', 'red,bold')}: Couldn't clone the following repos: {', '.join(failed_entries)}", file=sys.stderr)
sys.exit(1)

View File

@@ -12,8 +12,7 @@ class RepoForkCommand(osc.commandline_git.GitObsCommand):
parent = "RepoCommand"
def init_arguments(self):
self.add_argument_owner()
self.add_argument_repo()
self.add_argument_owner_repo(nargs="+")
self.add_argument_new_repo_name()
def run(self, args):
@@ -22,15 +21,35 @@ class RepoForkCommand(osc.commandline_git.GitObsCommand):
self.print_gitea_settings()
print(f"Forking git repo {args.owner}/{args.repo} ...", file=sys.stderr)
try:
response = gitea_api.Fork.create(self.gitea_conn, args.owner, args.repo, new_repo_name=args.new_repo_name)
repo = response.json()
fork_owner = repo["owner"]["login"]
fork_repo = repo["name"]
print(f" * Fork created: {fork_owner}/{fork_repo}", file=sys.stderr)
except gitea_api.ForkExists as e:
fork_owner = e.fork_owner
fork_repo = e.fork_repo
print(f" * Fork already exists: {fork_owner}/{fork_repo}", file=sys.stderr)
print(f" * {tty.colorize('WARNING', 'yellow,bold')}: Using an existing fork with a different name than requested", file=sys.stderr)
if len(args.owner_repo) > 1 and args.new_repo_name:
self.parser.error("The --new-repo-name option cannot be used with multiple repos")
num_entries = 0
failed_entries = []
for owner, repo in args.owner_repo:
print(f"Forking git repo {owner}/{repo} ...", file=sys.stderr)
try:
response = gitea_api.Fork.create(self.gitea_conn, owner, repo, new_repo_name=args.new_repo_name)
repo = response.json()
fork_owner = repo["owner"]["login"]
fork_repo = repo["name"]
print(f" * Fork created: {fork_owner}/{fork_repo}", file=sys.stderr)
num_entries += 1
except gitea_api.ForkExists as e:
fork_owner = e.fork_owner
fork_repo = e.fork_repo
print(f" * Fork already exists: {fork_owner}/{fork_repo}", file=sys.stderr)
print(f" * {tty.colorize('WARNING', 'yellow,bold')}: Using an existing fork with a different name than requested", file=sys.stderr)
num_entries += 1
except gitea_api.GiteaException as e:
if e.status == 404:
print(f" * {tty.colorize('ERROR', 'red,bold')}: Repo doesn't exist: {owner}/{repo}", file=sys.stderr)
failed_entries.append(f"{owner}/{repo}")
continue
raise
print("", file=sys.stderr)
print(f"Total forked repos: {num_entries}", file=sys.stderr)
if failed_entries:
print(f"{tty.colorize('ERROR', 'red,bold')}: Couldn't fork the following repos: {', '.join(failed_entries)}", file=sys.stderr)
sys.exit(1)

View File

@@ -56,8 +56,8 @@ class Fork:
return conn.request("POST", url, json_data=json_data)
except GiteaException as e:
# use ForkExists exception to parse fork_owner and fork_repo from the response
fork_exists_exception = ForkExists(e.response, owner, repo)
if e.status == 409:
fork_exists_exception = ForkExists(e.response, owner, repo)
if exist_ok:
from . import Repo
return Repo.get(conn, fork_exists_exception.fork_owner, fork_exists_exception.fork_repo)

View File

@@ -22,7 +22,7 @@ class PullRequest:
"""
Split <owner>/<repo>#<number> into individual components and return them in a tuple.
"""
match = re.match(r"(.+)/(.+)#(.+)", pr_id)
match = re.match(r"^([^/]+)/([^/]+)#([0-9]+)$", pr_id)
if not match:
raise ValueError(f"Invalid pull request id: {pr_id}")
return match.groups()

View File

@@ -1,6 +1,8 @@
import os
import re
import subprocess
from typing import Optional
from typing import Tuple
from .connection import Connection
from .connection import GiteaHTTPResponse
@@ -8,6 +10,16 @@ from .user import User
class Repo:
@classmethod
def split_id(cls, repo_id: str) -> Tuple[str, str]:
"""
Split <owner>/<repo> into individual components and return them in a tuple.
"""
match = re.match(r"^([^/]+)/([^/]+)$", repo_id)
if not match:
raise ValueError(f"Invalid repo id: {repo_id}")
return match.groups()
@classmethod
def get(
cls,