docs: spec badge versione build in GUI
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
8084b87261
commit
a88a064aa8
1 file changed
+95
@@ -0,0 +1,95 @@
|
||||
# GUI build-version badge
|
||||
|
||||
**Date:** 2026-06-03
|
||||
**Status:** approved (design)
|
||||
**Area:** `VERSION`, `build.sh`, `Dockerfile`, `src/presa_mano/version.py`, `src/presa_mano/main.py`, `web/index.html`, `web/app.js`
|
||||
|
||||
## Problem
|
||||
|
||||
`src/` and `web/` are baked into the Docker image (no bind-mount), so code changes only take effect after an image rebuild. There is no visible indicator of which build the running container serves, so a stale deployment is invisible — exactly the confusion behind "non vedo modifiche alla GUI". We want a version shown in the GUI header that increments on every build, plus the build time.
|
||||
|
||||
## Decisions (locked)
|
||||
|
||||
- **Version string:** `V<major>.<minor>.<patch>` (e.g. `V1.0.1`), **patch auto-increments every build**; build time shown too.
|
||||
- **Injection:** a build wrapper script passes the version + build time as Docker build args.
|
||||
- **Placement:** a pill badge in the GUI header, build time in its tooltip.
|
||||
|
||||
## Components
|
||||
|
||||
### `VERSION` (tracked file, repo root `presa-mano/VERSION`)
|
||||
Plain text `major.minor.patch`, initialized to `1.0.0`. Single source of truth for the number; persists across builds via the file on disk. The build script rewrites it (left as an uncommitted working-tree edit — the script does NOT auto-commit).
|
||||
|
||||
### `build.sh` (repo root, executable)
|
||||
```
|
||||
1. cd to script dir; ensure VERSION exists (else seed 1.0.0)
|
||||
2. parse current major.minor.patch
|
||||
3. bump: default patch++; arg `minor` → minor++/patch=0; `major` → major++/minor=patch=0
|
||||
4. write new VERSION
|
||||
5. BUILD_TIME = $(date -u +"%Y-%m-%d %H:%M UTC")
|
||||
6. (cd compose dir) docker compose build --build-arg APP_VERSION=<new> --build-arg BUILD_TIME="<ts>" presa-mano
|
||||
7. docker compose up -d presa-mano
|
||||
8. echo deployed version
|
||||
```
|
||||
The compose file lives one level up (`/opt/docker/robotserver/docker-compose.yml`); the script resolves that dir and runs compose there. Usage: `./build.sh [patch|minor|major]` (default patch).
|
||||
|
||||
### `Dockerfile`
|
||||
Add late (before `CMD`), so changing them doesn't bust the dependency layers:
|
||||
```
|
||||
ARG APP_VERSION=dev
|
||||
ARG BUILD_TIME=unknown
|
||||
ENV APP_VERSION=${APP_VERSION}
|
||||
ENV BUILD_TIME=${BUILD_TIME}
|
||||
```
|
||||
Also `COPY VERSION ./` (cheap, makes the file fallback work inside the container too).
|
||||
|
||||
### `src/presa_mano/version.py`
|
||||
```python
|
||||
def build_info() -> dict:
|
||||
"""{'version', 'build_time'}. Prefer env (set at Docker build); fall back to
|
||||
the VERSION file + '(local)' for `uv run` dev."""
|
||||
```
|
||||
- `version` = `APP_VERSION` env if set, else `<VERSION file contents> (local)` (or `0.0.0 (local)` if the file is unreadable).
|
||||
- `build_time` = `BUILD_TIME` env if set, else `(local)`.
|
||||
- `VERSION` file resolved as `Path(__file__).resolve().parents[2] / "VERSION"`.
|
||||
|
||||
### `src/presa_mano/main.py`
|
||||
```python
|
||||
from .version import build_info
|
||||
|
||||
@app.get("/api/version", tags=["meta"])
|
||||
def version() -> dict:
|
||||
return build_info()
|
||||
```
|
||||
|
||||
### `web/index.html`
|
||||
In the header, next to `#activeRobotPill`, add:
|
||||
```html
|
||||
<span class="active-robot-pill" id="appVersionPill" title="versione build">V—</span>
|
||||
```
|
||||
(reuses the existing pill styling).
|
||||
|
||||
### `web/app.js`
|
||||
Add and call once at startup (alongside `refreshHomeRobotSelector()`):
|
||||
```javascript
|
||||
async function refreshAppVersion() {
|
||||
try {
|
||||
const r = await api('GET', '/api/version');
|
||||
const pill = $('appVersionPill');
|
||||
if (pill) { pill.textContent = `V${r.version}`; pill.title = `build ${r.build_time}`; }
|
||||
} catch {}
|
||||
}
|
||||
refreshAppVersion();
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
- Unit test `tests/test_version.py` for `build_info()`:
|
||||
- env set (`APP_VERSION`, `BUILD_TIME` via monkeypatch) → returns exactly those.
|
||||
- env unset (monkeypatch.delenv) → `version` ends with `(local)` and contains the `VERSION` file content; `build_time == "(local)"`.
|
||||
- Frontend: manual — after `./build.sh` the badge increments and the tooltip shows the new build time.
|
||||
|
||||
## Out of scope (YAGNI)
|
||||
|
||||
- git SHA / dirty flag (user chose version+time only).
|
||||
- Auto-commit of the VERSION bump.
|
||||
- Frontend-vs-backend version mismatch warning.
|
||||
Reference in new issue
Block a user