Skip to content
Open
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
17 changes: 17 additions & 0 deletions src/specify_cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1211,6 +1211,7 @@ def init(

ensure_constitution_from_template(project_path, tracker=tracker)

_git_ext_freshly_installed = False
if not no_git:
tracker.start("git")
git_messages = []
Expand Down Expand Up @@ -1245,6 +1246,7 @@ def init(
bundled_path, get_speckit_version()
)
git_messages.append("extension installed")
_git_ext_freshly_installed = True
else:
git_has_error = True
git_messages.append("bundled extension not found")
Expand Down Expand Up @@ -1356,6 +1358,21 @@ def init(
console.print(tracker.render())
console.print("\n[bold green]Project ready.[/bold green]")

if _git_ext_freshly_installed:
console.print()
console.print(
Panel(
"The [bold]git[/bold] extension is currently enabled by default, "
"but starting with [bold]v1.0.0[/bold] it will require explicit opt-in.\n\n"
"To opt in after v1.0.0:\n"
" • [cyan]specify init --extension git[/cyan]\n"
" • [cyan]specify extension add git[/cyan] (post-init)",
title="[yellow]⚠ Upcoming Change: git Extension[/yellow]",
border_style="yellow",
padding=(1, 2),
)
)

# Agent folder security notice
agent_config = AGENT_CONFIG.get(selected_ai)
if agent_config:
Expand Down
76 changes: 76 additions & 0 deletions tests/extensions/git/test_git_extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -587,3 +587,79 @@ def test_check_feature_branch_rejects_malformed_timestamp(self, tmp_path: Path):
capture_output=True, text=True,
)
assert result.returncode != 0


# ── Deprecation Notice Tests ──────────────────────────────────────────────────


class TestGitExtDeprecationNotice:
"""Tests for the v1.0.0 deprecation notice shown during specify init."""

def test_deprecation_notice_shown_on_fresh_install(self, tmp_path: Path):
"""specify init shows the git extension deprecation notice on first install."""
from typer.testing import CliRunner
from unittest.mock import patch, MagicMock
from specify_cli import app

project_dir = tmp_path / "test-project"
runner = CliRunner()

mock_registry = MagicMock()
mock_registry.is_installed.return_value = False

mock_manager = MagicMock()
mock_manager.registry = mock_registry

with patch("specify_cli.extensions.ExtensionManager", return_value=mock_manager):
result = runner.invoke(
app,
["init", str(project_dir), "--ai", "claude", "--ignore-agent-tools", "--script", "sh"],
catch_exceptions=False,
)

assert result.exit_code == 0, result.output
assert "Upcoming Change: git Extension" in result.output
assert "v1.0.0" in result.output
assert "specify init --extension git" in result.output

def test_deprecation_notice_not_shown_when_already_installed(self, tmp_path: Path):
"""specify init does NOT show the deprecation notice when git extension is already installed."""
from typer.testing import CliRunner
from unittest.mock import patch, MagicMock
from specify_cli import app

project_dir = tmp_path / "test-project"
runner = CliRunner()

mock_registry = MagicMock()
mock_registry.is_installed.return_value = True

mock_manager = MagicMock()
mock_manager.registry = mock_registry

with patch("specify_cli.extensions.ExtensionManager", return_value=mock_manager):
result = runner.invoke(
app,
["init", str(project_dir), "--ai", "claude", "--ignore-agent-tools", "--script", "sh"],
catch_exceptions=False,
)

assert result.exit_code == 0, result.output
assert "Upcoming Change: git Extension" not in result.output

def test_deprecation_notice_not_shown_with_no_git_flag(self, tmp_path: Path):
"""specify init does NOT show the deprecation notice when --no-git is passed."""
from typer.testing import CliRunner
from specify_cli import app

project_dir = tmp_path / "test-project"
runner = CliRunner()

result = runner.invoke(
app,
["init", str(project_dir), "--ai", "claude", "--ignore-agent-tools", "--no-git", "--script", "sh"],
catch_exceptions=False,
)

assert result.exit_code == 0, result.output
assert "Upcoming Change: git Extension" not in result.output
Loading