katalyst-taxonomy-cli 2.0.1a1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. katalyst_taxonomy_cli/__init__.py +14 -0
  2. katalyst_taxonomy_cli/__main__.py +12 -0
  3. katalyst_taxonomy_cli/_wiring.py +248 -0
  4. katalyst_taxonomy_cli/app.py +550 -0
  5. katalyst_taxonomy_cli/commands/__init__.py +1 -0
  6. katalyst_taxonomy_cli/commands/api.py +104 -0
  7. katalyst_taxonomy_cli/commands/backend.py +96 -0
  8. katalyst_taxonomy_cli/commands/bundle.py +106 -0
  9. katalyst_taxonomy_cli/commands/clone.py +68 -0
  10. katalyst_taxonomy_cli/commands/config.py +748 -0
  11. katalyst_taxonomy_cli/commands/config_filters.py +159 -0
  12. katalyst_taxonomy_cli/commands/config_home.py +179 -0
  13. katalyst_taxonomy_cli/commands/config_plugins.py +180 -0
  14. katalyst_taxonomy_cli/commands/config_profile.py +604 -0
  15. katalyst_taxonomy_cli/commands/config_schemas.py +257 -0
  16. katalyst_taxonomy_cli/commands/config_sources.py +141 -0
  17. katalyst_taxonomy_cli/commands/core.py +468 -0
  18. katalyst_taxonomy_cli/commands/create.py +145 -0
  19. katalyst_taxonomy_cli/commands/deps.py +48 -0
  20. katalyst_taxonomy_cli/commands/diff.py +63 -0
  21. katalyst_taxonomy_cli/commands/drafts.py +63 -0
  22. katalyst_taxonomy_cli/commands/export.py +186 -0
  23. katalyst_taxonomy_cli/commands/init.py +84 -0
  24. katalyst_taxonomy_cli/commands/kinds.py +302 -0
  25. katalyst_taxonomy_cli/commands/lifecycle.py +127 -0
  26. katalyst_taxonomy_cli/commands/lint.py +256 -0
  27. katalyst_taxonomy_cli/commands/plugin.py +148 -0
  28. katalyst_taxonomy_cli/commands/promote.py +95 -0
  29. katalyst_taxonomy_cli/commands/query.py +187 -0
  30. katalyst_taxonomy_cli/commands/relate.py +137 -0
  31. katalyst_taxonomy_cli/commands/relocate.py +129 -0
  32. katalyst_taxonomy_cli/commands/remove.py +95 -0
  33. katalyst_taxonomy_cli/commands/resolve.py +48 -0
  34. katalyst_taxonomy_cli/commands/rollback.py +51 -0
  35. katalyst_taxonomy_cli/commands/self_update.py +530 -0
  36. katalyst_taxonomy_cli/commands/show.py +33 -0
  37. katalyst_taxonomy_cli/commands/status.py +107 -0
  38. katalyst_taxonomy_cli/commands/sync.py +60 -0
  39. katalyst_taxonomy_cli/commands/update.py +112 -0
  40. katalyst_taxonomy_cli/commands/versions.py +54 -0
  41. katalyst_taxonomy_cli/context.py +145 -0
  42. katalyst_taxonomy_cli/discovery.py +157 -0
  43. katalyst_taxonomy_cli/fields.py +70 -0
  44. katalyst_taxonomy_cli/install.py +330 -0
  45. katalyst_taxonomy_cli/options.py +20 -0
  46. katalyst_taxonomy_cli/output.py +92 -0
  47. katalyst_taxonomy_cli/py.typed +0 -0
  48. katalyst_taxonomy_cli-2.0.1a1.dist-info/METADATA +12 -0
  49. katalyst_taxonomy_cli-2.0.1a1.dist-info/RECORD +51 -0
  50. katalyst_taxonomy_cli-2.0.1a1.dist-info/WHEEL +4 -0
  51. katalyst_taxonomy_cli-2.0.1a1.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,96 @@
