From 17ddfc4c8f88d7c8c630a8e849c341aa489d17a2 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Wed, 20 May 2026 08:42:45 +0100 Subject: [PATCH] fix(version): single source of truth via lib/version.ml + tag-time bake (#297) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes the five-site `0.1.0` drift documented in #297: the compiler binary's `--version`, REPL banner, LSP `initialize` response, and the ONNX `m_producer_version` field were all hand-edited to "0.1.0" and never bumped when v0.1.1 was tagged, so the v0.1.1 binary still reported "0.1.0" (caught during the #282/#295 shim smoke). Approach: option (1) from #297 — generated `Version` module + CI substitution. One small module + one small workflow step; no runtime dependency on `dune-build-info` or any new opam package. Source-of-truth single file --------------------------- lib/version.ml new — `let value = "0.1.1"`, 1 string, baked from the tag at release time Five sites collapsed onto it ---------------------------- bin/main.ml `let version = Affinescript.Version.value` lib/repl.ml `Printf.printf "AffineScript REPL v%s\n" Version.value` lib/lsp_server.ml `("version", `String Version.value)` lib/onnx_codegen.ml `m_producer_version = Version.value` dune-project `(version 0.1.1)` (matches the latest release; opam metadata regenerated) lib/dune `version` added to the modules list Release pipeline bake step -------------------------- `.github/workflows/release.yml`: new step between `Install dependencies` and `Build release` that rewrites BOTH `lib/version.ml` and `dune-project` from `${GITHUB_REF_NAME#v}` (stripping the leading `v`) before `dune build --release`. Subsequent tag bumps need no hand-edit — cut a `vX.Y.Z` tag and the binary self-reports `X.Y.Z`. Cross-checked locally --------------------- $ opam exec -- dune build --release (clean, no warnings introduced) $ _build/default/bin/main.exe --version 0.1.1 $ grep '^version' affinescript.opam # 0.1.1 $ grep '^let value' lib/version.ml # 0.1.1 $ grep '^(version' .build/dune-project # 0.1.1 All four sites coherent. Closes #297. Refs #282 (the closure-PR smoke that surfaced the drift). Co-Authored-By: Claude Opus 4.7 (1M context) --- .build/dune-project | 2 +- .github/workflows/release.yml | 14 ++++++++++++++ affinescript.opam | 4 ++-- bin/main.ml | 5 +++-- lib/dune | 1 + lib/lsp_server.ml | 2 +- lib/onnx_codegen.ml | 2 +- lib/repl.ml | 2 +- lib/version.ml | 19 +++++++++++++++++++ 9 files changed, 43 insertions(+), 8 deletions(-) create mode 100644 lib/version.ml diff --git a/.build/dune-project b/.build/dune-project index 34f3d847..1f6cdaf5 100644 --- a/.build/dune-project +++ b/.build/dune-project @@ -4,7 +4,7 @@ (name affinescript) -(version 0.1.0) +(version 0.1.1) (generate_opam_files true) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3ed732e1..704a7462 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -69,6 +69,20 @@ jobs: - name: Install dependencies run: opam install . --deps-only --yes + - name: Bake release version into source (#297) + # Single source of truth for the compiler version string lives + # in `lib/version.ml`; `dune-project` mirrors it for opam. The + # release workflow rewrites both from the tag so every emitted + # binary self-reports the right number (--version, REPL banner, + # LSP serverInfo, ONNX producer_version). + run: | + v="${GITHUB_REF_NAME#v}" + sed -i "s/^let value = .*/let value = \"$v\"/" lib/version.ml + sed -i "s/^(version .*)/(version $v)/" .build/dune-project + echo "Baked version: $v" + grep '^let value' lib/version.ml + grep '^(version' .build/dune-project + - name: Build release run: opam exec -- dune build --release diff --git a/affinescript.opam b/affinescript.opam index 002b5383..5a9afe88 100644 --- a/affinescript.opam +++ b/affinescript.opam @@ -1,6 +1,6 @@ # This file is generated by dune, edit dune-project instead opam-version: "2.0" -version: "0.1.0" +version: "0.1.1" synopsis: "A programming language with affine types, dependent types, row polymorphism, and extensible effects" description: @@ -23,7 +23,7 @@ doc: "https://github.com/hyperpolymath/affinescript" bug-reports: "https://github.com/hyperpolymath/affinescript/issues" depends: [ "ocaml" {>= "4.14"} - "dune" {>= "3.14" & >= "3.14"} + "dune" {>= "3.14"} "menhir" {>= "20231231"} "sedlex" {>= "3.2"} "ppx_deriving" {>= "5.2"} diff --git a/bin/main.ml b/bin/main.ml index e9ef7a77..499094ab 100644 --- a/bin/main.ml +++ b/bin/main.ml @@ -11,8 +11,9 @@ let () = Fmt_tty.setup_std_outputs () -(** Version string *) -let version = "0.1.0" +(** Version string (single source of truth — see lib/version.ml; baked + from the release tag by .github/workflows/release.yml). *) +let version = Affinescript.Version.value (** Read file contents *) let read_file path = diff --git a/lib/dune b/lib/dune index 3212c65d..7fef36a0 100644 --- a/lib/dune +++ b/lib/dune @@ -73,6 +73,7 @@ types unify value + version wasm wasm_encode wasm_gc diff --git a/lib/lsp_server.ml b/lib/lsp_server.ml index c083c3b5..f681023a 100644 --- a/lib/lsp_server.ml +++ b/lib/lsp_server.ml @@ -313,7 +313,7 @@ let handle_initialize (id : Yojson.Basic.t) (_params : Yojson.Basic.t) : unit = ]); ("serverInfo", `Assoc [ ("name", `String "affinescript"); - ("version", `String "0.1.0"); + ("version", `String Version.value); ]); ] )) diff --git a/lib/onnx_codegen.ml b/lib/onnx_codegen.ml index 8a9029c1..8851bce9 100644 --- a/lib/onnx_codegen.ml +++ b/lib/onnx_codegen.ml @@ -230,7 +230,7 @@ let generate (program : program) (_symbols : Symbol.t) : string = let model = { Onnx_proto.m_ir_version = 7; (* ONNX 1.10+ *) m_producer_name = "affinescript"; - m_producer_version = "0.1.0"; + m_producer_version = Version.value; m_opset_import = [{ op_domain = ""; op_version = 13 }]; m_graph = graph; } in diff --git a/lib/repl.ml b/lib/repl.ml index a8669769..41fe8d71 100644 --- a/lib/repl.ml +++ b/lib/repl.ml @@ -297,7 +297,7 @@ let print_prompt () = (** Print the REPL banner *) let print_banner () = - print_endline "AffineScript REPL v0.1.0"; + Printf.printf "AffineScript REPL v%s\n" Version.value; print_endline "Type :help for help, :quit to exit"; print_endline "" diff --git a/lib/version.ml b/lib/version.ml new file mode 100644 index 00000000..8fa5877f --- /dev/null +++ b/lib/version.ml @@ -0,0 +1,19 @@ +(* SPDX-License-Identifier: MIT OR AGPL-3.0-or-later *) +(* Single source of truth for the compiler version string. + * + * Replaces the five hardcoded "0.1.0" sites that used to drift behind + * the release tag (issue #297): + * + * bin/main.ml — `affinescript --version` + * lib/repl.ml — REPL banner + * lib/lsp_server.ml — LSP `initialize` response + * lib/onnx_codegen.ml — ONNX `producer_version` field on emitted models + * + * The value below is baked at *build* time by the release workflow: + * `.github/workflows/release.yml` sed-substitutes this line (and the + * `(version …)` field in `dune-project`) to match `${GITHUB_REF_NAME}` + * before running `dune build --release`. When building from a non- + * release commit, this reflects whatever was last committed to main, + * matching `dune-project`'s declared version. *) + +let value = "0.1.1"