Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions doc/changes/unreleased.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Unreleased

## Summary

This releases fixes Nox session `release:prepare` for multi-project repositories.

## Bugfixes

* #580: Fixed Nox session `release:prepare` for multi-project repositories

## Features

* #485: Improved nox task `release:trigger`
42 changes: 19 additions & 23 deletions exasol/toolbox/util/dependencies/poetry_dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
Package,
)
from exasol.toolbox.util.git import Git
from noxconfig import PROJECT_CONFIG


class PoetryGroup(BaseModel):
Expand Down Expand Up @@ -82,6 +83,12 @@ def groups(self) -> tuple[PoetryGroup, ...]:
return tuple(groups)


def run_command(*args: str, cwd: Path | None = None) -> subprocess.CompletedProcess:
return subprocess.run(
args, capture_output=True, text=True, cwd=cwd, check=True
) # nosec: B603 - risk of untrusted input for subprocess call is accepted


class PoetryDependencies(BaseModel):
groups: tuple[PoetryGroup, ...]
working_directory: Path
Expand Down Expand Up @@ -111,44 +118,34 @@ def direct_dependencies(
) -> OrderedDict[str, dict[NormalizedPackageStr, Package]]:
dependencies = OrderedDict()
for group in self.groups:
command = (
proc = run_command(
"poetry",
"show",
"--top-level",
f"--only={group.name}",
"--no-truncate",
)
output = subprocess.run(
command,
capture_output=True,
text=True,
cwd=self.working_directory,
check=True,
)
result = self._extract_from_poetry_show(output_text=output.stdout)
result = self._extract_from_poetry_show(output_text=proc.stdout)
dependencies[group.name] = result
return dependencies

@property
def all_dependencies(self) -> OrderedDict[str, dict[NormalizedPackageStr, Package]]:
command = ("poetry", "show", "--no-truncate")
output = subprocess.run(
command,
capture_output=True,
text=True,
proc = run_command(
"poetry",
"show",
"--no-truncate",
cwd=self.working_directory,
check=True,
)

direct_dependencies = self.direct_dependencies.copy()

transitive_dependencies = {}
names_direct_dependencies = {
package_name
for group_list in direct_dependencies
for package_name in group_list
}
for line in output.stdout.splitlines():
for line in proc.stdout.splitlines():
dep = self._extract_from_line(line=line)
if dep and dep.name not in names_direct_dependencies:
transitive_dependencies[dep.normalized_name] = dep
Expand All @@ -169,10 +166,9 @@ def get_dependencies_from_latest_tag() -> (
OrderedDict[str, dict[NormalizedPackageStr, Package]]
):
latest_tag = Git.get_latest_tag()
with tempfile.TemporaryDirectory() as path:
tmpdir = Path(path)

Git.copy_remote_file_locally(latest_tag, "poetry.lock", tmpdir)
Git.copy_remote_file_locally(latest_tag, PYPROJECT_TOML, tmpdir)

path = PROJECT_CONFIG.root.relative_to(Git.toplevel())
with tempfile.TemporaryDirectory() as tmpdir_str:
tmpdir = Path(tmpdir_str)
for file in ("poetry.lock", PYPROJECT_TOML):
Git.checkout(latest_tag, path / file, tmpdir / file)
return get_dependencies(working_directory=tmpdir)
26 changes: 15 additions & 11 deletions exasol/toolbox/util/git.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import subprocess # nosec
from functools import wraps
from pathlib import Path
from typing import Union


def run_command(func):
Expand All @@ -26,25 +27,28 @@ def get_latest_tag():

@staticmethod
@run_command
def read_file_from_tag(tag: str, remote_file: str):
def read_file_from_tag(tag: str, path: Union[Path, str]):
"""
Read the contents of the specified file `remote_file` at the point in time
specified by git tag `tag`.
Read the contents of the specified file `path` at the point in
time specified by git tag `tag`.
"""
return ["git", "cat-file", "blob", f"{tag}:{remote_file}"]
return ["git", "cat-file", "blob", f"{tag}:{path}"]

@staticmethod
def copy_remote_file_locally(
tag: str, remote_file: str, destination_directory: Path
) -> None:
def checkout(tag: str, source: Path, dest: Path) -> None:
"""
Copy the contents of the specified file `remote_file` at the point in time
specified by git tag `tag` and copy it into the local `destination_directory/remote_file`.
Copy the specified file `source` at the point in time specified by
git tag `tag` to file `dest` within the local filesystem.
"""
contents = Git.read_file_from_tag(tag=tag, remote_file=remote_file)
(destination_directory / remote_file).write_text(contents)
contents = Git.read_file_from_tag(tag=tag, path=source)
dest.write_text(contents)

@staticmethod
@run_command
def create_and_switch_to_branch(branch_name: str):
return ["git", "switch", "-c", branch_name]

@staticmethod
@run_command
def toplevel():
return ["git", "rev-parse", "--show-toplevel"]
15 changes: 6 additions & 9 deletions test/unit/util/git_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def latest_tag() -> str:

@pytest.fixture(scope="module")
def read_file_from_tag(latest_tag) -> str:
return Git.read_file_from_tag(tag=latest_tag, remote_file=POETRY_LOCK)
return Git.read_file_from_tag(tag=latest_tag, path=POETRY_LOCK)


class TestGit:
Expand All @@ -28,12 +28,9 @@ def test_read_file_from_tag(read_file_from_tag):
assert read_file_from_tag != ""

@staticmethod
def test_copy_remote_file_locally(tmp_path, read_file_from_tag):
latest_tag = Git.get_latest_tag()

Git.copy_remote_file_locally(
tag=latest_tag, remote_file=POETRY_LOCK, destination_directory=tmp_path
)

result = (tmp_path / POETRY_LOCK).read_text()
def test_checkout(tmp_path, read_file_from_tag):
tag = Git.get_latest_tag()
dest = tmp_path / POETRY_LOCK
Git.checkout(tag=tag, source=POETRY_LOCK, dest=dest)
result = dest.read_text()
assert result == read_file_from_tag