deskribe 0.1.0

Native Kubernetes resource descriptions using a caller-provided kube client
"""Exercise release guards locally without GitHub access or crate uploads."""

import os
from pathlib import Path
import shutil
import subprocess
import tempfile
import textwrap
import unittest

ROOT = Path(__file__).resolve().parents[1]


class ReleaseTagTests(unittest.TestCase):
    def test_workflow_tag_validation(self):
        workflow = (ROOT / ".github/workflows/release.yaml").read_text()
        validation = workflow.split("      - name: Validate tag and Cargo version\n", 1)[1]
        script = textwrap.dedent(validation.split("        run: |\n", 1)[1].split("\n      - name:", 1)[0])
        with tempfile.TemporaryDirectory() as directory:
            Path(directory, "Cargo.toml").write_text('[package]\nversion = "0.1.0"\n')
            for tag, valid in [
                ("v0.1.0", True),
                ("v0.1.1", False),
                ("0.1.0", False),
                ("v0.1.0-rc.1", False),
                ("v00.1.0", False),
                ("v0.1.0\n", False),
                ("v0.1.0; exit 0", False),
            ]:
                with self.subTest(tag=tag):
                    result = subprocess.run(
                        ["bash", "-euo", "pipefail", "-c", script],
                        cwd=directory,
                        env={**os.environ, "RELEASE_TAG": tag},
                        capture_output=True,
                        text=True,
                    )
                    self.assertEqual(result.returncode == 0, valid, result.stdout + result.stderr)


@unittest.skipUnless(shutil.which("just"), "just is required for release recipe tests")
class ReleaseRecipeTests(unittest.TestCase):
    def run_just(self, *args, cwd=ROOT):
        return subprocess.run(
            ["just", "--justfile", str(cwd / "Justfile"), *args],
            cwd=cwd,
            capture_output=True,
            text=True,
        )

    def test_version_bumps(self):
        for latest, bump, expected in [
            ("v0.1.0", "patch", "0.1.1"),
            ("v0.1.9", "minor", "0.2.0"),
            ("v0.9.9", "major", "1.0.0"),
            ("v1.9.9", "patch", "1.9.10"),
        ]:
            with self.subTest(latest=latest, bump=bump):
                result = self.run_just("release", "_next-version", latest, bump)
                self.assertEqual(result.returncode, 0, result.stderr)
                self.assertEqual(result.stdout.strip(), expected)

    def test_rejects_invalid_versions_and_bumps(self):
        for latest, bump in [
            ("v1.2", "patch"),
            ("v1.2.3.4", "patch"),
            ("v1.2.3-rc.1", "patch"),
            ("v01.2.3", "minor"),
            ("v1.2.3", "invalid"),
        ]:
            with self.subTest(latest=latest, bump=bump):
                self.assertNotEqual(self.run_just("release", "_next-version", latest, bump).returncode, 0)

    def test_rejects_feature_branch_and_dirty_main_before_network(self):
        with tempfile.TemporaryDirectory() as directory:
            root = Path(directory)
            shutil.copy(ROOT / "Justfile", root)
            shutil.copytree(ROOT / ".just", root / ".just")
            subprocess.run(["git", "init", "-q", "-b", "feature"], cwd=root, check=True)
            result = self.run_just("release", "_ensure-release-ready", cwd=root)
            self.assertNotEqual(result.returncode, 0)
            self.assertIn("release from main only", result.stderr)
            subprocess.run(["git", "symbolic-ref", "HEAD", "refs/heads/main"], cwd=root, check=True)
            result = self.run_just("release", "_ensure-release-ready", cwd=root)
            self.assertNotEqual(result.returncode, 0)
            self.assertIn("working tree and index must be clean", result.stderr)

    def test_aliases_parse_without_running_release(self):
        for bump in ["patch", "minor", "major"]:
            result = self.run_just("--dry-run", f"release-{bump}")
            self.assertEqual(result.returncode, 0, result.stderr)
            self.assertIn(f"_release {bump}", result.stderr)


if __name__ == "__main__":
    unittest.main()