From a5b6a89e9200997219fcf5b2bfb1ae2d8926cc37 Mon Sep 17 00:00:00 2001 From: davidvujic Date: Sun, 15 Oct 2023 21:23:22 +0200 Subject: [PATCH 1/5] feat(poly diff): print affected projects, changed bricks as parseable output that is useful for running tests --- components/polylith/diff/report.py | 56 +++++++-------- components/polylith/poetry/commands/diff.py | 79 +++++++++++++++------ 2 files changed, 82 insertions(+), 53 deletions(-) diff --git a/components/polylith/diff/report.py b/components/polylith/diff/report.py index 59d68862..0eaf1dc6 100644 --- a/components/polylith/diff/report.py +++ b/components/polylith/diff/report.py @@ -22,14 +22,35 @@ 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, "component", 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_diff_summary(tag: str, bases: List[str], components: List[str]) -> None: @@ -46,30 +67,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)) diff --git a/components/polylith/poetry/commands/diff.py b/components/polylith/poetry/commands/diff.py index 8162227a..0ea462ca 100644 --- a/components/polylith/poetry/commands/diff.py +++ b/components/polylith/poetry/commands/diff.py @@ -1,45 +1,80 @@ from pathlib import Path +from typing import List, Union from cleo.helpers import option from poetry.console.commands.command import Command from polylith import diff, info, repo, workspace +def opt( + name: str, short: Union[str, None] = None, description: Union[str, None] = None +) -> dict: + desc = description or f"Print changed {name}" + + defaults = { + "long_name": name, + "description": desc, + "flag": True, + } + + extra = {"short_name": short} if short else {} + + return {**defaults, **extra} + + class DiffCommand(Command): name = "poly diff" description = "Shows changed bricks compared to the latest git tag." options = [ - option( - long_name="short", - short_name="s", - description="Print only changed projects", - flag=True, - ), + option(**opt("short", short="s", description="Print short view")), + option(**opt("projects")), + option(**opt("bricks")), ] + def has_partial_options(self) -> bool: + return any(self.option(k) for k in {"projects", "bricks"}) + + def print_partial_views( + self, projects: list, bases: List[str], components: List[str] + ) -> None: + short = self.option("short") + + if short and not self.has_partial_options(): + diff.report.print_detected_changes_in_projects(projects, short) + + return + + if self.option("projects"): + diff.report.print_detected_changes_in_projects(projects, short) + + if self.option("bricks"): + diff.report.print_detected_changes_in_bricks(bases, components, short) + 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.") + + return 0 + + 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 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) 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_partial_views(projects, bases, components) return 0 From bc5c8d991e6ed94162349a6ec4fe55a4992e32fd Mon Sep 17 00:00:00 2001 From: davidvujic Date: Sat, 21 Oct 2023 14:22:15 +0200 Subject: [PATCH 2/5] bump version to 1.11.0 --- projects/poetry_polylith_plugin/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/poetry_polylith_plugin/pyproject.toml b/projects/poetry_polylith_plugin/pyproject.toml index abe8e638..4109a22e 100644 --- a/projects/poetry_polylith_plugin/pyproject.toml +++ b/projects/poetry_polylith_plugin/pyproject.toml @@ -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/" From 9a263e28175d88a5d38c0140fe621ff50dd813b2 Mon Sep 17 00:00:00 2001 From: davidvujic Date: Sat, 21 Oct 2023 15:36:37 +0200 Subject: [PATCH 3/5] fix(poly diff): print projects affected by changes --- components/polylith/diff/collect.py | 24 ++++++- components/polylith/diff/report.py | 16 +++-- components/polylith/poetry/commands/diff.py | 71 ++++++++++----------- 3 files changed, 68 insertions(+), 43 deletions(-) diff --git a/components/polylith/diff/collect.py b/components/polylith/diff/collect.py index afb833c8..2a42416d 100644 --- a/components/polylith/diff/collect.py +++ b/components/polylith/diff/collect.py @@ -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 @@ -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} diff --git a/components/polylith/diff/report.py b/components/polylith/diff/report.py index 0eaf1dc6..cc05cf5f 100644 --- a/components/polylith/diff/report.py +++ b/components/polylith/diff/report.py @@ -1,4 +1,4 @@ -from typing import List +from typing import List, Set from polylith import info from polylith.reporting import theme @@ -22,7 +22,7 @@ def print_diff_details( console.print(table, overflow="ellipsis") -def _print_detected_changes(changes: List[str], markup: str, short: bool) -> None: +def print_detected_changes(changes: List[str], markup: str, short: bool) -> None: if not changes: return @@ -43,14 +43,18 @@ def print_detected_changes_in_bricks( sorted_components = sorted(components) if short: - _print_detected_changes(sorted_components + sorted_bases, "data", short) + print_detected_changes(sorted_components + sorted_bases, "data", short) else: - _print_detected_changes(sorted_components, "component", short) - _print_detected_changes(sorted_bases, "base", short) + print_detected_changes(sorted_components, "component", 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) + print_detected_changes(projects, "proj", short) + + +def print_projects_affected_by_changes(projects: Set[str], short: bool) -> None: + print_detected_changes(list(projects), "proj", short) def print_diff_summary(tag: str, bases: List[str], components: List[str]) -> None: diff --git a/components/polylith/poetry/commands/diff.py b/components/polylith/poetry/commands/diff.py index 0ea462ca..3a35ee2e 100644 --- a/components/polylith/poetry/commands/diff.py +++ b/components/polylith/poetry/commands/diff.py @@ -1,65 +1,49 @@ from pathlib import Path -from typing import List, Union +from typing import List, Set from cleo.helpers import option from poetry.console.commands.command import Command from polylith import diff, info, repo, workspace -def opt( - name: str, short: Union[str, None] = None, description: Union[str, None] = None -) -> dict: - desc = description or f"Print changed {name}" - - defaults = { - "long_name": name, - "description": desc, - "flag": True, - } - - extra = {"short_name": short} if short else {} - - return {**defaults, **extra} - - class DiffCommand(Command): name = "poly diff" description = "Shows changed bricks compared to the latest git tag." options = [ - option(**opt("short", short="s", description="Print short view")), - option(**opt("projects")), - option(**opt("bricks")), + option( + long_name="short", + short_name="s", + 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 {"projects", "bricks"}) + return any(self.option(k) for k in {"bricks"}) def print_partial_views( - self, projects: list, bases: List[str], components: List[str] + 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_detected_changes_in_projects(projects, short) + diff.report.print_projects_affected_by_changes(affected_projects, short) return - if self.option("projects"): - diff.report.print_detected_changes_in_projects(projects, short) - if self.option("bricks"): diff.report.print_detected_changes_in_bricks(bases, components, short) - 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.") - - return 0 - + 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) @@ -68,13 +52,28 @@ def handle(self) -> int: 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: - self.print_partial_views(projects, bases, components) + self.print_views(root, tag) return 0 From cdf89b921e0c76c7dd7884117cc48447bf3e6611 Mon Sep 17 00:00:00 2001 From: davidvujic Date: Sat, 21 Oct 2023 16:18:18 +0200 Subject: [PATCH 4/5] fix(poly diff): sort affected projects --- components/polylith/diff/report.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/polylith/diff/report.py b/components/polylith/diff/report.py index cc05cf5f..cc0e1dc5 100644 --- a/components/polylith/diff/report.py +++ b/components/polylith/diff/report.py @@ -54,7 +54,9 @@ def print_detected_changes_in_projects(projects: List[str], short: bool) -> None def print_projects_affected_by_changes(projects: Set[str], short: bool) -> None: - print_detected_changes(list(projects), "proj", short) + 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: From 960b2cde69e674ab857250abfee8a5b5867dbe52 Mon Sep 17 00:00:00 2001 From: davidvujic Date: Sat, 21 Oct 2023 16:24:11 +0200 Subject: [PATCH 5/5] fix: typo in print component theming --- components/polylith/diff/report.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/polylith/diff/report.py b/components/polylith/diff/report.py index cc0e1dc5..e4eef366 100644 --- a/components/polylith/diff/report.py +++ b/components/polylith/diff/report.py @@ -45,7 +45,7 @@ def print_detected_changes_in_bricks( if short: print_detected_changes(sorted_components + sorted_bases, "data", short) else: - print_detected_changes(sorted_components, "component", short) + print_detected_changes(sorted_components, "comp", short) print_detected_changes(sorted_bases, "base", short)