Skip to content

Tag

tag

GitTagTool — one-shot semver tag: preflight + compute + create + verify + push.

GitTagTool

Bases: AXMTool

Create a semver release tag in one call.

Performs preflight checks (clean tree, CI status), computes the next version from Conventional Commits, creates an annotated tag, verifies hatch-vcs resolution, and pushes to origin.

Registered as git_tag via axm.tools entry point.

Source code in packages/axm-git/src/axm_git/tools/tag.py
class GitTagTool(AXMTool):
    """Create a semver release tag in one call.

    Performs preflight checks (clean tree, CI status), computes the
    next version from Conventional Commits, creates an annotated tag,
    verifies hatch-vcs resolution, and pushes to origin.

    Registered as ``git_tag`` via axm.tools entry point.
    """

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

    def execute(
        self,
        *,
        path: str = ".",
        version: str | None = None,
        **kwargs: Any,
    ) -> ToolResult:
        """Create and push a semver tag.

        Args:
            path: Project root (required).
            version: Version override (optional, e.g. ``"v1.0.0"``).

        Returns:
            ToolResult with tag, version, and push status.
        """
        resolved = Path(path).resolve()
        tag_prefix = _get_tag_prefix(resolved)

        # 1. Preflight: repo, clean tree, CI, commits
        result = _preflight(resolved, tag_prefix=tag_prefix)
        if isinstance(result, ToolResult):
            return result
        ci_check, current_tag, commits = result

        # 2. Compute version
        next_version, bump_type, breaking = _resolve_version(
            version, current_tag, commits, tag_prefix=tag_prefix
        )
        logger.info(
            "Tagging %s (bump=%s, breaking=%s)",
            next_version,
            bump_type,
            breaking,
        )

        # 3. Create annotated tag
        full_tag = f"{tag_prefix}{next_version}"
        tag_result = run_git(["tag", "-a", full_tag, "-m", full_tag], resolved)
        if tag_result.returncode != 0:
            return ToolResult(
                success=False,
                error=f"Failed to create tag: {tag_result.stderr.strip()}",
            )

        # 4. Verify hatch-vcs (best-effort)
        resolved_version = None
        pkg_name = detect_package_name(resolved)
        if pkg_name:
            resolved_version = _verify_hatch_vcs(resolved, pkg_name)

        # 5. Push tag
        push = run_git(["push", "origin", full_tag], resolved)

        return ToolResult(
            success=True,
            data={
                "tag": next_version,
                "bump": bump_type,
                "breaking": breaking,
                "resolved_version": resolved_version,
                "pushed": push.returncode == 0,
                "ci_check": ci_check,
                "commits_included": len(commits),
                "current_tag": current_tag or "none",
            },
        )
name property

Tool name used for MCP registration.

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

Create and push a semver tag.

Parameters:

Name Type Description Default
path str

Project root (required).

'.'
version str | None

Version override (optional, e.g. "v1.0.0").

None

Returns:

Type Description
ToolResult

ToolResult with tag, version, and push status.

Source code in packages/axm-git/src/axm_git/tools/tag.py
def execute(
    self,
    *,
    path: str = ".",
    version: str | None = None,
    **kwargs: Any,
) -> ToolResult:
    """Create and push a semver tag.

    Args:
        path: Project root (required).
        version: Version override (optional, e.g. ``"v1.0.0"``).

    Returns:
        ToolResult with tag, version, and push status.
    """
    resolved = Path(path).resolve()
    tag_prefix = _get_tag_prefix(resolved)

    # 1. Preflight: repo, clean tree, CI, commits
    result = _preflight(resolved, tag_prefix=tag_prefix)
    if isinstance(result, ToolResult):
        return result
    ci_check, current_tag, commits = result

    # 2. Compute version
    next_version, bump_type, breaking = _resolve_version(
        version, current_tag, commits, tag_prefix=tag_prefix
    )
    logger.info(
        "Tagging %s (bump=%s, breaking=%s)",
        next_version,
        bump_type,
        breaking,
    )

    # 3. Create annotated tag
    full_tag = f"{tag_prefix}{next_version}"
    tag_result = run_git(["tag", "-a", full_tag, "-m", full_tag], resolved)
    if tag_result.returncode != 0:
        return ToolResult(
            success=False,
            error=f"Failed to create tag: {tag_result.stderr.strip()}",
        )

    # 4. Verify hatch-vcs (best-effort)
    resolved_version = None
    pkg_name = detect_package_name(resolved)
    if pkg_name:
        resolved_version = _verify_hatch_vcs(resolved, pkg_name)

    # 5. Push tag
    push = run_git(["push", "origin", full_tag], resolved)

    return ToolResult(
        success=True,
        data={
            "tag": next_version,
            "bump": bump_type,
            "breaking": breaking,
            "resolved_version": resolved_version,
            "pushed": push.returncode == 0,
            "ci_check": ci_check,
            "commits_included": len(commits),
            "current_tag": current_tag or "none",
        },
    )