Versioning: introduce tags, releases, changesets & toolchain packaging #33

Closed
opened 2026-08-30 12:50:29 +02:00 by orkun · 1 comment
Owner

Problem

The project has no version control discipline beyond raw commits:

  • 0 git tags, no releases, no CHANGELOG.
  • No versioning scheme for the language/compiler, no packaging of the toolchain
    (ludicc, ludic, x, ludic-fmt, ludic-lsp) for consumers.
  • There's no way to say "this program targets Ludic vX" or to pin a compiler
    version — a real problem as the language is actively renaming builtins/keywords
    (fn→function, str→string, ptr→pointer, …).

Proposal

Introduce lightweight release management:

  • Adopt a versioning scheme (SemVer-ish; the compiler self-reports its version
    via ludicc --version).
  • Adopt changesets: each user-facing change adds a small changeset entry;
    releasing aggregates them into CHANGELOG.md and bumps the version. (A native
    Ludic or bin/x-driven changeset flow is preferable to a Node tool, to stay
    consistent with the "no external toolchain" goal — but pick what's pragmatic.)
  • Tag + release on Forgejo: bin/x release builds the toolchain binaries,
    tags vX.Y.Z, and attaches build artifacts to a Forgejo release.
  • Decide a packaging story for the toolchain (tarball of bin/ + seed, or a
    reproducible bootstrap from a tagged source).

Acceptance criteria

  • Versioning scheme defined; --version reports it.
  • Changeset workflow in place; CHANGELOG.md generated on release.
  • bin/x release tags and publishes a Forgejo release with artifacts.
  • First v0.x.0 tagged from current main.

Part of the repository-cleanup / DX pass. Depends on CI/CD being in place.

## Problem The project has **no version control discipline beyond raw commits**: - **0 git tags**, no releases, no `CHANGELOG`. - No versioning scheme for the language/compiler, no packaging of the toolchain (`ludicc`, `ludic`, `x`, `ludic-fmt`, `ludic-lsp`) for consumers. - There's no way to say "this program targets Ludic vX" or to pin a compiler version — a real problem as the language is actively renaming builtins/keywords (`fn`→`function`, `str`→`string`, `ptr`→`pointer`, …). ## Proposal Introduce lightweight release management: - Adopt a **versioning scheme** (SemVer-ish; the compiler self-reports its version via `ludicc --version`). - Adopt **changesets**: each user-facing change adds a small changeset entry; releasing aggregates them into `CHANGELOG.md` and bumps the version. (A native Ludic or `bin/x`-driven changeset flow is preferable to a Node tool, to stay consistent with the "no external toolchain" goal — but pick what's pragmatic.) - **Tag + release** on Forgejo: `bin/x release` builds the toolchain binaries, tags `vX.Y.Z`, and attaches build artifacts to a Forgejo release. - Decide a **packaging** story for the toolchain (tarball of `bin/` + seed, or a reproducible bootstrap from a tagged source). ## Acceptance criteria - [ ] Versioning scheme defined; `--version` reports it. - [ ] Changeset workflow in place; `CHANGELOG.md` generated on release. - [ ] `bin/x release` tags and publishes a Forgejo release with artifacts. - [ ] First `v0.x.0` tagged from current `main`. Part of the repository-cleanup / DX pass. Depends on CI/CD being in place.
orkun added the
priority:medium
area:ci
dx
labels 2026-08-30 12:50:29 +02:00
Author
Owner

Done — and v0.1.0 is cut and published: https://git.workshopsoft.io/workshopsoft/ludic/releases/tag/v0.1.0 (release id 1, with source + darwin-arm64 toolchain tarballs attached). The release commit itself went green through CI (build + bootstrap-cfree + commit-lint).

Implemented in fed80f2 (tooling) and cut with x release minor --publish (commit 2e9081c, tag v0.1.0).

Design — native, no Node:

  • Versioning: SemVer, with VERSION as the single source of truth. ludicc --version / ludic --version read it at runtime, so a bump touches one file and never reseeds the compiler. x version reports it too.
    $ ludicc --version
    ludic 0.1.0
    
  • Changesets: one small Markdown file per user-facing change under changes/ (bump: level + type: + summary; see changes/README.md). Mergeable, reviewable, and it replaces "remember to hand-edit the changelog." No Node changeset tool.
  • x release [major|minor|patch] [--publish]: folds the pending changesets into a new CHANGELOG.md section (bulleted, grouped by type), bumps VERSION, commits chore(release): vX.Y.Z, and tags it. The level defaults to the highest changeset bump:. --publish also pushes and creates the Forgejo release with the two tarballs. The one piece that speaks HTTP is tools/ci/forgejo_release.py (stdlib-Python, matching the docgen tooling) — it can move into x once the native Http client (#6) lands.

Packaging / reproducibility: the tag is the reproducible bootstrap point — the -src.tar.gz (source + checked-in seed) rebuilds that exact toolchain with clang alone; the -darwin-arm64.tar.gz is the prebuilt bin/.

Acceptance criteria:

  • Versioning scheme defined; --version reports it.
  • Changeset workflow in place; CHANGELOG.md generated on release.
  • x release tags and publishes a Forgejo release with artifacts.
  • First v0.x.0 tagged from current main (v0.1.0).

Depended on CI (#32), now in place. Documented in CONTRIBUTING.md (a new "Versioning & releases" section + a changeset step in the stdlib workflow) and README. This also delivers the safe, non-destructive v0 baseline that #34 deferred here — the messy Phase-era prefix is now bracketed by a real tag without rewriting a single commit.

A bug caught in a throwaway dry-run before anything touched main: the bump-level derivation was reading changes/README.md's format example (bump: minor) as a real changeset; highest_bump() now excludes the README.

Follow-up worth its own issue: a prebuilt CI image so releases (and CI) skip the per-run apt-get.

Done — and **v0.1.0 is cut and published**: https://git.workshopsoft.io/workshopsoft/ludic/releases/tag/v0.1.0 (release id 1, with source + `darwin-arm64` toolchain tarballs attached). The release commit itself went green through CI (build + bootstrap-cfree + commit-lint). Implemented in fed80f2 (tooling) and cut with `x release minor --publish` (commit 2e9081c, tag `v0.1.0`). **Design — native, no Node:** - **Versioning:** SemVer, with `VERSION` as the single source of truth. `ludicc --version` / `ludic --version` read it *at runtime*, so a bump touches one file and never reseeds the compiler. `x version` reports it too. ``` $ ludicc --version ludic 0.1.0 ``` - **Changesets:** one small Markdown file per user-facing change under `changes/` (`bump:` level + `type:` + summary; see `changes/README.md`). Mergeable, reviewable, and it replaces "remember to hand-edit the changelog." No Node changeset tool. - **`x release [major|minor|patch] [--publish]`:** folds the pending changesets into a new `CHANGELOG.md` section (bulleted, grouped by type), bumps `VERSION`, commits `chore(release): vX.Y.Z`, and tags it. The level defaults to the highest changeset `bump:`. `--publish` also pushes and creates the Forgejo release with the two tarballs. The one piece that speaks HTTP is `tools/ci/forgejo_release.py` (stdlib-Python, matching the docgen tooling) — it can move into `x` once the native Http client (#6) lands. **Packaging / reproducibility:** the tag *is* the reproducible bootstrap point — the `-src.tar.gz` (source + checked-in seed) rebuilds that exact toolchain with clang alone; the `-darwin-arm64.tar.gz` is the prebuilt `bin/`. **Acceptance criteria:** - [x] Versioning scheme defined; `--version` reports it. - [x] Changeset workflow in place; `CHANGELOG.md` generated on release. - [x] `x release` tags and publishes a Forgejo release with artifacts. - [x] First `v0.x.0` tagged from current `main` (v0.1.0). Depended on CI (#32), now in place. Documented in CONTRIBUTING.md (a new "Versioning & releases" section + a changeset step in the stdlib workflow) and README. This also delivers the safe, non-destructive `v0` baseline that #34 deferred here — the messy `Phase`-era prefix is now bracketed by a real tag without rewriting a single commit. A bug caught in a throwaway dry-run before anything touched `main`: the bump-level derivation was reading `changes/README.md`'s format example (`bump: minor`) as a real changeset; `highest_bump()` now excludes the README. Follow-up worth its own issue: a prebuilt CI image so releases (and CI) skip the per-run `apt-get`.
orkun closed this issue 2026-08-30 22:51:05 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: workshopsoft/ludic#33
No description provided.