diff --git a/Makefile b/Makefile index 0c01658..3e4341d 100644 --- a/Makefile +++ b/Makefile @@ -33,6 +33,7 @@ release: dist uv publish release-npm: clean build + uv run python scripts/set_npm_version.py cd js && npm publish add-language: diff --git a/js/package.json b/js/package.json index 4c27540..d6fa0f4 100644 --- a/js/package.json +++ b/js/package.json @@ -27,5 +27,5 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, - "version": "0.2.18" + "version": "0.0.0" } diff --git a/scripts/generate_from_specs.py b/scripts/generate_from_specs.py index 598daa1..66c8d62 100644 --- a/scripts/generate_from_specs.py +++ b/scripts/generate_from_specs.py @@ -14,7 +14,6 @@ from collections import OrderedDict from glob import glob from hashlib import md5 -from importlib.metadata import version as get_version from uuid import UUID from uuid import uuid3 @@ -259,43 +258,6 @@ def write_constants_src_files(constants_outputs, schemas): return output_files -def pep440_to_npm_semver(version): - """Convert a PEP 440 version to npm-compatible semver. - - Extracts just the base version (X.Y.Z) to ensure the version is - stable across commits and valid npm semver. Dev/local suffixes from - setuptools-scm change with every commit, which would cause the - rebuild-from-specs pre-commit hook to perpetually modify this file. - On tagged releases, setuptools-scm returns the clean version directly. - """ - match = re.match(r"(\d+\.\d+\.\d+)", version) - return match.group(1) if match else version - - -def set_package_json_version(): - python_version = get_version("le-utils") - npm_version = pep440_to_npm_semver(python_version) - - package_json = os.path.join(js_output_dir, "package.json") - - with open(package_json, "r") as f: - package = json.load(f) - - package["version"] = npm_version - - with open(package_json, "w") as f: - output = json.dumps(package, indent=2, sort_keys=True) - firstline = True - for line in output.split("\n"): - if firstline: - firstline = False - else: - f.write("\n") - f.write(line.rstrip()) - f.write("\n") - return [package_json] - - if __name__ == "__main__": labels_to_write = read_labels_specs() @@ -310,8 +272,6 @@ def set_package_json_version(): output_files += write_constants_src_files(constants_to_write, schemas_to_write) - output_files += set_package_json_version() - py_files = [f for f in output_files if f.endswith(".py")] subprocess.call(["ruff", "check", "--fix"] + py_files) subprocess.call(["ruff", "format"] + py_files) diff --git a/scripts/set_npm_version.py b/scripts/set_npm_version.py new file mode 100644 index 0000000..1f78cba --- /dev/null +++ b/scripts/set_npm_version.py @@ -0,0 +1,55 @@ +""" +set_npm_version +Writes the release version into js/package.json, for the npm publish path only. + +Kept out of generate_from_specs.py on purpose. The version is derived from git +tags, so a tracked value can never match what setuptools-scm computes once a +release tag is created: the tag is applied to a commit whose package.json was +written before the tag existed. Regenerating it as part of `make build` made the +rebuild-from-specs hook fail on every commit after a release. The tracked value +is a 0.0.0 placeholder; only `make release-npm` sets a real one. +""" + +import json +import os +import re +from importlib.metadata import version as get_version + +package_json = os.path.join(os.path.dirname(__file__), "..", "js", "package.json") + + +def pep440_to_npm_semver(version): + """Return version if it is an exact X.Y.Z release, else fail. + + setuptools-scm only returns a bare X.Y.Z for a checkout at a release tag. + Anything else carries a dev/local suffix and would publish a version that + does not correspond to a release. + """ + if not re.match(r"^\d+\.\d+\.\d+$", version): + raise SystemExit("Refusing to set npm version from non-release version {!r}. Publish from a checkout at a release tag.".format(version)) + return version + + +def set_package_json_version(): + npm_version = pep440_to_npm_semver(get_version("le-utils")) + + with open(package_json, "r") as f: + package = json.load(f) + + package["version"] = npm_version + + with open(package_json, "w") as f: + output = json.dumps(package, indent=2, sort_keys=True) + firstline = True + for line in output.split("\n"): + if firstline: + firstline = False + else: + f.write("\n") + f.write(line.rstrip()) + f.write("\n") + return npm_version + + +if __name__ == "__main__": + print("Set js/package.json version to {}".format(set_package_json_version()))