Skip to content

Commit 643b5bf

Browse files
resolve conversation
1 parent 4b17f5b commit 643b5bf

File tree

3 files changed

+137
-106
lines changed

3 files changed

+137
-106
lines changed

exasol/toolbox/release/__init__.py

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
from dataclasses import dataclass
55
from datetime import datetime
66
from enum import Enum
7-
from functools import total_ordering
7+
from functools import (
8+
total_ordering,
9+
wraps,
10+
)
811
from inspect import cleandoc
912
from pathlib import Path
1013
from shutil import which
@@ -28,27 +31,19 @@ def __str__(self):
2831
return self.name.lower()
2932

3033

31-
def poetry(arguments: str):
32-
def decorator(function):
33-
def wrapper(*args, **kwargs):
34-
cmd = which("poetry")
35-
if not cmd:
36-
raise ToolboxError("Couldn't find poetry executable")
34+
def poetry_command(func):
35+
@wraps(func)
36+
def wrapper(*args, **kwargs):
37+
cmd = which("poetry")
38+
if not cmd:
39+
raise ToolboxError("Couldn't find poetry executable")
40+
print("huhu")
41+
try:
42+
return func(*args, **kwargs)
43+
except subprocess.CalledProcessError as ex:
44+
raise ToolboxError(f"Failed to execute: {ex.cmd}") from ex
3745

38-
try:
39-
command = [cmd] + arguments.split(" ")
40-
result = subprocess.run(
41-
command,
42-
capture_output=True,
43-
)
44-
except subprocess.CalledProcessError as ex:
45-
raise ToolboxError() from ex
46-
47-
return function(result)
48-
49-
return wrapper
50-
51-
return decorator
46+
return wrapper
5247

5348

5449
@total_ordering
@@ -95,19 +90,24 @@ def from_string(version):
9590
return Version(*version)
9691

9792
@staticmethod
98-
@poetry("version --no-ansi --short")
99-
def from_poetry(result):
100-
version = result.stdout.decode().strip()
101-
102-
return Version.from_string(version)
93+
@poetry_command
94+
def from_poetry():
95+
output = subprocess.run(
96+
["poetry", "version", "--no-ansi", "--short"],
97+
capture_output=True,
98+
text=True,
99+
)
100+
return Version.from_string(output.stdout.strip())
103101

104102
@staticmethod
103+
@poetry_command
105104
def upgrade_version_from_poetry(t: ReleaseTypes):
106-
@poetry(f"version {str(t)} --dry-run --no-ansi --short")
107-
def version(result):
108-
return result.stdout.decode().strip()
109-
110-
return Version.from_string(version())
105+
output = subprocess.run(
106+
["poetry", "version", str(t), "--dry-run", "--no-ansi", "--short"],
107+
capture_output=True,
108+
text=True,
109+
)
110+
return Version.from_string(output.stdout.strip())
111111

112112

113113
def extract_release_notes(file: str | Path) -> str:

test/unit/poetry_decorator_test.py

Lines changed: 0 additions & 31 deletions
This file was deleted.

test/unit/release_test.py

Lines changed: 106 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
_trigger_release,
1616
)
1717
from exasol.toolbox.release import (
18+
ReleaseTypes,
1819
Version,
1920
extract_release_notes,
2021
new_changelog,
22+
poetry_command,
2123
)
2224

2325

@@ -56,7 +58,7 @@ def set_poetry_version(version):
5658
return subprocess.CompletedProcess(
5759
args=["poetry", "version", "--no-ansi", "--short"],
5860
returncode=0,
59-
stdout=version.encode("utf8"),
61+
stdout=version,
6062
stderr="",
6163
)
6264

@@ -154,53 +156,113 @@ def test_extract_release_notes(unreleased_md):
154156
assert expected == actual
155157

156158

157-
@pytest.mark.parametrize(
158-
"error_cmd",
159-
[
160-
("git", "remote", "show", "origin"),
161-
("git", "checkout", "main"),
162-
("git", "pull"),
163-
("git", "tag", "--list"),
164-
("gh", "release", "list"),
165-
("git", "tag", "0.3.0"),
166-
("git", "push", "origin", "0.3.0"),
167-
],
168-
)
169-
@patch("exasol.toolbox.nox._release.Version.from_poetry", return_value="0.3.0")
170-
def test_trigger_release(mock, error_cmd):
171-
def simulate_fail(args, **kwargs):
172-
print("_______________")
173-
print(args)
174-
if args == error_cmd:
175-
raise CalledProcessError(returncode=1, cmd=error_cmd)
176-
result = ""
159+
@pytest.fixture(scope="class")
160+
def mock_from_poetry():
161+
with patch(
162+
"exasol.toolbox.nox._release.Version.from_poetry", return_value="0.3.0"
163+
) as mock_obj:
164+
yield mock_obj
165+
166+
167+
class TestTriggerReleaseWithMocking:
168+
@staticmethod
169+
def _get_mock_string(args) -> str:
177170
if args == ("git", "remote", "show", "origin"):
178-
result = "test\nHEAD branch: main\ntest"
179-
return MagicMock(returncode=0, stdout=result)
171+
return "test\nHEAD branch: main\ntest"
172+
if args in [("git", "tag", "--list"), ("gh", "release", "list")]:
173+
return "0.1.0\n0.2.0"
174+
return ""
180175

