Skip to content

Commit 57749d4

Browse files
JohnVillalovosnejch
authored andcommitted
fix(cli): support binary files with @ notation
Support binary files being used in the CLI with arguments using the `@` notation. For example `--avatar @/path/to/avatar.png` Also explicitly catch the common OSError exception, which is the parent exception for things like: FileNotFoundError, PermissionError and more exceptions. Remove the bare exception handling. We would rather have the full traceback of any exceptions that we don't know about and add them later if needed. Closes: #2752
1 parent dae9e52 commit 57749d4

File tree

3 files changed

+21
-11
lines changed

3 files changed

+21
-11
lines changed

gitlab/cli.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import argparse
22
import functools
33
import os
4+
import pathlib
45
import re
56
import sys
67
import textwrap
@@ -298,12 +299,17 @@ def _parse_value(v: Any) -> Any:
298299
return v[1:]
299300
if isinstance(v, str) and v.startswith("@"):
300301
# If the user-provided value starts with @, we try to read the file
301-
# path provided after @ as the real value. Exit on any error.
302+
# path provided after @ as the real value.
303+
filepath = pathlib.Path(v[1:]).expanduser().resolve()
302304
try:
303-
with open(v[1:], encoding="utf-8") as f:
305+
with open(filepath, encoding="utf-8") as f:
304306
return f.read()
305-
except Exception as e:
306-
sys.stderr.write(f"{e}\n")
307+
except UnicodeDecodeError:
308+
with open(filepath, "rb") as f:
309+
return f.read()
310+
except OSError as exc:
311+
exc_name = type(exc).__name__
312+
sys.stderr.write(f"{exc_name}: {exc}\n")
307313
sys.exit(1)
308314

309315
return v

tests/functional/cli/test_cli_v4.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,12 +540,15 @@ def test_update_application_settings(gitlab_cli):
540540
assert ret.success
541541

542542

543-
def test_create_project_with_values_from_file(gitlab_cli, tmpdir):
543+
def test_create_project_with_values_from_file(gitlab_cli, fixture_dir, tmpdir):
544544
name = "gitlab-project-from-file"
545545
description = "Multiline\n\nData\n"
546546
from_file = tmpdir.join(name)
547547
from_file.write(description)
548548
from_file_path = f"@{str(from_file)}"
549+
avatar_file = fixture_dir / "avatar.png"
550+
assert avatar_file.exists()
551+
avatar_file_path = f"@{avatar_file}"
549552

550553
cmd = [
551554
"-v",
@@ -555,6 +558,8 @@ def test_create_project_with_values_from_file(gitlab_cli, tmpdir):
555558
name,
556559
"--description",
557560
from_file_path,
561+
"--avatar",
562+
avatar_file_path,
558563
]
559564
ret = gitlab_cli(cmd)
560565

tests/unit/test_cli.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import argparse
2+
import contextlib
23
import io
34
import os
45
import sys
56
import tempfile
6-
from contextlib import redirect_stderr # noqa: H302
77
from unittest import mock
88

99
import pytest
@@ -62,7 +62,7 @@ def test_cls_to_gitlab_resource(class_name, expected_gitlab_resource):
6262
)
6363
def test_die(message, error, expected):
6464
fl = io.StringIO()
65-
with redirect_stderr(fl):
65+
with contextlib.redirect_stderr(fl):
6666
with pytest.raises(SystemExit) as test:
6767
cli.die(message, error)
6868
assert fl.getvalue() == expected
@@ -90,12 +90,11 @@ def test_parse_value():
9090
os.unlink(temp_path)
9191

9292
fl = io.StringIO()
93-
with redirect_stderr(fl):
93+
with contextlib.redirect_stderr(fl):
9494
with pytest.raises(SystemExit) as exc:
9595
cli._parse_value("@/thisfileprobablydoesntexist")
96-
assert (
97-
fl.getvalue() == "[Errno 2] No such file or directory:"
98-
" '/thisfileprobablydoesntexist'\n"
96+
assert fl.getvalue().startswith(
97+
"FileNotFoundError: [Errno 2] No such file or directory:"
9998
)
10099
assert exc.value.code == 1
101100

0 commit comments

Comments
 (0)