1
+ """kata tax backend — inspect backends and refresh a remote (github, git) backend's snapshot."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ import click
8
+
9
+ from katalyst_taxonomy_cli.context import CliContext
10
+
11
+
12
+ @click.group("backend")
13
+ def backend() -> None:
14
+ """Backend operations: status, and refreshing a github or git backend."""
15
+
16
+
17
+ def _source(payload: dict[str, Any]) -> str:
18
+ """What the backend reads: ``owner/name`` (github) or the redacted URL (git)."""
19
+ return str(payload.get("repo") or payload.get("url") or "?")
20
+
21
+
22
+ def _render(ctx: CliContext, payload: dict[str, Any], *, heading: str) -> None:
23
+ if ctx.output_format == "json":
24
+ ctx.output.json_out(payload)
25
+ return
26
+ ctx.output.echo(heading)
27
+ # Rendered from the fields the backend's status reports — a git remote is a ``url``,
28
+ # a github repository a ``repo`` — never from its type.
29
+ by_url = "url" in payload
30
+ rows = [
31
+ ("backend", str(payload.get("backend"))),
32
+ ("type", str(payload.get("type"))),
33
+ ("url" if by_url else "repo", _source(payload)),
34
+ (
35
+ "ref",
36
+ str(payload.get("ref") or ("(remote HEAD)" if by_url else "(default branch)")),
37
+ ),
38
+ ("path", str(payload.get("path") or "(repository root)")),
39
+ ("sha", str(payload.get("sha") or "(not fetched)")),
40
+ ("refresh", f"{payload.get('refreshSeconds')}s"),
41
+ ]
42
+ if "depth" in payload:
43
+ rows.append(("depth", "full" if payload.get("depth") == 0 else str(payload.get("depth"))))
44
+ if "auth" in payload:
45
+ rows.append(
46
+ (
47
+ "auth",
48
+ "embedded in the url (redacted)"
49
+ if payload.get("auth") == "url"
50
+ else "git (ssh-agent, ~/.ssh/config, credential helpers)",
51
+ )
52
+ )
53
+ if "tokenSource" in payload:
54
+ rows.append(("token", str(payload.get("tokenSource"))))
55
+ if "changed" in payload:
56
+ rows.append(("changed", "yes" if payload["changed"] else "no"))
57
+ if payload.get("lastError"):
58
+ rows.append(("last error", str(payload["lastError"])))
59
+ ctx.output.key_value(rows)
60
+
61
+
62
+ @backend.command("refresh")
63
+ @click.argument("name")
64
+ @click.pass_obj
65
+ def refresh(ctx: CliContext, name: str) -> None:
66
+ """Re-check github or git backend NAME's ref now, fetching the new tree if it moved.
67
+
68
+ A remote backend serves a cached snapshot and re-checks its ref once its
69
+ ``refresh`` window passes; this re-checks immediately. Nothing is written to the
70
+ repository, the remote or the configuration.
71
+ """
72
+ from katalyst_taxonomy.adapters.orchestration import refresh_backend
73
+
74
+ try:
75
+ payload = refresh_backend(ctx.cwd, name, profile=ctx.profile)
76
+ except ValueError as exc:
77
+ raise click.ClickException(str(exc)) from exc
78
+ sha = str(payload.get("sha") or "")[:12]
79
+ verb = "updated to" if payload.get("changed") else "unchanged at"
80
+ _render(ctx, payload, heading=f"Refreshed {name}: {_source(payload)} {verb} {sha}")
81
+
82
+
83
+ @backend.command("status")
84
+ @click.argument("name")
85
+ @click.pass_obj
86
+ def status(ctx: CliContext, name: str) -> None:
87
+ """Show what github or git backend NAME is serving, without fetching."""
88
+ from katalyst_taxonomy.adapters.orchestration import refreshable_backend
89
+
90
+ from .._wiring import load_registry
91
+
92
+ try:
93
+ inner = refreshable_backend(load_registry(ctx), name)
94
+ except ValueError as exc:
95
+ raise click.ClickException(str(exc)) from exc
96
+ _render(ctx, inner.status(), heading=f"Backend {name}")
@@ -0,0 +1,106 @@
1
+ """kata tax bundle — manage schema bundles installed from a source (add / list / remove)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import click
6
+
7
+ from katalyst_taxonomy_cli._wiring import create_bundle_service
8
+ from katalyst_taxonomy_cli.context import CliContext
9
+
10
+
11
+ @click.group("bundle")
12
+ def bundle() -> None:
13
+ """Manage schema bundles installed from a source.
14
+
15
+ Bundles are fetched from PyPI, git, GitHub, or a local path into the shared source
16
+ cache, then path-imported and registered into the taxonomy at runtime. The pinned
17
+ source (an exact commit or version) is recorded in config.yaml's spec.schemas, so
18
+ every process — and every machine with that config — loads the same bundle.
19
+ """
20
+
21
+
22
+ @bundle.command("add")
23
+ @click.argument("source_uri")
24
+ @click.option("-y", "--yes", is_flag=True, help="Skip the confirmation prompt.")
25
+ @click.pass_obj
26
+ def add_bundle(ctx: CliContext, source_uri: str, yes: bool) -> None:
27
+ """Install a schema bundle from SOURCE_URI.
28
+
29
+ SOURCE_URI may be:
30
+
31
+ pypi:<name>[==<version>] e.g. pypi:acme-bundle==1.2.0
32
+
33
+ git:<url>[@<ref>] e.g. git:git@github.com:acme/b.git@v1
34
+
35
+ github:<owner>/<repo>[@<ref>] e.g. github:acme/bundle@v1.0.0
36
+
37
+ file://<path> or a local path
38
+
39
+ git:, github: and file:// take an optional trailing #path=<sub/dir> for a
40
+ bundle in a subdirectory (monorepo), e.g. github:acme/mono@v2#path=bundles/acme.
41
+ A private github: repository reads GITHUB_TOKEN / GH_TOKEN, then `gh auth token`.
42
+
43
+ A git:/github: ref is pinned to its commit and a pypi: name to its version in
44
+ config.yaml. Installing executes the bundle's Python at load time. Only bundles
45
+ that depend solely on katalyst-engine are accepted.
46
+ """
47
+ from katalyst_taxonomy.services.bundle_service import install_bundle
48
+
49
+ if not yes:
50
+ click.echo(
51
+ "Installing a remote bundle path-imports and executes its Python code.\n"
52
+ f"Source: {source_uri}"
53
+ )
54
+ if not click.confirm("Proceed?", default=False):
55
+ ctx.output.echo("Aborted.")
56
+ raise SystemExit(1)
57
+
58
+ try:
59
+ result = install_bundle(create_bundle_service(), source_uri)
60
+ except Exception as exc: # noqa: BLE001
61
+ ctx.output.echo(f"Error: {exc}")
62
+ raise SystemExit(1) from exc
63
+
64
+ kinds = ", ".join(result.provided_kinds) or "(none)"
65
+ ctx.output.echo(
66
+ f"Installed bundle '{result.fqn}' v{result.version}\n"
67
+ f" source: {result.resolved_source}\n"
68
+ f" kinds: {kinds}"
69
+ )
70
+
71
+
72
+ @bundle.command("list")
73
+ @click.pass_obj
74
+ def list_bundles(ctx: CliContext) -> None:
75
+ """List schema bundles declared with a source in config.yaml."""
76
+ from katalyst_taxonomy.services.source_providers import source_bundle_infos
77
+ from katalyst_taxonomy.sources.bundle_sources import shown_source
78
+ from katalyst_taxonomy.sources.cache import is_pinned
79
+
80
+ bundles = [i for i in source_bundle_infos(ctx.profile) if i.state != "not-a-bundle"]
81
+ if not bundles:
82
+ ctx.output.echo("No schema bundles installed from a source.")
83
+ return
84
+ ctx.output.echo(f"Schema bundles from sources ({len(bundles)}):")
85
+ for b in bundles:
86
+ version = f" v{b.version}" if b.version else ""
87
+ kinds = ", ".join(b.provided_kinds) or "(none)"
88
+ pin = "pinned" if is_pinned(b.source) else "unpinned"
89
+ ctx.output.echo(
90
+ f" {b.name or b.fqn or '(unnamed)'}{version} [{shown_source(b.source)}] "
91
+ f"{pin}, {b.state} kinds: {kinds}"
92
+ )
93
+
94
+
95
+ @bundle.command("remove")
96
+ @click.argument("name")
97
+ @click.pass_obj
98
+ def remove_bundle(ctx: CliContext, name: str) -> None:
99
+ """Remove a schema bundle installed from a source, by name or FQN."""
100
+ from katalyst_taxonomy.services.bundle_service import remove_bundle as remove
101
+
102
+ result = remove(name)
103
+ if not result.success:
104
+ ctx.output.echo(f"Error: {result.error}")
105
+ raise SystemExit(1)
106
+ ctx.output.echo(f"Removed bundle '{result.name}' ({result.source_uri}).")
@@ -0,0 +1,68 @@
1
+ """kata tax clone — Clone an existing taxonomy node."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import click
6
+
7
+ from katalyst_taxonomy_cli.context import CliContext
8
+
9
+
10
+ @click.command("clone")
11
+ @click.argument("node_type")
12
+ @click.argument("source_name")
13
+ @click.argument("target_name")
14
+ @click.option("--source-system", default=None, help="Source system name.")
15
+ @click.option("--source-subsystem", default=None, help="Source subsystem name.")
16
+ @click.option("--source-stack", default=None, help="Source stack name.")
17
+ @click.option("--target-system", default=None, help="Target system name.")
18
+ @click.option("--target-subsystem", default=None, help="Target subsystem name.")
19
+ @click.option("--target-stack", default=None, help="Target stack name.")
20
+ @click.option("--description", default=None, help="New description for cloned node.")
21
+ @click.option("-y", "--yes", "non_interactive", is_flag=True, help="Non-interactive mode.")
22
+ @click.option(
23
+ "--backend",
24
+ "backend",
25
+ default=None,
26
+ help=(
27
+ "Filesystem backend (repository) to clone within. Defaults to the profile's only "
28
+ "filesystem backend, else the one the current directory is inside."
29
+ ),
30
+ )
31
+ @click.pass_obj
32
+ def clone(
33
+ ctx: CliContext,
34
+ node_type: str,
35
+ source_name: str,
36
+ target_name: str,
37
+ source_system: str | None,
38
+ source_subsystem: str | None,
39
+ source_stack: str | None,
40
+ target_system: str | None,
41
+ target_subsystem: str | None,
42
+ target_stack: str | None,
43
+ description: str | None,
44
+ non_interactive: bool,
45
+ backend: str | None,
46
+ ) -> None:
47
+ """Clone an existing taxonomy node to a new name, within one repository."""
48
+ from katalyst_taxonomy.adapters.orchestration import run_clone
49
+ from katalyst_taxonomy.services.permissions import refuse_read_only_addresses
50
+
51
+ # A source or target in a read-only backend (github, git) is refused before any
52
+ # repository is chosen: naming one is the error, not an ambiguity.
53
+ refuse_read_only_addresses(ctx.cwd, "clone", source_name, target_name, profile=ctx.profile)
54
+ exit_code = run_clone(
55
+ path=ctx.repository(backend).root,
56
+ node_type=node_type,
57
+ source_name=source_name,
58
+ target_name=target_name,
59
+ source_system=source_system,
60
+ source_stack=source_stack,
61
+ target_system=target_system,
62
+ target_stack=target_stack,
63
+ description=description,
64
+ yes=non_interactive,
65
+ output=None,
66
+ err_output=None,
67
+ )
68
+ raise SystemExit(exit_code)