summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md6
-rw-r--r--Makefile26
-rw-r--r--bin/main.ml15
-rw-r--r--colitur.opam1
-rw-r--r--dune-project1
-rw-r--r--test/cli.t18
6 files changed, 66 insertions, 1 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..1c5d1fb
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,6 @@
+# Changelog
+
+One line per release. Versions are git tags (`vX.Y.Z`).
+
+## [0.1.0] - 2026-08-17
+- First tag. The Extraordinary Form (1962 Roman Missal) end to end: the complete temporal cycle, the resolution engine (occurrence, precedence, commemorations, transfers) against the sanctoral calendar, and the Mass reading citations for every day — correct and total over 1583–9999, with no clock, randomness or environment read below the CLI. Four commands (`easter`, `temporal`, `day`, `readings`) plus `--help`/`--version`, a man page, and a Makefile that installs binary, calendar data and man page into `~/.local` by default. Validated in five layers: types, QCheck properties over every year in the domain, a 16 801-day differential against the sibling lectio engine, two independent missalemeum oracle windows (2026–2027 and 2038), and ~36 hand-verified golden pins — 375 tests. Rules are computed against the Missal and its *Rubricae Generales*, with every published-calendar divergence adjudicated against the primary text rather than adopted; several are resolved in this engine's favour and cited in the register. Not included: the Ordinary Form, the chants (Psalm/Gradual/Tract/Alleluia/Sequence, deliberately rejected rather than guessed), and template-driven output.
diff --git a/Makefile b/Makefile
index 75372ac..f90d32e 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ MANDIR := $(PREFIX)/share/man/man1
# over documenting the dune commands.
DUNE := opam exec --
-.PHONY: help build test check install uninstall reinstall clean fmt man doc
+.PHONY: help build test check install uninstall reinstall clean fmt man doc release
help: ## show this help
@grep -hE '^[a-z-]+:.*##' $(MAKEFILE_LIST) | sed -E 's/:.*## /\t/' | sort
@@ -53,3 +53,27 @@ fmt: ## format the OCaml sources
clean: ## remove build artifacts
$(DUNE) dune clean
+
+# Mirrors lectio's own release target, including its refusals: no release from
+# a dirty tree, no release without a CHANGELOG line, and no release whose
+# version bump silently failed to apply. The version lives in TWO places
+# (dune-project, which feeds colitur.opam, and bin/main.ml's own constant,
+# which is what --version prints), so both are rewritten and both are
+# re-checked -- a release that bumped one and not the other would ship a
+# binary disagreeing with its own package metadata.
+release: ## cut a release: make release VERSION=0.1.0 (add its CHANGELOG line first)
+ @test -n "$(VERSION)" || { echo "set VERSION=X.Y.Z" >&2; exit 2; }
+ @echo "$(VERSION)" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$$' || { echo "VERSION must be X.Y.Z" >&2; exit 2; }
+ @test -z "$$(git status --porcelain)" || { echo "working tree not clean; commit or stash first" >&2; exit 2; }
+ @grep -q '## \[$(VERSION)\]' CHANGELOG.md || { echo "add a one-line CHANGELOG.md entry under '## [$(VERSION)]' first" >&2; exit 2; }
+ @sed -i 's/^(version .*)$$/(version $(VERSION))/' dune-project
+ @sed -i 's/^let version = ".*"/let version = "$(VERSION)"/' bin/main.ml
+ @grep -q '^(version $(VERSION))$$' dune-project || { echo "dune-project version bump failed" >&2; exit 2; }
+ @grep -q '^let version = "$(VERSION)"' bin/main.ml || { echo "bin/main.ml version bump failed" >&2; exit 2; }
+ $(MAKE) check
+ @test "$$($(DUNE) dune exec --no-build colitur -- --version)" = "$(VERSION)" || \
+ { echo "the built binary does not report $(VERSION)" >&2; exit 2; }
+ git add dune-project colitur.opam bin/main.ml CHANGELOG.md
+ git commit -m "release: v$(VERSION)"
+ git tag -a "v$(VERSION)" -m "colitur $(VERSION)"
+ @echo "tagged v$(VERSION). publish with: git push origin main v$(VERSION)"
diff --git a/bin/main.ml b/bin/main.ml
index 573f190..141f016 100644
--- a/bin/main.ml
+++ b/bin/main.ml
@@ -336,6 +336,17 @@ let readings_report y = resolved_year_report ~line:readings_line y
pager or grepped); being invoked wrongly is an error, so [usage] prints a
one-liner to stderr and exits 2, keeping stdout clean for whatever the
caller was really trying to capture. *)
+(* Kept in lockstep with dune-project's own [(version ...)] by `make release`,
+ which bumps BOTH and refuses to proceed if either edit did not take. Two
+ places rather than one because dune's watermarking (`dune subst`) only
+ substitutes in a release tarball, not in a plain `dune build` from a
+ checkout, so a binary built the ordinary way would report a placeholder.
+ A constant edited by the release target is what lectio does too, for the
+ same reason. Deliberately NOT embedded in [help_text]: the cram test pins
+ help's first line, and a version in it would make every release edit a
+ test expectation for no gain. *)
+let version = "0.1.0"
+
let help_text =
{|colitur -- deterministic liturgical calendar engine (Roman rite, 1962)
@@ -345,6 +356,7 @@ usage:
colitur day <year> the resolved day identity, one line per day
colitur readings <year> the Mass reading citations, one line per day
colitur -h, --help this help
+ colitur -V, --version print the version and exit
<year> is a civil year, 1583..9999 inclusive. Each report covers 1 January to
31 December of that year, not a liturgical year.
@@ -394,6 +406,9 @@ let with_year ys f =
let () =
match Sys.argv with
| [| _; ("-h" | "--help" | "help") |] -> print_help ()
+ | [| _; ("-V" | "--version" | "version") |] ->
+ print_endline version;
+ exit 0
| [| _; "easter"; ys |] -> with_year ys easter_report
| [| _; "temporal"; ys |] -> with_year ys temporal_report
| [| _; "day"; ys |] -> with_year ys day_report
diff --git a/colitur.opam b/colitur.opam
index 3edcfa4..12d0e2b 100644
--- a/colitur.opam
+++ b/colitur.opam
@@ -1,5 +1,6 @@
# This file is generated by dune, edit dune-project instead
opam-version: "2.0"
+version: "0.1.0"
synopsis: "Deterministic liturgical calendar engine (computus liturgicus)"
depends: [
"ocaml"
diff --git a/dune-project b/dune-project
index 91824f4..ccef6df 100644
--- a/dune-project
+++ b/dune-project
@@ -1,5 +1,6 @@
(lang dune 3.0)
(name colitur)
+(version 0.1.0)
(generate_opam_files true)
(cram enable)
diff --git a/test/cli.t b/test/cli.t
index d7e86f7..419e7f0 100644
--- a/test/cli.t
+++ b/test/cli.t
@@ -241,3 +241,21 @@ Every command the help lists is a command the binary actually accepts. This
is the check that catches help text drifting away from the dispatch:
$ for c in easter temporal day readings; do colitur $c 2026 > /dev/null || echo "$c FAILED"; done
+
+--version prints the version alone, to standard output, exit 0. Deliberately
+not embedded in the help text above: this pin would then have to be edited
+every release, for no gain. The Makefile's release target asserts the built
+binary reports the version it just wrote, so the two cannot drift.
+
+ $ colitur --version
+ 0.1.0
+
+ $ colitur -V
+ 0.1.0
+
+Agreement with the package metadata (dune-project's own (version ...), which
+generates colitur.opam) is NOT asserted here: the cram sandbox has no source
+tree to read dune-project from. It is asserted in the Makefile's release
+target instead, which rewrites both and then requires the freshly built
+binary to report the version it just wrote -- the point in time where a drift
+between the two could actually be introduced.