Skip to content

Release diff

release_diff

GitReleaseDiffTool — read-only SemVer bump decision for a package subdir.

GitReleaseDiffTool

Bases: AXMTool

Summarise commits/diff since the last tag to decide a SemVer bump.

Strictly read-only: issues only log, diff, tag and rev-parse — never creates or pushes a tag. Scopes every log and diff to the resolved package subdir so monorepo attribution is correct. Registered as git_release_diff via axm.tools.

Source code in packages/axm-git/src/axm_git/tools/release_diff.py
Python
class GitReleaseDiffTool(AXMTool):
    """Summarise commits/diff since the last tag to decide a SemVer bump.

    Strictly read-only: issues only ``log``, ``diff``, ``tag`` and
    ``rev-parse`` — never creates or pushes a tag. Scopes every ``log``
    and ``diff`` to the resolved package subdir so monorepo attribution
    is correct. Registered as ``git_release_diff`` via axm.tools.
    """

    @property
    def name(self) -> str:
        """Tool name used for MCP registration."""
        return "git_release_diff"

    def execute(self, *, path: str = ".", **kwargs: object) -> ToolResult:
        """Compute a read-only release diff for the package at *path*.

        Args:
            path: Package root (defaults to the current directory).

        Returns:
            ToolResult with current tag, commit summary, diffstat and a
            suggested next version.
        """
        resolved = Path(path).resolve()
        prefix = get_tag_prefix(resolved)
        try:
            data = self._collect(resolved, prefix)
        except subprocess.TimeoutExpired as exc:
            return _timeout_error_result(exc)
        return ToolResult(success=True, data=data, text=render_text(data))

    def _collect(self, resolved: Path, prefix: str) -> dict[str, object]:
        """Gather all read-only data for the success-path payload."""
        root = find_git_root(resolved)
        subdir = self._subdir(root, resolved)
        cwd = root or resolved
        current_tag = _current_tag(cwd, prefix)
        commits = _scoped_log(cwd, current_tag, subdir)
        files_changed, diffstat = _diffstat(cwd, current_tag, subdir)
        suggested_bump, suggested_next, breaking = _suggest(commits, current_tag)
        return {
            "current_tag": current_tag,
            "suggested_bump": suggested_bump,
            "suggested_next": suggested_next,
            "breaking": breaking,
            "commits_since": commits,
            "counts": _aggregate_counts(commits),
            "files_changed": files_changed,
            "diffstat": diffstat,
            "public_api_touched": _public_api_touched(cwd, current_tag, subdir),
        }

    @staticmethod
    def _subdir(root: Path | None, resolved: Path) -> str:
        """Package path relative to the git root (``.`` when at the root)."""
        if root is None:
            return "."
        try:
            rel = resolved.relative_to(root)
        except ValueError:
            return "."
        return str(rel)
name property

Tool name used for MCP registration.

execute(*, path='.', **kwargs)

Compute a read-only release diff for the package at path.

Parameters:

Name Type Description Default
path str

Package root (defaults to the current directory).

'.'

Returns:

Type Description
ToolResult

ToolResult with current tag, commit summary, diffstat and a

ToolResult

suggested next version.

Source code in packages/axm-git/src/axm_git/tools/release_diff.py
Python
def execute(self, *, path: str = ".", **kwargs: object) -> ToolResult:
    """Compute a read-only release diff for the package at *path*.

    Args:
        path: Package root (defaults to the current directory).

    Returns:
        ToolResult with current tag, commit summary, diffstat and a
        suggested next version.
    """
    resolved = Path(path).resolve()
    prefix = get_tag_prefix(resolved)
    try:
        data = self._collect(resolved, prefix)
    except subprocess.TimeoutExpired as exc:
        return _timeout_error_result(exc)
    return ToolResult(success=True, data=data, text=render_text(data))