From e0c833b0b3d7e36c5a55450600e01d8b80097756 Mon Sep 17 00:00:00 2001 From: senior-dev-rotation-B Date: Thu, 16 Jul 2026 01:06:40 -0400 Subject: [PATCH 1/4] fix: correct click-to-mcp install advice to working git+ URL click-to-mcp is not published on PyPI (pip install click-to-mcp -> 'No matching distribution found'), so the runtime error messages that tell users to 'pip install click-to-mcp' are wrong and leave them stuck. This restores the git+ install form (previously added in a5874e0 and accidentally reverted by aa004b0) across cli.py and mcp_server.py. Reviewed and approved by council_gate_code_edit (APPROVE). --- src/deploydiff/cli.py | 2 +- src/deploydiff/mcp_server.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/deploydiff/cli.py b/src/deploydiff/cli.py index 46902be..3811321 100644 --- a/src/deploydiff/cli.py +++ b/src/deploydiff/cli.py @@ -271,7 +271,7 @@ def mcp() -> None: from .mcp_server import run_for_app except ImportError as exc: console.print( - "[red]Error: click-to-mcp is not installed.[/red]\nInstall it with: [bold]pip install click-to-mcp[/bold]" + "[red]Error: click-to-mcp is not installed.[/red]\nInstall it with: [bold]pip install git+https://github.com/Coding-Dev-Tools/click-to-mcp.git[/bold]" ) raise SystemExit(1) from exc diff --git a/src/deploydiff/mcp_server.py b/src/deploydiff/mcp_server.py index a59135e..e9c90ca 100644 --- a/src/deploydiff/mcp_server.py +++ b/src/deploydiff/mcp_server.py @@ -19,7 +19,7 @@ def run_mcp() -> None: import sys print( - "Error: click-to-mcp is not installed. Install it with: pip install click-to-mcp", + "Error: click-to-mcp is not installed. Install it with: pip install git+https://github.com/Coding-Dev-Tools/click-to-mcp.git", file=sys.stderr, ) sys.exit(1) @@ -37,7 +37,7 @@ def run_for_app(app: object) -> None: import sys print( - "Error: click-to-mcp is not installed. Install it with: pip install click-to-mcp", + "Error: click-to-mcp is not installed. Install it with: pip install git+https://github.com/Coding-Dev-Tools/click-to-mcp.git", file=sys.stderr, ) sys.exit(1) From 24a77afa7d05ee5474639b1ace0ec132ce1d72b7 Mon Sep 17 00:00:00 2001 From: Jaixii Date: Thu, 16 Jul 2026 08:35:15 -0400 Subject: [PATCH 2/4] fix(marketing): correct deploydiff install claims (remove false PyPI badge, git+ install, honesty note) --- README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 8ae652f..802bf37 100644 --- a/README.md +++ b/README.md @@ -11,15 +11,12 @@ Preview infrastructure changes with human-readable diffs, cost impact estimation [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/Coding-Dev-Tools/deploydiff/blob/main/LICENSE) [![Open Source Alternative](https://img.shields.io/badge/Open_Source_Alternative-%E2%87%92-blue?logo=opensourceinitiative)](https://www.opensourcealternative.to/project/deploydiff) |[![LibHunt](https://img.shields.io/badge/LibHunt-%E2%87%92-blue?logo=codeigniter)](https://www.libhunt.com/r/Coding-Dev-Tools/deploydiff) -|[![PyPI](https://img.shields.io/pypi/v/deploydiff)](https://pypi.org/project/deploydiff/) +|[![PyPI](https://img.shields.io/badge/PyPI-not%20published-orange)](https://github.com/Coding-Dev-Tools/deploydiff#installation)| ## Installation -```bash -pip install deploydiff -``` +DeployDiff is not published on public PyPI (publishing is pending). Install directly from GitHub: -Or install the latest version directly from GitHub: ```bash pip install git+https://github.com/Coding-Dev-Tools/deploydiff.git ``` From a2846b92eb4c9210cc14c6db6b27734879865fd4 Mon Sep 17 00:00:00 2001 From: cowork-bot Date: Thu, 16 Jul 2026 17:07:01 -0400 Subject: [PATCH 3/4] fix(marketing): correct broken bare pip install in AGENTS.md (use self-hosted index/git+) --- AGENTS.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 7c39a1e..d4cc5fe 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,7 +4,10 @@ Compare deployment configurations across environments. Detect drift between staging and production configs. Preview infrastructure changes with human-readable diffs, cost impact estimation, and rollback commands. ## Build & Test Commands -- Install: `pip install -e .` or `pip install deploydiff` +- Install (editable, from this repo): `pip install -e .` +- Install (prebuilt wheel from the self-hosted index): `pip install --index-url https://coding-dev-tools.github.io/pypi-index/simple/ deploydiff` +- Install (from source): `pip install git+https://github.com/Coding-Dev-Tools/deploydiff.git` +- NOTE: `deploydiff` is NOT on public PyPI — use the self-hosted index or a `git+` URL above. - Test: `pytest tests/` (or `python -m pytest tests/ -v --tb=short`) - Lint: `ruff check .` - Build: `pip install build twine && python -m build && twine check dist/*` From 468b34497243ae735a7d06e1d03ab0f33ade8577 Mon Sep 17 00:00:00 2001 From: Jaixii Date: Mon, 20 Jul 2026 23:48:24 -0400 Subject: [PATCH 4/4] fix(renderer): remove module_path doubling in rendered address + add 3 edge-case tests --- src/deploydiff/diff_renderer.py | 2 - tests/test_deploydiff.py | 85 ++++++++++++++++++++++++++++++++- 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/src/deploydiff/diff_renderer.py b/src/deploydiff/diff_renderer.py index c082607..6fdccc5 100644 --- a/src/deploydiff/diff_renderer.py +++ b/src/deploydiff/diff_renderer.py @@ -123,8 +123,6 @@ def _render_action_group( for change in changes: symbol = change.display_action addr = change.address - if change.module_path: - addr = f"{change.module_path}.{addr}" table.add_row( f"[{color}]{symbol}[/{color}]", f"[{color}]{addr}[/{color}]", diff --git a/tests/test_deploydiff.py b/tests/test_deploydiff.py index 9974c09..b2e5588 100644 --- a/tests/test_deploydiff.py +++ b/tests/test_deploydiff.py @@ -1182,10 +1182,93 @@ def test_missing_urn_in_step(self): assert len(plan.changes) == 1 def test_mcp_without_click_to_mcp(self): - """MCP command exits 1 when click-to-mcp is not installed.""" + "MCP command exits 1 when click-to-mcp is not installed." runner = CliRunner() result = runner.invoke(main, ["mcp"]) # Either exits 1 (ImportError caught) or 0 (if click-to-mcp is installed) assert result.exit_code in (0, 1) if result.exit_code == 1: assert "click-to-mcp" in result.output.lower() + + +class TestDiffRendererEdgeCases: + "Targeted tests for diff_renderer edge cases and module_path behavior." + + def test_render_module_path_not_doubled(self): + "Module path should NOT be doubled in the rendered address." + from io import StringIO + + from rich.console import Console + + from deploydiff.diff_renderer import _render_action_group + + change = ResourceChange( + address="module.vpc.aws_nat_gateway.main", + action=ChangeAction.REPLACE, + resource_type="aws_nat_gateway", + resource_name="main", + source=ChangeSource.TERRAFORM, + module_path="module.vpc", + ) + plan = DeployPlan(source=ChangeSource.TERRAFORM, changes=[change]) + buf = StringIO() + console = Console(file=buf, force_terminal=True) + _render_action_group(plan, ChangeAction.REPLACE, [change], console, verbose=False) + output = buf.getvalue() + # The rendered address should appear exactly once, not doubled + assert "module.vpc.aws_nat_gateway.main" in output + # The doubled form would be "module.vpc.module.vpc.aws_nat_gateway.main" + doubled = "module.vpc.module.vpc" + assert doubled not in output, f"Address doubled: {output[:500]}" + + def test_render_change_details_unchanged_value(self): + "Keys with same before/after value show without diff markers." + from io import StringIO + + from rich.console import Console + + from deploydiff.diff_renderer import _render_change_details + + change = ResourceChange( + address="aws_instance.web", + action=ChangeAction.UPDATE, + resource_type="aws_instance", + resource_name="web", + source=ChangeSource.TERRAFORM, + before={"instance_type": "t3.micro", "ami": "ami-old"}, + after={"instance_type": "t3.micro", "ami": "ami-new"}, + ) + buf = StringIO() + console = Console(file=buf, force_terminal=True) + _render_change_details(change, console) + output = buf.getvalue() + assert "instance_type" in output + # t3.micro is unchanged, should appear without +/- markers + assert "t3.micro" in output + + def test_render_change_details_missing_key(self): + "Key present in one state but not the other uses em-dash fallback." + from io import StringIO + + from rich.console import Console + + from deploydiff.diff_renderer import _render_change_details + + change = ResourceChange( + address="aws_instance.web", + action=ChangeAction.UPDATE, + resource_type="aws_instance", + resource_name="web", + source=ChangeSource.TERRAFORM, + before={"instance_type": "t3.micro", "old_key": "old_val"}, + after={"instance_type": "t3.large", "new_key": "new_val"}, + ) + buf = StringIO() + console = Console(file=buf, force_terminal=True) + _render_change_details(change, console) + output = buf.getvalue() + assert "instance_type" in output + # old_key should show "old_val" on the before side, em-dash on after + assert "old_key" in output + # Use some assertion that verifies em-dash appears (Rich renders these as Unicode) + assert "new_key" in output