build: add release tagging, version checks and a release script

This repo has no tags and no GitHub releases, and manifest.json has read
"1.0.0" since the integration was vendored -- unchanged across 20 commits,
including today's breaking reshape of the config flow. HACS falls back to
serving the default branch when there are no releases, so every download is
indistinguishable from the last and there is no way to tell what is running.

- scripts/release.py bumps manifest.json, commits and creates an annotated
  tag in one step. It refuses a dirty tree, a branch other than main, a main
  that differs from origin/main, a malformed version and an existing tag. It
  stops short of pushing, since pushing the tag is what publishes.
- .github/workflows/release.yaml triggers on v* tags and refuses to publish
  when the tag and manifest.json disagree. That mismatch is the failure worth
  guarding: HACS offers the tag while Home Assistant reports the manifest, so
  you install "v0.2.0" and the integration page says 0.1.0. It then creates
  the release with gh (no third-party action).
- tests/test_version.py keeps the manifest version parseable by
  AwesomeVersion (what HACS validates with) and in the shape the release
  script accepts, so a release never fails on the version string itself.

Scheme: 0.x while the config entry shape is still in motion -- it changed
twice today -- and 1.0.0 when it settles. Documented in the README.

Local: 169 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NxJYWgGJtCw13qUHZtG8ki
This commit is contained in:
Adam SmithandClaude Opus 5 committed 2026-09-17 23:08:47 -04:00
1 parent e7fcb1d7a1
commit 4a347369cc
4 files changed
+197

No files matched your search

+38
View File
@@ -0,0 +1,38 @@
"""manifest.json's version is what HACS and Home Assistant report."""
import json
from pathlib import Path
from awesomeversion import AwesomeVersion
import pytest
MANIFEST = (
Path(__file__).resolve().parent.parent
/ "custom_components"
/ "openai_compatible"
/ "manifest.json"
)
@pytest.fixture(name="manifest")
def manifest_fixture() -> dict:
"""Return the integration manifest."""
return json.loads(MANIFEST.read_text(encoding="utf-8"))
def test_version_is_present_and_parseable(manifest: dict) -> None:
"""HACS validates the version with AwesomeVersion; so do we, locally."""
version = manifest.get("version")
assert version, "manifest.json needs a version for HACS to install it"
assert AwesomeVersion(version).valid
def test_version_matches_the_release_script_format(manifest: dict) -> None:
"""Keep the manifest in the shape scripts/release.py will accept, so a
release never fails on the version string itself."""
from scripts.release import VERSION_RE
assert VERSION_RE.match(manifest["version"]), (
f"{manifest['version']} is not MAJOR.MINOR.PATCH; "
"scripts/release.py and the release workflow expect that shape"
)