Mark WilkensXL build versions
Some checks failed
Container Image / build-and-push (push) Has been cancelled
Some checks failed
Container Image / build-and-push (push) Has been cancelled
This commit is contained in:
19
app.py
19
app.py
@@ -924,8 +924,23 @@ async def serve_login(request: Request):
|
||||
|
||||
@app.get("/api/version")
|
||||
async def get_version():
|
||||
from core.constants import APP_VERSION
|
||||
return {"version": APP_VERSION}
|
||||
from core.constants import (
|
||||
APP_VERSION,
|
||||
BUILD_FLAVOR,
|
||||
BUILD_REVISION,
|
||||
BUILD_VERSION,
|
||||
FULL_VERSION,
|
||||
UPSTREAM_VERSION,
|
||||
)
|
||||
return {
|
||||
"version": BUILD_VERSION,
|
||||
"upstream_version": UPSTREAM_VERSION,
|
||||
"app_version": APP_VERSION,
|
||||
"build_flavor": BUILD_FLAVOR,
|
||||
"build_revision": BUILD_REVISION,
|
||||
"build_version": BUILD_VERSION,
|
||||
"full_version": FULL_VERSION,
|
||||
}
|
||||
|
||||
@app.get("/api/health")
|
||||
async def health_check() -> Dict[str, str]:
|
||||
|
||||
36
docs/wilkensxl-build.md
Normal file
36
docs/wilkensxl-build.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# WilkensXL build versioning
|
||||
|
||||
Odysseus keeps the upstream application version separate from the local
|
||||
WilkensXL build version.
|
||||
|
||||
- `APP_VERSION` and `UPSTREAM_VERSION` track the upstream release.
|
||||
- `BUILD_VERSION` and `FULL_VERSION` identify this custom image.
|
||||
- `/api/version` returns both values so Dockge, logs, and the UI can show which
|
||||
build is running.
|
||||
|
||||
The default custom build is:
|
||||
|
||||
```text
|
||||
1.0.1-wilkensxl.2
|
||||
```
|
||||
|
||||
The value can be overridden at runtime with:
|
||||
|
||||
- `ODYSSEUS_BUILD_FLAVOR`
|
||||
- `ODYSSEUS_BUILD_REVISION`
|
||||
- `ODYSSEUS_BUILD_VERSION`
|
||||
|
||||
## Update workflow
|
||||
|
||||
When upstream publishes a new Odysseus version:
|
||||
|
||||
1. Merge or rebase the upstream changes into the WilkensXL branch.
|
||||
2. Keep the addon loader small and stable.
|
||||
3. Put local behavior changes into addons wherever possible.
|
||||
4. Run the addon, integration, readiness, and version metadata tests.
|
||||
5. Bump `BUILD_REVISION` or set `ODYSSEUS_BUILD_VERSION` for the new image.
|
||||
|
||||
The loader does not remove all porting work, but it reduces it. Most local
|
||||
behavior should live behind addon manifests, so future upstream updates only
|
||||
need the loader compatibility checked plus any addons that touch changed
|
||||
internals.
|
||||
@@ -5,6 +5,14 @@ import os
|
||||
from src.runtime_paths import get_app_root, get_default_data_dir
|
||||
|
||||
APP_VERSION = "1.0.1"
|
||||
UPSTREAM_VERSION = APP_VERSION
|
||||
BUILD_FLAVOR = os.getenv("ODYSSEUS_BUILD_FLAVOR", "wilkensxl")
|
||||
BUILD_REVISION = os.getenv("ODYSSEUS_BUILD_REVISION", "2")
|
||||
BUILD_VERSION = os.getenv(
|
||||
"ODYSSEUS_BUILD_VERSION",
|
||||
f"{APP_VERSION}-{BUILD_FLAVOR}.{BUILD_REVISION}" if BUILD_FLAVOR else APP_VERSION,
|
||||
)
|
||||
FULL_VERSION = BUILD_VERSION
|
||||
|
||||
# Base paths
|
||||
BASE_DIR = os.path.join(get_app_root(), "")
|
||||
|
||||
@@ -19,7 +19,13 @@ def check_readiness() -> Dict[str, object]:
|
||||
``local_first`` is informational — a remote database is a valid deployment, so
|
||||
it never fails readiness, it only reports whether storage stays on this host.
|
||||
"""
|
||||
from core.constants import APP_VERSION, DATA_DIR
|
||||
from core.constants import (
|
||||
APP_VERSION,
|
||||
BUILD_FLAVOR,
|
||||
BUILD_VERSION,
|
||||
DATA_DIR,
|
||||
UPSTREAM_VERSION,
|
||||
)
|
||||
from core.database import DATABASE_URL, engine
|
||||
from sqlalchemy import text as sql_text
|
||||
|
||||
@@ -55,7 +61,11 @@ def check_readiness() -> Dict[str, object]:
|
||||
ready = all(bool(c.get("ok")) for c in checks.values())
|
||||
return {
|
||||
"ready": ready,
|
||||
"version": APP_VERSION,
|
||||
"version": BUILD_VERSION,
|
||||
"upstream_version": UPSTREAM_VERSION,
|
||||
"app_version": APP_VERSION,
|
||||
"build_flavor": BUILD_FLAVOR,
|
||||
"build_version": BUILD_VERSION,
|
||||
"checks": checks,
|
||||
"timestamp": datetime.utcnow().isoformat(),
|
||||
}
|
||||
|
||||
@@ -994,7 +994,10 @@
|
||||
el.textContent = 'Type /setup, then choose Local models or API.';
|
||||
}
|
||||
fetch('/api/version').then(function(r){return r.json()}).then(function(d){
|
||||
if (d.version) window._appVersion = d.version;
|
||||
var fullVersion = d.full_version || d.build_version || d.version;
|
||||
if (fullVersion) window._appVersion = fullVersion;
|
||||
if (d.upstream_version) window._upstreamVersion = d.upstream_version;
|
||||
if (d.build_flavor) window._buildFlavor = d.build_flavor;
|
||||
}).catch(function(){});
|
||||
})();
|
||||
</script>
|
||||
|
||||
@@ -305,7 +305,11 @@
|
||||
const vr = await fetch('/api/version');
|
||||
if (vr.ok) {
|
||||
const vd = await vr.json();
|
||||
document.getElementById('version-label').textContent = 'v' + vd.version;
|
||||
const version = vd.full_version || vd.build_version || vd.version;
|
||||
const upstream = vd.upstream_version && vd.upstream_version !== version
|
||||
? ' (upstream ' + vd.upstream_version + ')'
|
||||
: '';
|
||||
document.getElementById('version-label').textContent = version ? 'v' + version + upstream : '';
|
||||
}
|
||||
} catch(e) {}
|
||||
|
||||
|
||||
@@ -6,7 +6,20 @@ from src.readiness import check_readiness
|
||||
def test_readiness_reports_core_subsystems():
|
||||
result = check_readiness()
|
||||
|
||||
assert {"ready", "version", "checks", "timestamp"}.issubset(result.keys())
|
||||
assert {
|
||||
"ready",
|
||||
"version",
|
||||
"upstream_version",
|
||||
"app_version",
|
||||
"build_flavor",
|
||||
"build_version",
|
||||
"checks",
|
||||
"timestamp",
|
||||
}.issubset(result.keys())
|
||||
assert result["upstream_version"] == "1.0.1"
|
||||
assert result["app_version"] == result["upstream_version"]
|
||||
assert result["build_flavor"] == "wilkensxl"
|
||||
assert result["version"] == result["build_version"]
|
||||
checks = result["checks"]
|
||||
for name in ("database", "data_dir", "local_first"):
|
||||
assert name in checks, f"missing check: {name}"
|
||||
|
||||
11
tests/test_version_metadata.py
Normal file
11
tests/test_version_metadata.py
Normal file
@@ -0,0 +1,11 @@
|
||||
"""Tests for WilkensXL build metadata."""
|
||||
|
||||
from src.constants import APP_VERSION, BUILD_FLAVOR, BUILD_VERSION, FULL_VERSION, UPSTREAM_VERSION
|
||||
|
||||
|
||||
def test_custom_build_version_is_distinct_from_upstream_version():
|
||||
assert APP_VERSION == "1.0.1"
|
||||
assert UPSTREAM_VERSION == APP_VERSION
|
||||
assert BUILD_FLAVOR == "wilkensxl"
|
||||
assert BUILD_VERSION.startswith(f"{APP_VERSION}-wilkensxl.")
|
||||
assert FULL_VERSION == BUILD_VERSION
|
||||
Reference in New Issue
Block a user