Skip to content

Commit 47c586a

Browse files
committed
Add tag version verification to CI/CD pipeline
Add verify_version.py script that checks all version-bearing files match an expected version. Add verify_tag CI job that runs after lint on tag pushes to catch cases where set_version.py was not run before tagging. Also disable PyPI attestations since we use token auth.
1 parent e5aa30f commit 47c586a

2 files changed

Lines changed: 130 additions & 2 deletions

File tree

.github/workflows/main.yml

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,27 @@ jobs:
9595
run: npx tsc --noEmit
9696
working-directory: native/bindings/node
9797

98+
# ---------------------------------------------------------------------------
99+
# Verify Tag — ensure set_version.py was run before tagging
100+
# ---------------------------------------------------------------------------
101+
verify_tag:
102+
name: Verify Tag Versions
103+
needs: lint
104+
runs-on: ubuntu-latest
105+
steps:
106+
- name: Skip on non-tag runs
107+
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
108+
run: echo "Not a tag push — skipping version check."
109+
- uses: actions/checkout@v6
110+
if: startsWith(github.ref, 'refs/tags/')
111+
- uses: actions/setup-python@v5
112+
if: startsWith(github.ref, 'refs/tags/')
113+
with:
114+
python-version: '3.12'
115+
- name: Verify all package versions match tag
116+
if: startsWith(github.ref, 'refs/tags/')
117+
run: python scripts/verify_version.py "${GITHUB_REF_NAME#v}"
118+
98119
# ---------------------------------------------------------------------------
99120
# Tests — gate for all downstream jobs
100121
# ---------------------------------------------------------------------------
@@ -242,7 +263,7 @@ jobs:
242263
# ---------------------------------------------------------------------------
243264
build_artifacts:
244265
name: Build Artifacts (${{ matrix.os }})
245-
needs: test
266+
needs: [test, verify_tag]
246267
if: >-
247268
github.event_name == 'schedule' ||
248269
github.event_name == 'workflow_dispatch' ||
@@ -512,7 +533,7 @@ jobs:
512533
# ---------------------------------------------------------------------------
513534
package_scenarios:
514535
name: Package Scenario Resources
515-
needs: test
536+
needs: [test, verify_tag]
516537
if: >-
517538
github.event_name == 'schedule' ||
518539
github.event_name == 'workflow_dispatch' ||
@@ -741,3 +762,4 @@ jobs:
741762
with:
742763
packages-dir: dist/
743764
password: ${{ secrets.PYPI_TOKEN }}
765+
attestations: false

scripts/verify_version.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#!/usr/bin/env python3
2+
# SPDX-FileCopyrightText: 2024-present American Society Of Cinematographers
3+
# SPDX-License-Identifier: Apache-2.0
4+
"""Verify that all version-bearing files match an expected version.
5+
6+
Checks every file that set_version.py updates and reports mismatches.
7+
Intended to run in CI on tag pushes to catch cases where set_version.py
8+
was not run before tagging.
9+
10+
Usage:
11+
python scripts/verify_version.py 1.0.1
12+
python scripts/verify_version.py "$TAG"
13+
"""
14+
15+
import argparse
16+
import json
17+
import re
18+
import sys
19+
from pathlib import Path
20+
21+
REPO_ROOT = Path(__file__).resolve().parent.parent
22+
23+
PYPROJECT_FILES = [
24+
"pyproject.toml",
25+
"native/bindings/python/pyproject.toml",
26+
"packages/fdl_imaging/pyproject.toml",
27+
"packages/fdl_viewer/pyproject.toml",
28+
"packages/fdl_frameline_generator/pyproject.toml",
29+
]
30+
31+
PACKAGE_JSON_FILES = [
32+
"native/bindings/node/package.json",
33+
"examples/web_viewer/server/package.json",
34+
"examples/web_viewer/client/package.json",
35+
]
36+
37+
CMAKE_VERSION_FILE = "native/core/cmake/FDLVersion.cmake"
38+
39+
40+
def read_pyproject_version(path: Path) -> str | None:
41+
text = path.read_text(encoding="utf-8")
42+
m = re.search(r'^version\s*=\s*"(.*?)"', text, re.MULTILINE)
43+
return m.group(1) if m else None
44+
45+
46+
def read_package_json_version(path: Path) -> str | None:
47+
data = json.loads(path.read_text(encoding="utf-8"))
48+
return data.get("version")
49+
50+
51+
def read_cmake_version_full(path: Path) -> str | None:
52+
text = path.read_text(encoding="utf-8")
53+
m = re.search(r'set\(FDL_CORE_VERSION_FULL\s+"(.*?)"\)', text)
54+
return m.group(1) if m else None
55+
56+
57+
def main() -> None:
58+
parser = argparse.ArgumentParser(description="Verify all repo package versions match the expected version.")
59+
parser.add_argument("version", help="Expected version string, e.g. 1.0.1 (without leading 'v')")
60+
args = parser.parse_args()
61+
62+
expected = args.version.lstrip("v")
63+
errors = 0
64+
65+
print(f"Expected version: {expected}\n")
66+
67+
# --- pyproject.toml files ---
68+
for rel in PYPROJECT_FILES:
69+
path = REPO_ROOT / rel
70+
actual = read_pyproject_version(path)
71+
if actual != expected:
72+
print(f" MISMATCH {rel}: {actual!r} (expected {expected!r})")
73+
errors += 1
74+
else:
75+
print(f" OK {rel}: {actual}")
76+
77+
# --- package.json files ---
78+
for rel in PACKAGE_JSON_FILES:
79+
path = REPO_ROOT / rel
80+
actual = read_package_json_version(path)
81+
if actual != expected:
82+
print(f" MISMATCH {rel}: {actual!r} (expected {expected!r})")
83+
errors += 1
84+
else:
85+
print(f" OK {rel}: {actual}")
86+
87+
# --- CMake ---
88+
path = REPO_ROOT / CMAKE_VERSION_FILE
89+
actual = read_cmake_version_full(path)
90+
if actual != expected:
91+
print(f" MISMATCH {CMAKE_VERSION_FILE}: {actual!r} (expected {expected!r})")
92+
errors += 1
93+
else:
94+
print(f" OK {CMAKE_VERSION_FILE}: {actual}")
95+
96+
print()
97+
if errors:
98+
print(f"FAILED: {errors} version mismatch(es) found.")
99+
print(f"Run 'python scripts/set_version.py {expected}' and commit before tagging.")
100+
sys.exit(1)
101+
102+
print(f"All versions match {expected}")
103+
104+
105+
if __name__ == "__main__":
106+
main()

0 commit comments

Comments
 (0)