Skip to content

Commit 4b17f5b

Browse files
resolve conversation
1 parent 565c66d commit 4b17f5b

File tree

5 files changed

+96
-108
lines changed

5 files changed

+96
-108
lines changed

doc/shared_content/how_release.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Creating a Release
88

99
.. code-block:: shell
1010
11-
nox -s release:prepare -- [-h]
11+
nox -s release:prepare -- --type {major,minor,patch}
1212
1313
#. Merge your **Pull Request** to the **default branch**
1414

@@ -36,17 +36,17 @@ The release failed during pre-release checks
3636
3737
git push --delete origin "<major>.<minor>.<patch>"
3838
39-
#. Fix the issue(s) which lead to the failing checks
39+
#. Fix the issue(s) which led to the failing checks
4040
#. Start the release process from the beginning
4141
4242
4343
One of the release steps failed (Partial Release)
4444
-------------------------------------------------
45-
#. Check the Github action/workflow to see which steps failed
45+
#. Check the GitHub action/workflow to see which steps failed
4646
#. Finish or redo the failed release steps manually
4747
4848
.. note:: Example
4949
50-
**Scenario**: Publishing of the release on Github was successfully but during the PyPi release, the upload step got interrupted.
50+
**Scenario**: Publishing of the release on GitHub was successfully but during the PyPi release, the upload step was interrupted.
5151
5252
**Solution**: Manually push the package to PyPi

exasol/toolbox/nox/_release.py

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,11 @@
33
import argparse
44
import re
55
import subprocess
6-
import sys
76
from pathlib import Path
8-
from typing import (
9-
List,
10-
Tuple,
11-
)
127

138
import nox
149
from nox import Session
1510

16-
from exasol.toolbox import cli
1711
from exasol.toolbox.nox._shared import (
1812
Mode,
1913
_version,
@@ -42,7 +36,6 @@ def _create_parser() -> argparse.ArgumentParser:
4236
type=ReleaseTypes,
4337
help="specifies which type of upgrade is to be performed",
4438
required=True,
45-
choices=[rt.value for rt in list(ReleaseTypes)],
4639
default=argparse.SUPPRESS,
4740
)
4841
parser.add_argument(
@@ -97,17 +90,6 @@ def _add_files_to_index(session: Session, files: list[Path]) -> None:
9790
session.run("git", "add", f"{file}")
9891

9992

100-
def _type_release(release_type: ReleaseTypes, old_version: Version) -> Version:
101-
upgrade = {
102-
ReleaseTypes.Major: Version(old_version.major + 1, 0, 0),
103-
ReleaseTypes.Minor: Version(old_version.major, old_version.minor + 1, 0),
104-
ReleaseTypes.Patch: Version(
105-
old_version.major, old_version.minor, old_version.patch + 1
106-
),
107-
}
108-
return upgrade[release_type]
109-
110-
11193
class ReleaseError(Exception):
11294
"""Error during trigger release"""
11395

@@ -119,7 +101,9 @@ def run(*args: str):
119101
args, capture_output=True, text=True, check=True
120102
).stdout
121103
except subprocess.CalledProcessError as ex:
122-
raise ReleaseError(f"failed to execute command {args}") from ex
104+
raise ReleaseError(
105+
f"failed to execute command {ex.cmd}\n\n{ex.stderr}"
106+
) from ex
123107

124108
branches = run("git", "remote", "show", "origin")
125109
if not (result := re.search(r"HEAD branch: (\S+)", branches)):
@@ -196,5 +180,5 @@ def prepare_release(session: Session, python=False) -> None:
196180

197181
@nox.session(name="release:trigger", python=False)
198182
def trigger_release(session: Session) -> None:
199-
"""releases the project automatically"""
183+
"""trigger an automatic project release"""
200184
print(f"new version: {_trigger_release()}")

exasol/toolbox/release/__init__.py

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,29 @@ def __str__(self):
2828
return self.name.lower()
2929

3030

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")
37+
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
52+
53+
3154
@total_ordering
3255
@dataclass(frozen=True)
3356
class Version:
@@ -72,37 +95,19 @@ def from_string(version):
7295
return Version(*version)
7396

7497
@staticmethod
75-
def from_poetry():
76-
poetry = which("poetry")
77-
if not poetry:
78-
raise ToolboxError("Couldn't find poetry executable")
79-
80-
try:
81-
result = subprocess.run(
82-
[poetry, "version", "--no-ansi", "--short"], capture_output=True
83-
)
84-
except subprocess.CalledProcessError as ex:
85-
raise ToolboxError() from ex
98+
@poetry("version --no-ansi --short")
99+
def from_poetry(result):
86100
version = result.stdout.decode().strip()
87101

88102
return Version.from_string(version)
89103

90104
@staticmethod
91105
def upgrade_version_from_poetry(t: ReleaseTypes):
92-
poetry = which("poetry")
93-
if not poetry:
94-
raise ToolboxError("Couldn't find poetry executable")
95-
96-
try:
97-
result = subprocess.run(
98-
[poetry, "version", str(t), "--dry-run", "--no-ansi", "--short"],
99-
capture_output=True,
100-
)
101-
except subprocess.CalledProcessError as ex:
102-
raise ToolboxError() from ex
103-
version = result.stdout.decode().strip()
106+
@poetry(f"version {str(t)} --dry-run --no-ansi --short")
107+
def version(result):
108+
return result.stdout.decode().strip()
104109

