refactor(version): separate version and release commands

`markitect version` now prints a clean version string (Unix style),
with -v for commit/branch/dirty. `markitect release` shows detailed
development status: commits since tag, local changes, upstream
divergence. No overlap between the two commands.

Replaces get_version_info()/get_release_info() with get_version()
and get_release_status(). Drops yaml output format from release
(json + text sufficient).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-13 17:49:14 +01:00
parent be3b4e3aae
commit 69aea1ada7
3 changed files with 186 additions and 136 deletions

View File

@@ -28,7 +28,7 @@ import builtins
from .database import DatabaseManager
from .legacy_compat import LegacyMode, emit_deprecation_warning, legacy_switch_option
from .__version__ import get_version_info, get_release_info
from .__version__ import get_version, get_release_status
from .batch_processor import BatchProcessor, ProcessingMode, ErrorHandling, create_file_processor
from .config_manager import ConfigurationManager
@@ -201,8 +201,7 @@ def print_version(ctx, param, value):
"""Callback to print version and exit."""
if not value or ctx.resilient_parsing:
return
version_info = get_version_info()
click.echo(version_info['full_version'])
click.echo(get_version())
ctx.exit()
@click.group()
@@ -253,59 +252,98 @@ def cli(config, verbose, database, config_file):
# Version and release information commands
@cli.command()
@click.option('--short', is_flag=True, help='Show only version number')
def version(short):
"""Show MarkiTect version information."""
version_info = get_version_info()
@click.option('--verbose', '-v', 'verbose', is_flag=True,
help='Include commit and branch details.')
def version(verbose):
"""Print the version number.
if short:
click.echo(version_info['full_version'])
\b
Behaves like standard Unix tools: bare version string by default,
additional detail with -v.
\b
Examples:
markitect version # 0.12.0
markitect version -v # 0.12.0 (be3b4e3 on main)
"""
ver = get_version()
if not verbose:
click.echo(ver)
else:
click.echo("MarkiTect Version Information")
click.echo("============================")
click.echo(f"Version: {version_info['full_version']}")
click.echo(f"Short Version: {version_info['short_version']}")
if version_info.get('is_git_repo'):
click.echo(f"Git Commit: {version_info.get('git_commit', 'N/A')}")
click.echo(f"Git Branch: {version_info.get('git_branch', 'N/A')}")
if version_info.get('git_tag'):
click.echo(f"Git Tag: {version_info['git_tag']}")
click.echo(f"Development Build: {'Yes' if version_info.get('is_dev') else 'No'}")
else:
click.echo("Git Repository: Not available")
status = get_release_status()
parts = [ver]
if status.get("commit"):
parts.append(f"({status['commit']} on {status.get('branch', '?')})")
if status.get("is_dirty"):
parts.append("[dirty]")
click.echo(" ".join(parts))
@cli.command()
@click.option('--format', 'output_format', default='text',
type=click.Choice(['text', 'json', 'yaml']),
help='Output format (text, json, yaml)')
type=click.Choice(['text', 'json']),
help='Output format.')
def release(output_format):
"""Show MarkiTect release information."""
release_info = get_release_info()
"""Show detailed release and development status.
\b
Reports what has changed since the last tagged version:
commits, local modifications, and upstream divergence.
\b
Examples:
markitect release
markitect release --format json
"""
import json as _json
status = get_release_status()
if output_format == 'json':
import json
click.echo(json.dumps(release_info, indent=2))
elif output_format == 'yaml':
import yaml
click.echo(yaml.dump(release_info, default_flow_style=False))
else:
# Text format
click.echo("MarkiTect Release Information")
click.echo("============================")
click.echo(f"Version: {release_info['full_version']}")
click.echo(f"Release Type: {release_info['release_type']}")
click.echo(f"Build From: {release_info['build_from']}")
click.echo(f"Commit: {release_info['commit']}")
click.echo(f"Clean Build: {'Yes' if release_info['clean_build'] else 'No'}")
click.echo(_json.dumps(status, indent=2))
return
if release_info['is_git_repo']:
click.echo(f"Git Repository: Available")
if release_info['git_tag']:
click.echo(f"Tagged Release: {release_info['git_tag']}")
# ── Header ──
tag_label = status.get("tag") or "(none)"
dirty = " [dirty]" if status.get("is_dirty") else ""
click.echo(f"Version: {status['version']}")
click.echo(f"Commit: {status.get('commit', 'N/A')}")
click.echo(f"Branch: {status.get('branch', 'N/A')}")
click.echo(f"Tag: {tag_label}")
# ── Commits since tag ──
n = status.get("commits_since_tag", 0)
if n == 0 and status.get("tag"):
click.echo(f"Status: release (tagged){dirty}")
else:
click.echo(f"Status: development ({n} commit{'s' if n != 1 else ''} since last tag){dirty}")
# ── Upstream comparison ──
upstream = status.get("upstream_diff")
if upstream:
ahead = upstream["ahead"]
behind = upstream["behind"]
tracking = upstream["tracking"]
if ahead == 0 and behind == 0:
click.echo(f"Upstream: up to date with {tracking}")
else:
click.echo("Git Repository: Not available")
parts = []
if ahead:
parts.append(f"{ahead} ahead")
if behind:
parts.append(f"{behind} behind")
click.echo(f"Upstream: {', '.join(parts)} ({tracking})")
else:
click.echo("Upstream: no tracking branch")
# ── Changed files ──
changed = status.get("changed_files", [])
if changed:
click.echo(f"\nLocal changes ({len(changed)} file{'s' if len(changed) != 1 else ''}):")
for line in changed:
click.echo(f" {line}")
elif not status.get("is_git_repo"):
click.echo("\nNot a git repository — no change tracking available.")