chore: import upstream snapshot with attribution
Dashboard / frontend (push) Failing after 0s
Dashboard / api (push) Failing after 0s
Lint PowerShell / powershell-lint (ubuntu-latest) (push) Failing after 1s
Python Lint / Lint Python with Ruff (push) Failing after 1s
ShellCheck / Lint shell scripts (push) Failing after 1s
Matrix Smoke / linux-smoke (push) Failing after 1s
Matrix Smoke / distro: cachyos (push) Failing after 15s
Matrix Smoke / distro: linux-mint-21.3 (push) Failing after 15s
Matrix Smoke / distro: debian-12 (push) Failing after 5m21s
Matrix Smoke / distro: fedora-41 (push) Failing after 4m56s
Matrix Smoke / distro: ubuntu-24.04 (push) Failing after 2m13s
Matrix Smoke / distro: rocky-9 (push) Failing after 10m39s
Matrix Smoke / distro: manjaro (push) Failing after 12m11s
Matrix Smoke / distro: opensuse-tw (push) Failing after 11m53s
Matrix Smoke / distro: archlinux (push) Failing after 20m3s
Matrix Smoke / distro: ubuntu-22.04 (push) Failing after 13m49s
Validate .env Schema / tier-1-env-validation (push) Successful in 52s
Validate .env Schema / tier-2-env-validation (push) Successful in 44s
Validate .env Schema / tier-3-env-validation (push) Successful in 52s
Validate .env Schema / tier-4-env-validation (push) Successful in 51s
Validate Extensions Catalog / Check catalog is up-to-date (push) Failing after 9m47s
Secret Scan / Scan for secrets (push) Failing after 21m4s
Validate Docker Compose / Validate Docker Compose files (push) Has been cancelled
Python Type Check / Type check with mypy (push) Has been cancelled
Validate .env Schema / tier-0-env-validation (push) Has been cancelled
Test Linux / integration-smoke (push) Has been cancelled
Lint PowerShell / powershell-lint (windows-latest) (push) Has been cancelled
Matrix Smoke / macos-smoke (push) Has been cancelled
Dashboard / frontend (push) Failing after 0s
Dashboard / api (push) Failing after 0s
Lint PowerShell / powershell-lint (ubuntu-latest) (push) Failing after 1s
Python Lint / Lint Python with Ruff (push) Failing after 1s
ShellCheck / Lint shell scripts (push) Failing after 1s
Matrix Smoke / linux-smoke (push) Failing after 1s
Matrix Smoke / distro: cachyos (push) Failing after 15s
Matrix Smoke / distro: linux-mint-21.3 (push) Failing after 15s
Matrix Smoke / distro: debian-12 (push) Failing after 5m21s
Matrix Smoke / distro: fedora-41 (push) Failing after 4m56s
Matrix Smoke / distro: ubuntu-24.04 (push) Failing after 2m13s
Matrix Smoke / distro: rocky-9 (push) Failing after 10m39s
Matrix Smoke / distro: manjaro (push) Failing after 12m11s
Matrix Smoke / distro: opensuse-tw (push) Failing after 11m53s
Matrix Smoke / distro: archlinux (push) Failing after 20m3s
Matrix Smoke / distro: ubuntu-22.04 (push) Failing after 13m49s
Validate .env Schema / tier-1-env-validation (push) Successful in 52s
Validate .env Schema / tier-2-env-validation (push) Successful in 44s
Validate .env Schema / tier-3-env-validation (push) Successful in 52s
Validate .env Schema / tier-4-env-validation (push) Successful in 51s
Validate Extensions Catalog / Check catalog is up-to-date (push) Failing after 9m47s
Secret Scan / Scan for secrets (push) Failing after 21m4s
Validate Docker Compose / Validate Docker Compose files (push) Has been cancelled
Python Type Check / Type check with mypy (push) Has been cancelled
Validate .env Schema / tier-0-env-validation (push) Has been cancelled
Test Linux / integration-smoke (push) Has been cancelled
Lint PowerShell / powershell-lint (windows-latest) (push) Has been cancelled
Matrix Smoke / macos-smoke (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Fail the release gate when ODS version authorities drift."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
SEMVER = re.compile(r"^\d+\.\d+\.\d+$")
|
||||
|
||||
|
||||
def read_text(path: Path) -> str:
|
||||
return path.read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def first_match(path: Path, pattern: str, label: str) -> str:
|
||||
match = re.search(pattern, read_text(path), re.MULTILINE | re.DOTALL)
|
||||
if not match:
|
||||
raise ValueError(f"{label}: could not find version in {path.relative_to(ROOT)}")
|
||||
return match.group(1)
|
||||
|
||||
|
||||
def latest_changelog_release() -> tuple[str, str]:
|
||||
changelog = read_text(ROOT / "CHANGELOG.md")
|
||||
for match in re.finditer(r"^## \[([^\]]+)\](?: - ([0-9]{4}-[0-9]{2}-[0-9]{2}))?", changelog, re.MULTILINE):
|
||||
version, date = match.group(1), match.group(2) or ""
|
||||
if version.lower() != "unreleased":
|
||||
return version, date
|
||||
raise ValueError("CHANGELOG.md: could not find a released version heading")
|
||||
|
||||
|
||||
def optional_version_file() -> str | None:
|
||||
path = ROOT / ".version"
|
||||
if not path.exists():
|
||||
return None
|
||||
raw = read_text(path).strip()
|
||||
if not raw:
|
||||
return None
|
||||
try:
|
||||
data = json.loads(raw)
|
||||
except json.JSONDecodeError:
|
||||
return raw
|
||||
if isinstance(data, dict) and data.get("version"):
|
||||
return str(data["version"])
|
||||
return raw
|
||||
|
||||
|
||||
def add_regex_check(
|
||||
checks: list[tuple[str, str]],
|
||||
errors: list[str],
|
||||
label: str,
|
||||
path: Path,
|
||||
pattern: str,
|
||||
) -> None:
|
||||
try:
|
||||
checks.append((label, first_match(path, pattern, label)))
|
||||
except ValueError as exc:
|
||||
errors.append(str(exc))
|
||||
|
||||
|
||||
def main() -> int:
|
||||
errors: list[str] = []
|
||||
manifest_path = ROOT / "manifest.json"
|
||||
|
||||
try:
|
||||
manifest = json.loads(read_text(manifest_path))
|
||||
expected = str(manifest.get("ods_version", "")).strip()
|
||||
release = manifest.get("release") if isinstance(manifest.get("release"), dict) else {}
|
||||
release_version = str(release.get("version", "")).strip()
|
||||
release_date = str(release.get("date", "")).strip()
|
||||
except Exception as exc: # noqa: BLE001 - gate should report cleanly
|
||||
print(f"[FAIL] version consistency: cannot read manifest.json: {exc}")
|
||||
return 1
|
||||
|
||||
if not expected:
|
||||
errors.append("manifest.json ods_version is empty")
|
||||
elif not SEMVER.match(expected):
|
||||
errors.append(f"manifest.json ods_version must be x.y.z, got {expected!r}")
|
||||
|
||||
checks = [("manifest.json release.version", release_version)]
|
||||
add_regex_check(
|
||||
checks,
|
||||
errors,
|
||||
"extensions/services/dashboard-api/main.py FastAPI version",
|
||||
ROOT / "extensions/services/dashboard-api/main.py",
|
||||
r"app\s*=\s*FastAPI\([^)]*?version\s*=\s*[\"']([^\"']+)[\"']",
|
||||
)
|
||||
add_regex_check(
|
||||
checks,
|
||||
errors,
|
||||
"installers/lib/constants.sh VERSION",
|
||||
ROOT / "installers/lib/constants.sh",
|
||||
r'^VERSION="([^"]+)"',
|
||||
)
|
||||
add_regex_check(
|
||||
checks,
|
||||
errors,
|
||||
"installers/macos/lib/constants.sh ODS_VERSION",
|
||||
ROOT / "installers/macos/lib/constants.sh",
|
||||
r'^ODS_VERSION="([^"]+)"',
|
||||
)
|
||||
add_regex_check(
|
||||
checks,
|
||||
errors,
|
||||
"installers/windows/lib/constants.ps1 ODS_VERSION",
|
||||
ROOT / "installers/windows/lib/constants.ps1",
|
||||
r'^\$script:ODS_VERSION\s*=\s*"([^"]+)"',
|
||||
)
|
||||
add_regex_check(
|
||||
checks,
|
||||
errors,
|
||||
"installers/phases/06-directories.sh ODS_VERSION fallback",
|
||||
ROOT / "installers/phases/06-directories.sh",
|
||||
r"^ODS_VERSION=\$\{VERSION:-([^}]+)\}",
|
||||
)
|
||||
add_regex_check(
|
||||
checks,
|
||||
errors,
|
||||
"ARCHITECTURE.md version",
|
||||
ROOT.parent / "ARCHITECTURE.md",
|
||||
r"^> Version ([0-9]+\.[0-9]+\.[0-9]+)\s+\|",
|
||||
)
|
||||
|
||||
version_file = optional_version_file()
|
||||
if version_file is not None:
|
||||
checks.append((".version version", version_file))
|
||||
|
||||
try:
|
||||
changelog_version, changelog_date = latest_changelog_release()
|
||||
checks.append(("CHANGELOG.md latest release", changelog_version))
|
||||
if release_date and changelog_date and release_date != changelog_date:
|
||||
errors.append(
|
||||
f"manifest.json release.date {release_date!r} != CHANGELOG.md latest release date {changelog_date!r}"
|
||||
)
|
||||
except ValueError as exc:
|
||||
errors.append(str(exc))
|
||||
|
||||
for label, value in checks:
|
||||
if value != expected:
|
||||
errors.append(f"{label} {value!r} != manifest.json ods_version {expected!r}")
|
||||
|
||||
if errors:
|
||||
print("[FAIL] version consistency")
|
||||
for error in errors:
|
||||
print(f" - {error}")
|
||||
return 1
|
||||
|
||||
print(f"[PASS] version consistency ({expected})")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user