Skip to content

Commit 3f7638f

Browse files
author
Théo LAGACHE
committed
chore(release): 26.01.2b4
1 parent d69da03 commit 3f7638f

6 files changed

Lines changed: 91 additions & 15 deletions

File tree

CITATION.cff

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@ keywords:
2222
- management
2323
- integration
2424
license: Apache-2.0
25-
version: 26.01.2b3
25+
version: 26.01.2b4
2626
date-released: "2026-01-15"

commands/config.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import typer
2+
from core.utils import console
3+
from core.config import set_config_value, get_config_value
4+
5+
app = typer.Typer(help="Manage global CLI configuration.")
6+
7+
@app.command()
8+
def channel(
9+
name: str = typer.Argument(..., help="Update channel name (stable or beta)")
10+
):
11+
name = name.lower()
12+
if name not in ["stable", "beta"]:
13+
console.print("[danger]✖ Invalid channel. Choose either 'stable' or 'beta'.[/danger]")
14+
raise typer.Exit(1)
15+
16+
set_config_value("update_channel", name)
17+
console.print(f"[success]✔ Update channel set to: [bold]{name}[/bold][/success]")
18+
19+
@app.command()
20+
def show():
21+
channel = get_config_value("update_channel", "auto (based on current version)")
22+
console.print(f"[info]Current Configuration:[/info]")
23+
console.print(f" [bold]Update Channel:[/bold] {channel}")

core/config.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
from pathlib import Path
55

66
TEMPLATE_BASE_URL = "https://s3.eu-central-3.ionoscloud.com/portabase-software/cli/public/templates/"
7+
GLOBAL_CONFIG_DIR = Path.home() / ".portabase"
8+
GLOBAL_CONFIG_FILE = GLOBAL_CONFIG_DIR / "config.json"
79

810
def write_file(path: Path, content: str):
911
path.parent.mkdir(parents=True, exist_ok=True)
@@ -26,6 +28,29 @@ def write_env_file(work_dir: Path, env_vars: dict):
2628
content += f'{k}="{v}"\n'
2729
write_file(env_path, content)
2830

31+
def load_global_config() -> dict:
32+
if not GLOBAL_CONFIG_FILE.exists():
33+
return {}
34+
try:
35+
with open(GLOBAL_CONFIG_FILE, "r") as f:
36+
return json.load(f)
37+
except:
38+
return {}
39+
40+
def save_global_config(config: dict):
41+
GLOBAL_CONFIG_DIR.mkdir(parents=True, exist_ok=True)
42+
with open(GLOBAL_CONFIG_FILE, "w") as f:
43+
json.dump(config, f, indent=2)
44+
45+
def get_config_value(key: str, default=None):
46+
config = load_global_config()
47+
return config.get(key, default)
48+
49+
def set_config_value(key: str, value):
50+
config = load_global_config()
51+
config[key] = value
52+
save_global_config(config)
53+
2954
def load_db_config(path: Path) -> dict:
3055
json_path = path / "databases.json"
3156
if not json_path.exists():

core/updater.py

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,16 @@
99
import typer
1010
from pathlib import Path
1111
from core.utils import current_version, console
12+
from core.config import get_config_value
1213

1314
GITHUB_REPO = "Portabase/cli"
14-
GITHUB_API_URL = f"https://api.github.com/repos/{GITHUB_REPO}/releases/latest"
15+
GITHUB_API_BASE_URL = f"https://api.github.com/repos/{GITHUB_REPO}/releases"
1516
CACHE_FILE = Path.home() / ".portabase" / "update_cache.json"
1617

18+
def is_prerelease(version: str) -> bool:
19+
v = version.lower()
20+
return any(x in v for x in ['a', 'b', 'rc', 'alpha', 'beta'])
21+
1722
def get_platform_info():
1823
system = platform.system().lower()
1924
if system == "darwin":
@@ -28,11 +33,17 @@ def get_platform_info():
2833

2934
return system, arch
3035