105-
return Version.from_string(version)
110+
return Version.from_string(version())
106111

107112

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

test/unit/poetry_decorator_test.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from subprocess import CalledProcessError
2+
from unittest.mock import patch
3+
4+
import pytest
5+
6+
from exasol.toolbox.error import ToolboxError
7+
from exasol.toolbox.release import poetry
8+
9+
10+
@patch("exasol.toolbox.release.which", return_value=None)
11+
def test_poetry_decorator_no_poetry_executable(mock):
12+
@poetry("test")
13+
def test(result):
14+
pass
15+
16+
with pytest.raises(ToolboxError):
17+
test()
18+
19+
20+
@patch("exasol.toolbox.release.which", return_value="")
21+
@patch(
22+
"exasol.toolbox.release.subprocess.run",
23+
side_effect=CalledProcessError(returncode=1, cmd=["test"]),
24+
)
25+
def test_poetry_decorator_subprocess(mockSR, mockW):
26+
@poetry("test")
27+
def test(result):
28+
pass
29+
30+
with pytest.raises(ToolboxError):
31+
test()

test/unit/release_test.py

Lines changed: 28 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,10 @@
99

1010
import pytest
1111

12+
from exasol.toolbox.error import ToolboxError
1213
from exasol.toolbox.nox._release import (
1314
ReleaseError,
14-
ReleaseTypes,
1515
_trigger_release,
16-
_type_release,
1716
)
1817
from exasol.toolbox.release import (
1918
Version,
@@ -156,83 +155,52 @@ def test_extract_release_notes(unreleased_md):
156155

157156

158157
@pytest.mark.parametrize(
159-
"rtype,old,expected",
158+
"error_cmd",
160159
[
161-
("major", "1.2.3", "2.0.0"),
162-
("minor", "1.2.3", "1.3.0"),
163-
("patch", "1.2.3", "1.2.4"),
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"),
164167
],
165168
)
166-
def test_type_release(rtype, old, expected):
167-
actual = _type_release(ReleaseTypes(rtype), Version.from_string(old))
168-
expected = Version.from_string(expected)
169-
assert actual == expected
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 = ""
177+
if args == ("git", "remote", "show", "origin"):
178+
result = "test\nHEAD branch: main\ntest"
179+
return MagicMock(returncode=0, stdout=result)
180+
181+
with patch("subprocess.run", side_effect=simulate_fail):
182+
with pytest.raises(ReleaseError) as ex:
183+
_trigger_release()
184+
print(ex.value)
170185

171186

172187
@pytest.mark.parametrize(
173-
"cmdline, expected",
188+
"error_cmd, result",
174189
[
175-
(
176-
("git", "remote", "show", "origin"),
177-
CalledProcessError,
178-
),
179190
(
180191
("git", "remote", "show", "origin"),
181192
"test\nHEAD: \ntest",
182193
),
183-
(
184-
("git", "checkout", "main"),
185-
CalledProcessError,
186-
),
187-
(
188-
("git", "pull"),
189-
CalledProcessError,
190-
),
191-
(
192-
("git", "tag", "--list"),
193-
CalledProcessError,
194-
),
195194
(
196195
("git", "tag", "--list"),
197196
"0.1.0\n0.2.0\n0.3.0",
198197
),
199-
(
200-
("gh", "release", "list"),
201-
CalledProcessError,
202-
),
203198
(
204199
("gh", "release", "list"),
205200
"0.1.0\n0.2.0\n0.3.0",
206201
),
207-
(
208-
("git", "tag", "0.3.0"),
209-
CalledProcessError,
210-
),
211-
(
212-
("git", "push", "origin", "0.3.0"),
213-
CalledProcessError,
214-
),
215202
],
216203
)
217204
@patch("exasol.toolbox.nox._release.Version.from_poetry", return_value="0.3.0")
218-
def test_x1(mock, cmdline, expected):
219-
def valide_result(args):
220-
if args == ("git", "remote", "show", "origin"):
221-
return "test\nHEAD branch: main\ntest"
222-
return ""
223-
224-
def simulate_fail(args, **kwargs):
225-
print("_______________")
226-
print(args)
227-
if args != cmdline:
228-
print(valide_result(args))
229-
return MagicMock(returncode=0, stdout=valide_result(args))
230-
if expected == CalledProcessError:
231-
raise CalledProcessError(returncode=1, cmd=cmdline)
232-
else:
233-
return MagicMock(returncode=0, stdout=expected)
234-
235-
with patch("subprocess.run", side_effect=simulate_fail):
236-
with pytest.raises(ReleaseError) as ex:
237-
_trigger_release()
238-
print(ex.value)
205+
def test_trigger_release_bad_return(mock, error_cmd, result):
206+
assert True

0 commit comments

Comments
 (0)