Skip to content
This repository was archived by the owner on Jan 23, 2026. It is now read-only.

Commit 9e52283

Browse files
authored
Merge pull request #479 from jumpstarter-dev/backport-478-to-release-0.6
2 parents 99c4cc5 + 2948c28 commit 9e52283

6 files changed

Lines changed: 117 additions & 23 deletions

File tree

docs/source/conf.py

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,18 @@
66
# -- Project information -----------------------------------------------------
77
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
88

9+
import asyncio
910
import os
1011
import sys
1112

12-
import requests
13+
from jumpstarter_cli_admin.controller import get_latest_compatible_controller_version
1314

1415
sys.path.insert(0, os.path.abspath("../.."))
1516

1617
project = "jumpstarter"
1718
copyright = "2025, Jumpstarter Contributors"
1819
author = "Jumpstarter Contributors"
1920

20-
controller_version = requests.get(
21-
"https://quay.io/api/v1/repository/jumpstarter-dev/helm/jumpstarter/tag/", params={"limit": 1}
22-
).json()["tags"][0]["name"]
23-
2421
# -- General configuration ---------------------------------------------------
2522
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
2623

@@ -54,14 +51,36 @@
5451
html_favicon = "_static/img/favicon.png"
5552
html_show_sphinx = False
5653

54+
55+
def get_controller_version():
56+
name = os.getenv("SPHINX_MULTIVERSION_NAME")
57+
if name == "main" or name is None:
58+
version = None
59+
elif name.startswith("release-"):
60+
version = name.removeprefix("release-")
61+
else:
62+
version = None
63+
64+
return asyncio.run(get_latest_compatible_controller_version(client_version=version))
65+
66+
67+
def get_index_url():
68+
name = os.getenv("SPHINX_MULTIVERSION_NAME")
69+
if name is None:
70+
return "https://pkg.jumpstarter.dev/simple"
71+
else:
72+
return "https://pkg.jumpstarter.dev/{}/simple".format(name)
73+
74+
5775
myst_heading_anchors = 3
5876
myst_enable_extensions = [
5977
"substitution",
6078
]
6179
myst_substitutions = {
6280
"requires_python": ">=3.11",
6381
"version": "latest",
64-
"controller_version": controller_version,
82+
"controller_version": get_controller_version(),
83+
"index_url": get_index_url(),
6584
}
6685

6786
doctest_test_doctest_blocks = ""
@@ -91,10 +110,11 @@
91110
# This replaces the custom bash script approach with built-in functionality
92111

93112
# Tags pattern for html_context["versions"]
94-
smv_tag_whitelist = r"^v(0\.[5-9](\.\d+)|0\.[1-9][0-9]+(\.\d+)|[1-9]\d*\.\d+\.\d+)$" # Starting from v0.5.0
95-
smv_branch_whitelist = r"^(main|master)$" # Only include main/master branch
96-
smv_remote_whitelist = None
97-
smv_released_pattern = r"^v[0-9]+\.[0-9]+\.[0-9]+$" # Tags that are considered releases
113+
smv_tag_whitelist = r"$^" # Ignore all tags
114+
smv_branch_whitelist = r"^(main|release-\d+\.\d+)$" # Include all release branches and main
115+
smv_remote_whitelist = r'^(origin|upstream)$' # Include branches from origin and upstream
116+
smv_prefer_remote_refs = True
117+
# smv_released_pattern = r"^v[0-9]+\.[0-9]+\.[0-9]+$" # Tags that are considered releases
98118
smv_outputdir_format = "{ref.name}" # Directory name format
99119

100120
# Ensure static files are copied to all versions

docs/source/getting-started/installation/packages.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,21 @@ tools you need to run an exporter or interact with your hardware as a client.
2020
Install the Python package using `pip` or a similar tool. You need Python
2121
{{requires_python}}:
2222

23-
```shell
24-
$ pip3 install --extra-index-url https://pkg.jumpstarter.dev/simple/ jumpstarter-all
23+
```{code-block} shell
24+
:substitutions:
25+
$ pip3 install --extra-index-url {{index_url}} jumpstarter-all
2526
$ mkdir -p "${HOME}/.config/jumpstarter/"
2627
$ sudo mkdir /etc/jumpstarter
2728
```
2829

2930
The command above installs packages globally. For library usage, we recommend
3031
installing in a virtual environment instead:
3132

32-
```shell
33+
```{code-block} shell
34+
:substitutions:
3335
$ python3 -m venv ~/.venv/jumpstarter
3436
$ source ~/.venv/jumpstarter/bin/activate
35-
$ pip3 install --extra-index-url https://pkg.jumpstarter.dev/simple/ jumpstarter-all
37+
$ pip3 install --extra-index-url {{index_url}} jumpstarter-all
3638
```
3739

