chore: adopt learning-first charter and UTC run versions
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Stamp a development/release run once, using its current UTC date and time.
|
||||
|
||||
Run before building: python3 tools/stamp_version.py && make
|
||||
Ordinary rebuilds and validation retain the stamp for reproducibility.
|
||||
Historical release notes and changelog entries are deliberately not rewritten.
|
||||
"""
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
CURRENT_DOCS = (
|
||||
"CURRENT_STATUS.md", "CLASSROOM_READINESS.md", "CLI.md", "SPEC.md",
|
||||
"FINAL_RELEASE_CHECKLIST.md", "WEB_SERVER_PLAN.md", "GRAPHICS.md",
|
||||
"PERFORMANCE.md", "COMPLETE_PLATFORM_ROADMAP.md", "SDL12.md",
|
||||
"V1_16_PACKAGES_PROJECTS.md",
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
source = ROOT / "src/claro.c"
|
||||
match = re.search(r'#define CLARO_VERSION "Claro ([^"\n]+)"', source.read_text())
|
||||
if not match:
|
||||
raise SystemExit("Cannot find CLARO_VERSION; no files changed")
|
||||
previous = match.group(1)
|
||||
version = datetime.now(timezone.utc).strftime("v%Y.%m.%d.%H%M%S")
|
||||
paths = [source, ROOT / "README.md"]
|
||||
paths += sorted((ROOT / "tools").glob("*.py"))
|
||||
paths += [ROOT / "docs" / name for name in CURRENT_DOCS]
|
||||
updates = []
|
||||
for path in paths:
|
||||
if path == Path(__file__).resolve() or not path.exists():
|
||||
continue
|
||||
old = path.read_text(encoding="utf-8")
|
||||
new = old.replace(previous, version)
|
||||
if new != old:
|
||||
updates.append((path, new))
|
||||
for path, content in updates:
|
||||
path.write_text(content, encoding="utf-8")
|
||||
print(f"Claro {version} (UTC); updated {len(updates)} current source/docs/validator files")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -6,7 +6,7 @@ from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
EXE = ROOT / ("claro.exe" if os.name == "nt" else "claro")
|
||||
EXPECTED_VERSION = "Claro v1.18.26"
|
||||
EXPECTED_VERSION = "Claro v2026.10.20.155641"
|
||||
|
||||
|
||||
def fail(message):
|
||||
@@ -57,11 +57,11 @@ def main():
|
||||
fail(out)
|
||||
starter = work / "StarterApp"
|
||||
starter_project = read(starter / "claro.project")
|
||||
for phrase in ["manifest-version: 1", "name: StarterApp", "main: main.claro", "version: v1.18.26", "packages:"]:
|
||||
for phrase in ["manifest-version: 1", "name: StarterApp", "main: main.claro", "version: v2026.10.20.155641", "packages:"]:
|
||||
if phrase not in starter_project:
|
||||
fail(f"claro new project file missing {phrase!r}:\n{starter_project}")
|
||||
starter_lock = read(starter / "claro.lock")
|
||||
for phrase in ["lock-version: 1", "version: v1.18.26"]:
|
||||
for phrase in ["lock-version: 1", "version: v2026.10.20.155641"]:
|
||||
if phrase not in starter_lock:
|
||||
fail(f"claro new lockfile missing {phrase!r}:\n{starter_lock}")
|
||||
|
||||
@@ -71,7 +71,7 @@ def main():
|
||||
if rc != 0:
|
||||
fail(out)
|
||||
project = read(work / "claro.project")
|
||||
for phrase in ["manifest-version: 1", "name: ClaroProject", "main: main.claro", "version: v1.18.26", "packages:"]:
|
||||
for phrase in ["manifest-version: 1", "name: ClaroProject", "main: main.claro", "version: v2026.10.20.155641", "packages:"]:
|
||||
if phrase not in project:
|
||||
fail(f"claro.project missing {phrase!r}:\n{project}")
|
||||
|
||||
@@ -100,7 +100,7 @@ def main():
|
||||
fail(f"Package checksum should be a stable non-placeholder value, got {checksum!r}")
|
||||
|
||||
lock = read(work / "claro.lock")
|
||||
for phrase in ["lock-version: 1", "version: v1.18.26", "package: math-tools", "checksum:"]:
|
||||
for phrase in ["lock-version: 1", "version: v2026.10.20.155641", "package: math-tools", "checksum:"]:
|
||||
if phrase not in lock:
|
||||
fail(f"claro.lock missing {phrase!r}:\n{lock}")
|
||||
|
||||
@@ -127,12 +127,12 @@ def main():
|
||||
fail(f"Lock format-version diagnostic was unclear:\n{out}")
|
||||
if read(work / "claro.lock") != invalid_lock:
|
||||
fail("package doctor must not rewrite an invalid lock format version")
|
||||
invalid_release_lock = lock.replace("version: v1.18.26", "version: v1.18.25", 1)
|
||||
invalid_release_lock = lock.replace("version: v2026.10.20.155641", "version: v1.18.25", 1)
|
||||
(work / "claro.lock").write_text(invalid_release_lock, encoding="utf-8")
|
||||
rc, out = run([str(EXE), "package", "doctor"], work)
|
||||
if rc == 0:
|
||||
fail("package doctor must reject a lockfile for a different Claro release")
|
||||
if "BAD lock release version: expected exactly one version: v1.18.26 line" not in out:
|
||||
if "BAD lock release version: expected exactly one version: v2026.10.20.155641 line" not in out:
|
||||
fail(f"Lock release-version diagnostic was unclear:\n{out}")
|
||||
if read(work / "claro.lock") != invalid_release_lock:
|
||||
fail("package doctor must not rewrite an invalid lock release version")
|
||||
@@ -343,7 +343,7 @@ def main():
|
||||
fail("Long package name should not create a package folder")
|
||||
|
||||
(work / "claro.project").write_text(
|
||||
"manifest-version: 1\nname: ClaroProject\nmain: main.claro\nversion: v1.18.26\npackages:\npackage: ../bad\n",
|
||||
"manifest-version: 1\nname: ClaroProject\nmain: main.claro\nversion: v2026.10.20.155641\npackages:\npackage: ../bad\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
rc, out = run([str(EXE), "package", "doctor"], work)
|
||||
@@ -382,7 +382,7 @@ def main():
|
||||
fail("package add should not create a package folder while unsafe names remain in claro.project")
|
||||
|
||||
(work / "claro.project").write_text(
|
||||
"manifest-version: 1\nname: ClaroProject\nmain: main.claro\nversion: v1.18.26\npackages:\npackage: math-tools\npackage: ../bad\n",
|
||||
"manifest-version: 1\nname: ClaroProject\nmain: main.claro\nversion: v2026.10.20.155641\npackages:\npackage: math-tools\npackage: ../bad\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
rc, out = run([str(EXE), "package", "remove", "math-tools"], work)
|
||||
|
||||
@@ -43,4 +43,4 @@ with tempfile.TemporaryDirectory() as td:
|
||||
run([str(local), "package", "remove", "text"], cwd=proj)
|
||||
run([str(local), "run"], cwd=proj)
|
||||
|
||||
print("Validation passed. Claro v1.18.26 networking reliability is ready for use.")
|
||||
print("Validation passed. Claro v2026.10.20.155641 networking reliability is ready for use.")
|
||||
|
||||
@@ -38,7 +38,7 @@ def build():
|
||||
def main():
|
||||
build()
|
||||
out = run([str(EXE), "--version"])
|
||||
if "Claro v1.18.26" not in out:
|
||||
if "Claro v2026.10.20.155641" not in out:
|
||||
raise SystemExit("Wrong version string")
|
||||
run([str(EXE), "test"])
|
||||
run([str(EXE), "validate"])
|
||||
@@ -55,7 +55,7 @@ def main():
|
||||
run([sys.executable, "tools/validate_write_file_expression_cleanup.py"])
|
||||
run([sys.executable, "tools/validate_version_convention.py"])
|
||||
run([str(EXE), "examples/networking.claro"])
|
||||
print("v1.18.26 validation complete")
|
||||
print("v2026.10.20.155641 validation complete")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
import re
|
||||
from datetime import datetime
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
EXE = ROOT / "claro.exe"
|
||||
EXPECTED = "Claro v1.18.26"
|
||||
EXPECTED = "Claro v2026.10.20.155641"
|
||||
|
||||
|
||||
def fail(message):
|
||||
@@ -20,18 +22,21 @@ def main():
|
||||
if not EXE.exists():
|
||||
fail(f"Missing executable: {EXE}")
|
||||
out = run([str(EXE), "--version"]).stdout.strip()
|
||||
if not re.fullmatch(r"Claro v\d{4}\.\d{2}\.\d{2}\.\d{6}", out):
|
||||
fail(f"Expected UTC run timestamp Claro vYYYY.MM.DD.HHMMSS, got {out!r}")
|
||||
datetime.strptime(out.removeprefix("Claro v"), "%Y.%m.%d.%H%M%S")
|
||||
if out != EXPECTED:
|
||||
fail(f"Expected version {EXPECTED!r}, got {out!r}")
|
||||
ide = run([str(EXE), "ide"])
|
||||
if ide.returncode != 0:
|
||||
fail(ide.stdout)
|
||||
metadata = json.loads(ide.stdout)
|
||||
if metadata.get("version") != "v1.18.26":
|
||||
fail(f"Expected IDE metadata version 'v1.18.26', got {metadata.get('version')!r}")
|
||||
if metadata.get("version") != "v2026.10.20.155641":
|
||||
fail(f"Expected IDE metadata version 'v2026.10.20.155641', got {metadata.get('version')!r}")
|
||||
validator = ROOT / "tools" / "validate_v1_17.py"
|
||||
text = validator.read_text(encoding="utf-8")
|
||||
if "Claro v1.18.26" not in text:
|
||||
fail("tools/validate_v1_17.py must validate Claro v1.18.26")
|
||||
if "Claro v2026.10.20.155641" not in text:
|
||||
fail("tools/validate_v1_17.py must validate Claro v2026.10.20.155641")
|
||||
print("Version convention validation OK")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user