Skip to content

Commit cb4518a

Browse files
committed
Add commodore version command
This command prints extended Commodore version information including the Kapitan, gojsonnet and reclass-rs versions, and the path and version of the required external tools `helm`, `jb` and `kustomize`.
1 parent 56c8526 commit cb4518a

4 files changed

Lines changed: 192 additions & 7 deletions

File tree

commodore/cli/__init__.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from dotenv import load_dotenv, find_dotenv
1212
from commodore import __git_version__, __version__
1313
from commodore.config import Config
14+
from commodore.version import version_info
1415

1516
import commodore.cli.options as options
1617

@@ -30,6 +31,16 @@ def _version():
3031
CONTEXT_SETTINGS = {"help_option_names": ["-h", "--help"]}
3132

3233

34+
@click.command(name="version", short_help="Extended Commodore version information")
35+
@options.pass_config
36+
def commodore_version(config: Config):
37+
"""Print extended Commodore version information.
38+
39+
This command returns exit code 127 if a required external dependency (helm,
40+
kustomize, jb) can't be found in the PATH."""
41+
version_info(config, _version())
42+
43+
3344
@click.group(context_settings=CONTEXT_SETTINGS)
3445
@click.version_option(_version(), prog_name="commodore")
3546
@options.verbosity
@@ -66,6 +77,7 @@ def commodore(ctx, working_dir, verbose, request_timeout):
6677
commodore.add_command(package_group)
6778
commodore.add_command(commodore_login)
6879
commodore.add_command(commodore_fetch_token)
80+
commodore.add_command(commodore_version)
6981

7082

7183
def main():

commodore/version.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
"""Extended Commodore version information"""
2+
3+
import os
4+
import subprocess # nosec
5+
import shutil
6+
import sys
7+
8+
from importlib import metadata
9+
10+
import click
11+
import reclass_rs
12+
13+
from commodore.config import Config
14+
15+
from pygobuildinfo import get_go_build_info
16+
17+
18+
def _native_find_so(dep) -> os.PathLike[str]:
19+
files = metadata.files(dep)
20+
if not files:
21+
raise ValueError(
22+
f"Unable to parse build info for {dep}: no package files found"
23+
)
24+
so_files = [p.locate() for p in files if p.name.endswith(".so")]
25+
if len(so_files) != 1:
26+
raise ValueError(f"Unable to parse build info for {dep}: no unique *.so found")
27+
return so_files[0]
28+
29+
30+
def _gojsonnet_buildinfo():
31+
try:
32+
so_file = _native_find_so("gojsonnet")
33+
except ValueError as e:
34+
return str(e)
35+
gobuildinfo = get_go_build_info(str(so_file))
36+
return f"Go compiler: {gobuildinfo['GoVersion']}"
37+
38+
39+
def _reclass_rs_buildinfo():
40+
if hasattr(reclass_rs, "buildinfo"):
41+
buildinfo = reclass_rs.buildinfo()
42+
return f"Rust compiler: {buildinfo['rustc_version']}"
43+
# For reclass_rs 0.8.0 and older, we just return an informational message
44+
return f"Parsing build info not supported for reclass-rs <= 0.8.0"
45+
46+
47+
_buildinfo = {
48+
"gojsonnet": _gojsonnet_buildinfo,
49+
"reclass-rs": _reclass_rs_buildinfo,
50+
"kapitan": lambda: "",
51+
}
52+
53+
54+
def _get_tool_info(tool) -> tuple[str, bool]:
55+
tool_path = shutil.which(tool)
56+
if not tool_path:
57+
return "NOT FOUND IN PATH", False
58+
59+
version_arg = {
60+
"jb": ["--version"],
61+
"helm": ["version", "--template", "{{.Version}}"],
62+
"kustomize": ["version"],
63+
}
64+
tool_version = (
65+
subprocess.run(
66+
[tool_path] + version_arg[tool],
67+
stderr=subprocess.STDOUT,
68+
stdout=subprocess.PIPE,
69+
)
70+
.stdout.decode("utf-8")
71+
.strip()
72+
)
73+
return f"{tool_path}, version: {tool_version}", True
74+
75+
76+
def version_info(config: Config, version: str):
77+
exit_code = 0
78+
click.secho(f"Commodore {version}", bold=True)
79+
click.echo("")
80+
click.secho("Core dependency versions", bold=True)
81+
for dep in ["kapitan", "gojsonnet", "reclass-rs"]:
82+
dep_ver = metadata.version(dep)
83+
dep_buildinfo = _buildinfo[dep]()
84+
if dep_buildinfo:
85+
dep_buildinfo = f", build info: {dep_buildinfo}"
86+
click.echo(f"{dep}: {dep_ver}{dep_buildinfo}")
87+
click.echo("")
88+
click.secho("External tool versions", bold=True)
89+
for tool in ["helm", "jb", "kustomize"]:
90+
tool_info, found = _get_tool_info(tool)
91+
fgcolor = None
92+
bold = False
93+
if not found:
94+
fgcolor = "red"
95+
bold = True
96+
exit_code = 127
97+
click.secho(f"{tool}: {tool_info}", fg=fgcolor, bold=bold)
98+
sys.exit(exit_code)

poetry.lock

Lines changed: 81 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pyjwt = "2.10.1"
4343
PyGithub = "2.6.1"
4444
reclass-rs = "0.9.0"
4545
gojsonnet = "0.21.0"
46+
pygobuildinfo = "0.1.25"
4647

4748
[tool.poetry.dev-dependencies]
4849
tox = "3.28.0"

0 commit comments

Comments
 (0)