3840
Additional package indexes are available, this is a complete list of our indexes:
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import aiohttp
2+
import semver
3+
from jumpstarter_cli_common.version import get_client_version
4+
from packaging.version import Version
5+
6+
7+
async def get_latest_compatible_controller_version(
8+
client_version: str | None = None,
9+
):
10+
if client_version is None:
11+
client_version = Version(get_client_version())
12+
else:
13+
client_version = Version(client_version)
14+
15+
async with aiohttp.ClientSession(
16+
raise_for_status=True,
17+
) as session:
18+
try:
19+
async with session.get(
20+
"https://quay.io/api/v1/repository/jumpstarter-dev/helm/jumpstarter/tag/",
21+
timeout=aiohttp.ClientTimeout(total=30),
22+
) as resp:
23+
resp = await resp.json()
24+
except Exception as e:
25+
raise RuntimeError(f"Failed to fetch controller versions: {e}") from e
26+
27+
compatible = set()
28+
fallback = set()
29+
30+
if not isinstance(resp, dict) or "tags" not in resp or not isinstance(resp["tags"], list):
31+
raise RuntimeError("Unexpected response fetching controller version")
32+
33+
for tag in resp["tags"]:
34+
if not isinstance(tag, dict) or "name" not in tag:
35+
continue # Skip malformed tag entries
36+
37+
try:
38+
version = semver.VersionInfo.parse(tag["name"])
39+
except ValueError:
40+
continue # ignore invalid versions
41+
42+
if version.major == client_version.major and version.minor == client_version.minor:
43+
compatible.add(version)
44+
else:
45+
fallback.add(version)
46+
47+
if compatible:
48+
selected = max(compatible)
49+
elif fallback:
50+
selected = max(fallback)
51+
else:
52+
raise ValueError("No valid controller versions found in the repository")
53+
54+
return str(selected)

packages/jumpstarter-cli-admin/jumpstarter_cli_admin/install.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,12 @@
22

33
import asyncclick as click
44
from jumpstarter_cli_common.opt import opt_context, opt_kubeconfig
5-
from jumpstarter_cli_common.version import get_client_version
65
from jumpstarter_kubernetes import helm_installed, install_helm_chart
76

7+
from .controller import get_latest_compatible_controller_version
88
from jumpstarter.common.ipaddr import get_ip_address
99

1010

11-
def get_chart_version() -> str:
12-
client_version = get_client_version()
13-
parts = client_version.split(".")
14-
return f"{parts[0].replace('v', '')}.{parts[1]}.{parts[2]}"
15-
16-
1711
@click.command
1812
@click.option("--helm", type=str, help="Path or name of a helm executable", default="helm")
1913
@click.option("--name", type=str, help="The name of the chart installation", default="jumpstarter")
@@ -34,7 +28,7 @@ def get_chart_version() -> str:
3428
@click.option("--nodeport", "mode", flag_value="nodeport", help="Use Nodeport routing (recommended)", default=True)
3529
@click.option("--ingress", "mode", flag_value="ingress", help="Use a Kubernetes ingress")
3630
@click.option("--route", "mode", flag_value="route", help="Use an OpenShift route")
37-
@click.option("-v", "--version", help="The version of the service to install", default=get_chart_version())
31+
@click.option("-v", "--version", help="The version of the service to install", default=None)
3832
@opt_kubeconfig
3933
@opt_context
4034
async def install(
@@ -69,6 +63,9 @@ async def install(
6963
if router_endpoint is None:
7064
router_endpoint = f"router.{basedomain}:8083"
7165

66+
if version is None:
67+
version = await get_latest_compatible_controller_version()
68+
7269
click.echo(f'Installing Jumpstarter service v{version} in namespace "{namespace}" with Helm\n')
7370
click.echo(f"Chart URI: {chart}")
7471
click.echo(f"Chart Version: {version}")

packages/jumpstarter-cli-admin/pyproject.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,13 @@ authors = [{ name = "Kirk Brauer", email = "kbrauer@hatci.com" }]
66
readme = "README.md"
77
license = "Apache-2.0"
88
requires-python = ">=3.11"
9-
dependencies = ["jumpstarter-cli-common", "jumpstarter-kubernetes"]
9+
dependencies = [
10+
"aiohttp>=3.11.18",
11+
"jumpstarter-cli-common",
12+
"jumpstarter-kubernetes",
13+
"packaging>=25.0",
14+
"semver~=2.13",
15+
]
1016

1117
[dependency-groups]
1218
dev = [

uv.lock

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

0 commit comments

Comments
 (0)