Skip to content

fix(version): read from manifest.json (closes #784)#785

Merged
mholzi merged 2 commits intomainfrom
fix/784-version-from-manifest
Apr 25, 2026
Merged

fix(version): read from manifest.json (closes #784)#785
mholzi merged 2 commits intomainfrom
fix/784-version-from-manifest

Conversation

@mholzi
Copy link
Copy Markdown
Owner

@mholzi mholzi commented Apr 25, 2026

Closes #784. Cache-busting was a red herring — the admin footer was honestly reporting a stale _VERSION constant that hadn't been bumped since April 15.

Root cause

Two compounding issues:

  1. `server/base.py:25` hardcoded `_VERSION = "3.2.0-rc29"` as a constant.
  2. Commit 6d056b35 (April 15) untracked `.github/workflows/` from git. The version-bump workflow that was supposed to keep `_VERSION` in sync still exists on local disks but GitHub Actions has no copy. Last actual run: v3.0.6-rc.4 on 2026-04-15.

Every release since (3.2.x stable, 3.3.0, all six 3.3.1-rc tags) shipped with the wrong footer.

The fix

Eliminate the duplicated source of truth. Version is now read from `manifest.json` once at `async_setup_entry` time (via `async_add_executor_job` to stay off the event loop, respecting HA 2026.2+'s blocking-I/O detector) and cached in `hass.data[DOMAIN]['version']`. `_get_version(hass)` reads from there, falls back to "unknown" if hass isn't available.

Single source of truth, no GitHub Action dependency, can never drift again.

Test plan

  • `ruff check` + `ruff format --check` clean
  • Smoke-tested `_read_manifest_version()` in isolation: returns "3.3.1-rc6" from the actual manifest (now rc7 after this PR's bump)
  • Smoke-tested `_get_version(None)` returns "unknown" fallback
  • Smoke-tested `_get_version(fake_hass)` returns "3.3.1-rc7" from mocked `hass.data[DOMAIN]['version']`
  • Live verification: load `/beatify/admin` after rc7 ships, footer should read "Beatify v3.3.1-rc7" (not rc29)

Tradeoffs

  • `_get_version()` signature changed from no-args to optional `hass`. Only one caller (`StatusView` in `server/views.py`); updated inline.
  • The auto-bump workflow `.github/workflows/version-bump.yml` is now obsolete. Worth deleting the local-only copy in a follow-up — it's misleading to have "live" code that doesn't actually run anywhere.
  • Wider scope (out of this PR): `test.yml`, `validate.yml`, `pages.yml` are also untracked. CI hasn't run on PRs since April. Separate decision: re-track them, or accept local-only checks.

Version

  • `manifest.json` + `sw.js CACHE_VERSION` → `3.3.1-rc7`
  • No frontend asset changes — HTML cache-busters unchanged

🤖 Generated with Claude Code

Claude Code and others added 2 commits April 25, 2026 12:54
…loses #784)

The admin footer had been displaying "Beatify v3.2.0-rc29" since mid-April
regardless of which version was actually installed. Cache-busting was a
red herring — assets were loading fresh, the backend was just honestly
reporting its stale `_VERSION` constant.

Root cause is two compounding issues:

1. `server/base.py` hardcoded `_VERSION = "3.2.0-rc29"` as a constant.
   That constant was supposed to be auto-bumped on every release by
   `.github/workflows/version-bump.yml`.

2. Commit 6d056b3 (Apr 15) untracked `.github/workflows/` from git and
   added the path to `.gitignore`. The workflow file still exists on
   contributors' local disks, but GitHub Actions has no copy to run.
   Last actual run: v3.0.6-rc.4 on 2026-04-15. Every release since
   shipped with the wrong footer.

This change eliminates the duplicated source of truth. Version is now
read from `manifest.json` once at `async_setup_entry` (in an executor
job so HA's blocking-I/O detector stays happy on reload) and cached
in `hass.data[DOMAIN]['version']`. `_get_version(hass)` reads from
there. No GitHub Action dependency, can never drift.

`_get_version()` signature changed from no-args to optional `hass`.
Only one caller (`StatusView` in `server/views.py`), updated inline.
Falls back to "unknown" if hass isn't available — also covers a
malformed install where manifest.json can't be read at all.

The version-bump.yml workflow is now obsolete. Worth deleting the
local-only copy in a follow-up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bumped manifest + sw.js CACHE_VERSION → 3.3.1-rc7. No frontend
asset changes — HTML cache-busters unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request resolves issue #784 by establishing manifest.json as the single source of truth for the integration version, replacing a hardcoded constant that frequently drifted. The version is now read during setup via an executor job and cached in the Home Assistant data store. A review comment suggests enhancing the error handling in the manifest reading function to catch potential AttributeErrors if the JSON structure is unexpected.

Comment on lines +73 to +77
try:
return json.loads(manifest_path.read_text(encoding="utf-8")).get(
"version", "unknown"
)
except (OSError, ValueError):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The _read_manifest_version function should also catch AttributeError. If manifest.json contains a valid JSON value that is not an object (e.g., null or []), json.loads() will return a type that does not have a .get() method, causing an unhandled exception that would fail the integration setup. Adding AttributeError to the exception handler ensures robustness against malformed manifest files, consistent with the defensive approach used in server/base.py.

Suggested change
try:
return json.loads(manifest_path.read_text(encoding="utf-8")).get(
"version", "unknown"
)
except (OSError, ValueError):
try:
return json.loads(manifest_path.read_text(encoding="utf-8")).get(
"version", "unknown"
)
except (OSError, ValueError, AttributeError):

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: admin footer shows v3.2.0-rc29 — _VERSION constant drifted (workflow untracked)

1 participant