Skip to content

Commit fb0bf33

Browse files
committed
Merge remote-tracking branch 'dmach/git-store-osc-allow-scmurl' into devel
2 parents 8ed614c + df49576 commit fb0bf33

File tree

11 files changed

+104
-12
lines changed

11 files changed

+104
-12
lines changed

behave/features/git-login.feature

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ Scenario: Remove a credentials login entry
9797

9898

9999
Scenario: Update a credentials login entry
100-
When I execute git-obs with args "login update alice --new-name=NEW_NAME --new-url=NEW_URL --new-user=NEW_USER --new-token=1234567890123456789012345678901234567890 --new-ssh-key= --set-as-default"
100+
When I execute git-obs with args "login update alice --new-name=NEW_NAME --new-url=NEW_URL --new-user=NEW_USER --new-token=1234567890123456789012345678901234567890 --new-ssh-key= --new-quiet=1 --set-as-default"
101101
Then the exit code is 0
102102
And stderr is
103103
"""
@@ -117,6 +117,7 @@ Scenario: Update a credentials login entry
117117
Default : true
118118
URL : NEW_URL
119119
User : NEW_USER
120+
Quiet : yes
120121
"""
121122
When I execute git-obs with args "login list"
122123
Then stdout is
@@ -130,6 +131,7 @@ Scenario: Update a credentials login entry
130131
Default : true
131132
URL : NEW_URL
132133
User : NEW_USER
134+
Quiet : yes
133135
134136
Name : bob
135137
URL : http://localhost:{context.podman.container.ports[gitea_http]}

osc/commandline_git.py

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,17 @@ def gitea_conn(self):
7777
def gitea_conn(self, value):
7878
self.main_command.gitea_conn = value
7979

80+
@property
81+
def quiet(self):
82+
if self.main_command._args.quiet:
83+
return True
84+
if self.gitea_login and self.gitea_login.quiet:
85+
return True
86+
return False
87+
8088
def print_gitea_settings(self):
89+
if self.quiet:
90+
return
8191
print(f"Using the following Gitea settings:", file=sys.stderr)
8292
print(f" * Config path: {self.gitea_conf.path}", file=sys.stderr)
8393
print(f" * Login (name of the entry in the config file): {self.gitea_login.name}", file=sys.stderr)
@@ -176,6 +186,13 @@ def __init__(self, *args, **kwargs):
176186
self._gitea_conn = None
177187