31-
def get_latest_release_data():
36+
def get_latest_release_data(pre=False):
3237
try:
33-
response = requests.get(GITHUB_API_URL, timeout=5)
34-
response.raise_for_status()
35-
return response.json()
38+
if not pre:
39+
response = requests.get(f"{GITHUB_API_BASE_URL}/latest", timeout=5)
40+
response.raise_for_status()
41+
return response.json()
42+
else:
43+
response = requests.get(GITHUB_API_BASE_URL, timeout=5)
44+
response.raise_for_status()
45+
releases = response.json()
46+
return releases[0] if releases else None
3647
except Exception:
3748
return None
3849

@@ -41,6 +52,15 @@ def check_for_updates(force=False):
4152
return None
4253

4354
current = current_version()
55+
if current == "unknown":
56+
return None
57+
58+
channel = get_config_value("update_channel")
59+
if channel:
60+
include_pre = (channel == "beta")
61+
else:
62+
include_pre = is_prerelease(current)
63+
4464
latest_tag = None
4565

4666
try:
@@ -54,7 +74,7 @@ def check_for_updates(force=False):
5474
pass
5575

5676
if latest_tag is None:
57-
data = get_latest_release_data()
77+
data = get_latest_release_data(pre=include_pre)
5878
if data:
5979
latest_tag = data.get("tag_name", "").lstrip('v')
6080
try:
@@ -63,7 +83,7 @@ def check_for_updates(force=False):
6383
except Exception:
6484
pass
6585

66-
if not latest_tag or current == "unknown":
86+
if not latest_tag:
6787
return None
6888

6989
if latest_tag != current:
@@ -78,28 +98,35 @@ def update_cli():
7898
console.print("[info]If you installed via source, please use [bold]git pull[/bold] to update.[/info]")
7999
return
80100

81-
data = get_latest_release_data()
101+
current = current_version()
102+
103+
channel = get_config_value("update_channel")
104+
if channel:
105+
pre = (channel == "beta")
106+
else:
107+
pre = is_prerelease(current) if current != "unknown" else False
108+
109+
data = get_latest_release_data(pre=pre)
82110
if not data:
83111
console.print("[danger]✖ Could not fetch latest release data from GitHub.[/danger]")
84112
return
85113

86114
latest_tag = data.get("tag_name", "").lstrip('v')
87-
current = current_version()
88115

89116
if latest_tag == current:
90117
console.print(f"[success]✔ Portabase CLI is already up to date ({current}).[/success]")
91118
return
92119

93120
try:
94-
if latest_tag < current and not (".rc" in current and not ".rc" in latest_tag):
121+
if latest_tag < current and not (is_prerelease(current) and not is_prerelease(latest_tag)):
95122
console.print(f"[warning]⚠ Latest remote version ({latest_tag}) appears to be older than current ({current}).[/warning]")
96123
if not typer.confirm("Do you want to continue with the update (downgrade)?"):
97124
return
98125
except Exception:
99126
pass
100127

101128
system, arch = get_platform_info()
102-
asset_name = f"portabase_{system}_{arch}"
129+
asset_name = f"portabase_{{system}}_{{arch}}"
103130
if system == "windows":
104131
asset_name += ".exe"
105132

@@ -162,4 +189,4 @@ def update_cli():
162189
except Exception as e:
163190
console.print(f"[danger]✖ An error occurred during update: {e}[/danger]")
164191
if 'temp_file' in locals() and temp_file.exists():
165-
temp_file.unlink()
192+
temp_file.unlink()

main.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import typer
22
from typing import Optional
3-
from commands import agent, dashboard, common, db
3+
from commands import agent, dashboard, common, db, config
44
from core.utils import console, current_version
55
from core.updater import check_for_updates, update_cli
66

@@ -39,6 +39,7 @@ def update():
3939
app.command()(common.uninstall)
4040

4141
app.add_typer(db.app, name="db")
42+
app.add_typer(config.app, name="config")
4243

4344
if __name__ == "__main__":
4445
app()

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "portabase-cli"
3-
version = "26.01.2b3"
3+
version = "26.01.2b4"
44
description = "The official command line interface (CLI) for managing and deploying Portabase instances with ease."
55
readme = "README.md"
66
requires-python = ">=3.12"

0 commit comments

Comments
 (0)