Skip to content

Commit

Permalink
feat(poly diff): print changes for projects and/or bricks (#128)
Browse files Browse the repository at this point in the history
* feat(poly diff): print affected projects, changed bricks as parseable output that is useful for running tests

* bump version to 1.11.0
  • Loading branch information
DavidVujic authored Oct 21, 2023
1 parent 1bdabe2 commit ac058c9
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 51 deletions.
24 changes: 23 additions & 1 deletion components/polylith/diff/collect.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import subprocess
from pathlib import Path
from typing import List, Union
from typing import List, Set, Union

from polylith import repo, workspace

Expand Down Expand Up @@ -59,3 +59,25 @@ def get_files(tag: str) -> List[Path]:
)

return [Path(p) for p in res.stdout.decode("utf-8").split()]


def _affected(projects_data: List[dict], brick_type: str, bricks: List[str]) -> set:
res = {
p["path"].name: set(p.get(brick_type, [])).intersection(bricks)
for p in projects_data
}

return {k for k, v in res.items() if v}


def get_projects_affected_by_changes(
projects_data: List[dict],
projects: List[str],
bases: List[str],
components: List[str],
) -> Set[str]:
a = _affected(projects_data, "components", components)
b = _affected(projects_data, "bases", bases)
c = set(projects)

return {*a, *b, *c}
64 changes: 32 additions & 32 deletions components/polylith/diff/report.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import List
from typing import List, Set

from polylith import info
from polylith.reporting import theme
Expand All @@ -22,14 +22,41 @@ def print_diff_details(
console.print(table, overflow="ellipsis")


def print_detected_changes_in_projects(projects: List[str]) -> None:
if not projects:
def print_detected_changes(changes: List[str], markup: str, short: bool) -> None:
if not changes:
return

console = Console(theme=theme.poly_theme)

for project in sorted(projects):
console.print(f"[data]:gear: Changes found in [/][proj]{project}[/]")
if short:
console.print(",".join(changes))
return

for brick in changes:
console.print(f"[data]:gear: Changes found in [/][{markup}]{brick}[/]")


def print_detected_changes_in_bricks(
bases: List[str], components: List[str], short: bool
) -> None:
sorted_bases = sorted(bases)
sorted_components = sorted(components)

if short:
print_detected_changes(sorted_components + sorted_bases, "data", short)
else:
print_detected_changes(sorted_components, "comp", short)
print_detected_changes(sorted_bases, "base", short)


def print_detected_changes_in_projects(projects: List[str], short: bool) -> None:
print_detected_changes(projects, "proj", short)


def print_projects_affected_by_changes(projects: Set[str], short: bool) -> None:
sorted_projects = sorted(list(projects))

print_detected_changes(sorted_projects, "proj", short)


def print_diff_summary(tag: str, bases: List[str], components: List[str]) -> None:
Expand All @@ -46,30 +73,3 @@ def print_diff_summary(tag: str, bases: List[str], components: List[str]) -> Non

if bases:
console.print(f"[base]Changed bases[/]: [data]{len(bases)}[/]")


def _changed_projects(
projects_data: List[dict], brick_type: str, bricks: List[str]
) -> set:
res = {
p["path"].name: set(p.get(brick_type, [])).intersection(bricks)
for p in projects_data
}

return {k for k, v in res.items() if v}


def print_short_diff(
projects_data: List[dict],
projects: List[str],
bases: List[str],
components: List[str],
) -> None:
a = _changed_projects(projects_data, "components", components)
b = _changed_projects(projects_data, "bases", bases)
c = set(projects)

res = {*a, *b, *c}

console = Console(theme=theme.poly_theme)
console.print(",".join(res))
68 changes: 51 additions & 17 deletions components/polylith/poetry/commands/diff.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from pathlib import Path
from typing import List, Set

from cleo.helpers import option
from poetry.console.commands.command import Command
Expand All @@ -13,33 +14,66 @@ class DiffCommand(Command):
option(
long_name="short",
short_name="s",
description="Print only changed projects",
description="Print short view",
flag=True,
),
option(
long_name="bricks",
description="Print changed bricks",
flag=True,
),
]

def has_partial_options(self) -> bool:
return any(self.option(k) for k in {"bricks"})

def print_partial_views(
self,
affected_projects: Set[str],
bases: List[str],
components: List[str],
) -> None:
short = self.option("short")

if short and not self.has_partial_options():
diff.report.print_projects_affected_by_changes(affected_projects, short)

return

if self.option("bricks"):
diff.report.print_detected_changes_in_bricks(bases, components, short)

def print_views(self, root: Path, tag: str) -> None:
ns = workspace.parser.get_namespace_from_config(root)
files = diff.collect.get_files(tag)
bases = diff.collect.get_changed_bases(files, ns)
components = diff.collect.get_changed_components(files, ns)
projects = diff.collect.get_changed_projects(files)
all_projects_data = info.get_bricks_in_projects(root, components, bases, ns)
projects_data = [p for p in all_projects_data if info.is_project(p)]

affected_projects = diff.collect.get_projects_affected_by_changes(
projects_data, projects, bases, components
)

short = self.option("short")

if not short and not self.has_partial_options():
diff.report.print_diff_summary(tag, bases, components)
diff.report.print_detected_changes_in_projects(projects, short)
diff.report.print_diff_details(projects_data, bases, components)

return

self.print_partial_views(affected_projects, bases, components)

def handle(self) -> int:
root = repo.get_workspace_root(Path.cwd())
tag = diff.collect.get_latest_tag(root)

if not tag:
self.line("No tags found in repository.")
else:
ns = workspace.parser.get_namespace_from_config(root)
files = diff.collect.get_files(tag)
bases = diff.collect.get_changed_bases(files, ns)
components = diff.collect.get_changed_components(files, ns)
projects = diff.collect.get_changed_projects(files)
all_projects_data = info.get_bricks_in_projects(root, components, bases, ns)
projects_data = [p for p in all_projects_data if info.is_project(p)]

short = self.option("short")

if short:
diff.report.print_short_diff(projects_data, projects, bases, components)
else:
diff.report.print_diff_summary(tag, bases, components)
diff.report.print_detected_changes_in_projects(projects)
diff.report.print_diff_details(projects_data, bases, components)
self.print_views(root, tag)

return 0
2 changes: 1 addition & 1 deletion projects/poetry_polylith_plugin/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "poetry-polylith-plugin"
version = "1.10.1"
version = "1.11.0"
description = "A Poetry plugin that adds tooling support for the Polylith Architecture"
authors = ["David Vujic"]
homepage = "https://davidvujic.github.io/python-polylith-docs/"
Expand Down

0 comments on commit ac058c9

Please sign in to comment.