178188
def init_arguments(self):
189+
self.add_argument(
190+
"-q",
191+
"--quiet",
192+
action="store_true",
193+
help="Mute unnecessary output",
194+
)
195+
179196
self.add_argument(
180197
"--gitea-config",
181198
help="Path to gitea config. Default: $GIT_OBS_CONFIG or ~/.config/tea/config.yml.",
@@ -186,7 +203,9 @@ def init_arguments(self):
186203
"--gitea-login",
187204
help=(
188205
"Name of the login entry in the config file. Default: $GIT_OBS_LOGIN or the default entry from the config file.\n"
189-
"Alternatively, you can omit this argument and set GIT_OBS_GITEA_URL, GIT_OBS_GITEA_USER, and GIT_OBS_GITEA_TOKEN environmental variables instead.\n"
206+
"Alternatively, you can use gitea url as long as there's only a single matching entry in the config file.\n"
207+
"\n"
208+
"You can omit this argument and set GIT_OBS_GITEA_URL, GIT_OBS_GITEA_USER, and GIT_OBS_GITEA_TOKEN environmental variables instead.\n"
190209
"Optional variables: GIT_OBS_GITEA_SSH_KEY\n"
191210
"\n"
192211
"To override the existing values from the config file, you can specify the following environmental variables:\n"
@@ -245,8 +264,17 @@ def gitea_conf(self, value):
245264

246265
@property
247266
def gitea_login(self):
267+
from . import gitea_api
268+
248269
if self._gitea_login is None:
249-
self._gitea_login = self.gitea_conf.get_login(name=self._args.gitea_login)
270+
try:
271+
self._gitea_login = self.gitea_conf.get_login(name=self._args.gitea_login)
272+
except gitea_api.Login.DoesNotExist as e:
273+
try:
274+
self._gitea_login = self.gitea_conf.get_login_by_url_user(url=self._args.gitea_login)
275+
except gitea_api.Login.DoesNotExist:
276+
raise e
277+
250278
return self._gitea_login
251279

252280
@gitea_login.setter

osc/commands/fork.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ class ForkCommand(osc.commandline.OscCommand):
1919
post_parse_args = osc.commandline_git.GitObsMainCommand.post_parse_args
2020
print_gitea_settings = osc.commandline_git.GitObsCommand.print_gitea_settings
2121

22+
def quiet(self):
23+
if self.main_command.args.quiet:
24+
return True
25+
if self.gitea_login and self.gitea_login.quiet:
26+
return True
27+
return False
28+
2229
def init_arguments(self):
2330
# inherit global options from the main git-obs command
2431
osc.commandline_git.GitObsMainCommand.init_arguments(self)

osc/commands_git/login_add.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ def init_arguments(self):
2222
self.parser.add_argument("--token", help="Gitea access token; omit or set to '-' to invoke a secure interactive prompt")
2323
self.parser.add_argument("--ssh-key", metavar="PATH", help="Path to a private SSH key").completer = complete_ssh_key_path
2424
self.parser.add_argument("--git-uses-http", action="store_true", help="Git uses http(s) instead of SSH", default=None)
25+
self.parser.add_argument("--quiet", action="store_true", help="Mute unnecessary output when using this login entry")
2526
self.parser.add_argument("--set-as-default", help="Set the new login entry as default", action="store_true", default=None)
2627

2728
def run(self, args):

osc/commands_git/login_update.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def init_arguments(self):
2323
self.parser.add_argument("--new-token", metavar="TOKEN", help="Gitea access token; set to '-' to invoke a secure interactive prompt")
2424
self.parser.add_argument("--new-ssh-key", metavar="PATH", help="Path to a private SSH key").completer = complete_ssh_key_path
2525
self.parser.add_argument("--new-git-uses-http", help="Git uses http(s) instead of SSH", choices=["0", "1", "yes", "no"], default=None)
26+
self.parser.add_argument("--new-quiet", help="Mute unnecessary output when using this login entry", choices=["0", "1", "yes", "no"], default=None)
2627
self.parser.add_argument("--set-as-default", action="store_true", help="Set the login entry as default")
2728

2829
def run(self, args):
@@ -51,6 +52,13 @@ def run(self, args):
5152
else:
5253
new_git_uses_http = None
5354

55+
if args.new_quiet in ("0", "no"):
56+
new_quiet = False
57+
elif args.new_quiet in ("1", "yes"):
58+
new_quiet = True
59+
else:
60+
new_quiet = None
61+
5462
updated_login_obj = self.gitea_conf.update_login(
5563
args.name,
5664
new_name=args.new_name,
@@ -59,6 +67,7 @@ def run(self, args):
5967
new_token=args.new_token,
6068
new_ssh_key=args.new_ssh_key,
6169
new_git_uses_http=new_git_uses_http,
70+
new_quiet=new_quiet,
6271
set_as_default=args.set_as_default,
6372
)
6473
print("")

osc/core.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6490,9 +6490,15 @@ def parse_multibuild_data(s: str):
64906490

64916491
root = xml_fromstring(s)
64926492
for node in root.findall("flavor"):
6493+
if node.text is None:
6494+
result.add("")
6495+
continue
64936496
result.add(node.text)
64946497
# <package> is deprecated according to OBS Multibuild.pm, but it is widely used
64956498
for node in root.findall("package"):
6499+
if node.text is None:
6500+
result.add("")
6501+
continue
64966502
result.add(node.text)
64976503
return result
64986504

osc/git_scm/store.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,10 @@ def __init__(self, path: str, *, check: bool = True):
117117

118118
if not self._git.current_branch:
119119
# branch is required for determining and storing metadata
120-
msg = f"Directory '{path}' is not a Git SCM working copy because it has no branch or is in a detached HEAD state"
120+
msg = (
121+
f"Directory '{path}' contains a git repo that has no branch or is in a detached HEAD state.\n"
122+
"If it is a Git SCM working copy, switch to a branch to continue."
123+
)
121124
raise oscerr.NoWorkingCopy(msg)
122125

123126
# 'package' is the default type that applies to all git repos that are not projects (we have no means of detecting packages)

osc/gitea_api/conf.py

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class Login(BaseModel):
2121
token: str = Field() # type: ignore[assignment]
2222
ssh_key: Optional[str] = Field() # type: ignore[assignment]
2323
git_uses_http: Optional[bool] = Field() # type: ignore[assignment]
24+
quiet: Optional[bool] = Field() # type: ignore[assignment]
2425
default: Optional[bool] = Field() # type: ignore[assignment]
2526

2627
class AlreadyExists(oscerr.OscBaseError):
@@ -43,12 +44,21 @@ def __str__(self):
4344
" * either set the default entry by running `git-obs login update <login> --set-as-default`\n"
4445
" * or run the command with `-G/--gitea-login <login>` option"
4546
)
46-
kwargs_str = ", ".join([f"{key}={value}" for key, value in self.kwargs.items()])
47+
kwargs_str = ", ".join([f"{key}={value}" for key, value in self.kwargs.items() if value])
4748
return (
4849
f"Could not find a matching Gitea config entry: {kwargs_str}\n"
4950
" * see `git-obs login list` for valid entries"
5051
)
5152

53+
class MultipleEntriesReturned(oscerr.OscBaseError):
54+
def __init__(self, **kwargs):
55+
super().__init__()
56+
self.kwargs = kwargs
57+
58+
def __str__(self):
59+
kwargs_str = ", ".join([f"{key}={value}" for key, value in self.kwargs.items() if value])
60+
return f"Multiple login entries returned for the following args: {kwargs_str}"
61+
5262
def __init__(self, **kwargs):
5363
# ignore extra fields
5464
for key in list(kwargs):
@@ -69,6 +79,8 @@ def to_human_readable_string(self, *, show_token: bool = False):
6979
table.add("Private SSH key path", self.ssh_key)
7080
if self.git_uses_http:
7181
table.add("Git uses http(s)", "yes" if self.git_uses_http else "no")
82+
if self.quiet:
83+
table.add("Quiet", "yes" if self.quiet else "no")
7284
if show_token:
7385
# tokens are stored in the plain text, there's not reason to protect them too much
7486
# let's only hide them from the output by default
@@ -147,16 +159,25 @@ def get_login(self, name: Optional[str] = None) -> Login:
147159
return login
148160
raise Login.DoesNotExist(name=name)
149161

150-
def get_login_by_url_user(self, url: str, user: str) -> Login:
162+
def get_login_by_url_user(self, url: str, user: Optional[str] = None) -> Login:
151163
"""
152164
Return ``Login`` object for the given ``url`` and ``user``.
153165
"""
154166
from .git import Git
155167

156168
# exact match
169+
matches = []
157170
for login in self.list_logins():
158-
if (login.url, login.user) == (url, user):
159-
return login
171+
if user is None:
172+
if login.url == url:
173+
matches.append(login)
174+
elif (login.url, login.user) == (url, user):
175+
matches.append(login)
176+
177+
if len(matches) == 1:
178+
return matches[0]
179+
if len(matches) >= 2:
180+
raise Login.MultipleEntriesReturned(url=url, user=user)
160181

161182
def url_to_hostname(value):
162183
netloc = Git.urlparse(value).netloc
@@ -172,9 +193,18 @@ def url_to_hostname(value):
172193
return netloc
173194

174195
# match only hostname (netloc without 'user@' and ':port') + user
196+
matches = []
175197
for login in self.list_logins():
176-
if (url_to_hostname(login.url), login.user) == (url_to_hostname(url), user):
177-
return login
198+
if user is None:
199+
if url_to_hostname(login.url) == url_to_hostname(url):
200+
matches.append(login)
201+
elif (url_to_hostname(login.url), login.user) == (url_to_hostname(url), user):
202+
matches.append(login)
203+
204+
if len(matches) == 1:
205+
return matches[0]
206+
if len(matches) >= 2:
207+
raise Login.MultipleEntriesReturned(url=url, user=user)
178208

179209
raise Login.DoesNotExist(url=url, user=user)
180210

@@ -212,6 +242,7 @@ def update_login(
212242
new_token: Optional[str] = None,
213243
new_ssh_key: Optional[str] = None,
214244
new_git_uses_http: Optional[bool] = None,
245+
new_quiet: Optional[bool] = None,
215246
set_as_default: Optional[bool] = None,
216247
) -> Login:
217248
login = self.get_login(name)
@@ -236,6 +267,9 @@ def update_login(
236267
# remove from the config instead of setting to False
237268
login.git_uses_http = None
238269

270+
if new_quiet is not None:
271+
login.quiet = new_quiet
272+
239273
if set_as_default:
240274
login.default = True
241275

osc/obs_api/token.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ class Kind(str, Enum):
9494
),
9595
)
9696

97-
triggered_at: str = Field(
97+
triggered_at: Optional[str] = Field(
9898
xml_attribute=True,
9999
description=textwrap.dedent(
100100
"""

osc/store.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,5 @@ def git_is_unsupported(path: str, msg: str):
5656
# not a working copy, we're not handling it
5757
return
5858

59-
if isinstance(store, git_scm.GitStore) or store.scmurl:
59+
if isinstance(store, git_scm.GitStore):
6060
raise oscerr.NoWorkingCopy(msg)

0 commit comments

Comments
 (0)