181-
with patch("subprocess.run", side_effect=simulate_fail):
182-
with pytest.raises(ReleaseError) as ex:
183-
_trigger_release()
184-
print(ex.value)
176+
def _get_subprocess_run_mock(self, args) -> str:
177+
return MagicMock(returncode=0, stdout=self._get_mock_string(args))
185178

179+
def test_works_as_expected(self, mock_from_poetry):
180+
def simulate_pass(args, **kwargs):
181+
return self._get_subprocess_run_mock(args)
186182

187-
@pytest.mark.parametrize(
188-
"error_cmd, result",
189-
[
190-
(
183+
with patch("subprocess.run", side_effect=simulate_pass):
184+
result = _trigger_release()
185+
assert result == mock_from_poetry.return_value
186+
187+
@pytest.mark.parametrize(
188+
"error_cmd",
189+
[
191190
("git", "remote", "show", "origin"),
192-
"test\nHEAD: \ntest",
193-
),
194-
(
191+
("git", "checkout", "main"),
192+
("git", "pull"),
195193
("git", "tag", "--list"),
196-
"0.1.0\n0.2.0\n0.3.0",
197-
),
198-
(
199194
("gh", "release", "list"),
200-
"0.1.0\n0.2.0\n0.3.0",
201-
),
202-
],
203-
)
204-
@patch("exasol.toolbox.nox._release.Version.from_poetry", return_value="0.3.0")
205-
def test_trigger_release_bad_return(mock, error_cmd, result):
206-
assert True
195+
("git", "tag", "0.3.0"),
196+
("git", "push", "origin", "0.3.0"),
197+
],
198+
)
199+
def test_caught_called_process_error_raises_release_error(
200+
self, mock_from_poetry, error_cmd
201+
):
202+
def simulate_fail(args, **kwargs):
203+
if args == error_cmd:
204+
raise CalledProcessError(returncode=1, cmd=error_cmd)
205+
return self._get_subprocess_run_mock(args)
206+
207+
with patch("subprocess.run", side_effect=simulate_fail):
208+
with pytest.raises(ReleaseError) as ex:
209+
_trigger_release()
210+
assert str(error_cmd) in str(ex)
211+
212+
def test_default_branch_could_not_be_found(self, mock_from_poetry):
213+
def simulate_fail(args, **kwargs):
214+
if args == ("git", "remote", "show", "origin"):
215+
return MagicMock(returncode=0, stdout="DUMMY TEXT")
216+
return self._get_subprocess_run_mock(args)
217+
218+
with patch("subprocess.run", side_effect=simulate_fail):
219+
with pytest.raises(ReleaseError) as ex:
220+
_trigger_release()
221+
assert "default branch could not be found" in str(ex)
222+
223+
def test_tag_already_exists(self, mock_from_poetry):
224+
version = mock_from_poetry.return_value
225+
226+
def simulate_fail(args, **kwargs):
227+
if args == ("git", "tag", "--list"):
228+
return MagicMock(returncode=0, stdout=f"0.1.0\n0.2.0\n{version}")
229+
return self._get_subprocess_run_mock(args)
230+
231+
with patch("subprocess.run", side_effect=simulate_fail):
232+
with pytest.raises(ReleaseError) as ex:
233+
_trigger_release()
234+
assert f"tag {version} already exists" in str(ex)
235+
236+
def test_release_already_exists(self, mock_from_poetry):
237+
version = mock_from_poetry.return_value
238+
239+
def simulate_fail(args, **kwargs):
240+
if args == ("gh", "release", "list"):
241+
return MagicMock(returncode=0, stdout=f"0.1.0\n0.2.0\n{version}")
242+
return self._get_subprocess_run_mock(args)
243+
244+
with patch("subprocess.run", side_effect=simulate_fail):
245+
with pytest.raises(ReleaseError) as ex:
246+
_trigger_release()
247+
assert f"release {version} already exists" in str(ex)
248+
249+
250+
@patch("exasol.toolbox.release.which", return_value=None)
251+
def test_poetry_decorator_no_poetry_executable(mock):
252+
@poetry_command
253+
def test():
254+
pass
255+
256+
with pytest.raises(ToolboxError):
257+
test()
258+
259+
260+
@patch("exasol.toolbox.release.which", return_value="test/path")
261+
def test_poetry_decorator_subprocess(mock):
262+
@poetry_command
263+
def test():
264+
raise subprocess.CalledProcessError(returncode=1, cmd=["test"])
265+
pass
266+
267+
with pytest.raises(ToolboxError):
268+
test()

0 commit comments

Comments
 (0)