| 🛟 Updated. 28d5985 k33g 6h ago | 1 | # version |
| 2 | |
| 3 | Tells the editor what build of itself it is: a number, and — when the build recorded them — the commit it came from and when it was linked. |
| 4 | |
| 5 | Imports two things from the standard library and nothing else. No tcell, no `ui`, no files read, no commands run, so asking costs nothing and can be done from anywhere. |
| 6 | |
| 7 | ## There is no version constant |
| 8 | |
| 9 | There used to be, in `app`, and it was wrong for the fourteen commits after somebody last edited it. Nothing in committing, tagging or installing touches a Go constant, and an About box is exactly where a number nobody set gets believed. |
| 10 | |
| 11 | So three sources are consulted in order, and the first that answers wins: |
| 12 | |
| 13 | | Order | Source | Set by | |
| 14 | | --- | --- | --- | |
| 15 | | 1 | `stamp`, `commit`, `built` | `-ldflags -X`, from the Makefile and `scripts/install.sh` | |
| 16 | | 2 | `runtime/debug.ReadBuildInfo()` | The Go tool | |
| 17 | | 3 | `unknown` | Nothing | |
| 18 | |
| 19 | `unknown` is deliberately **not** a number. The failure being designed against is a plausible-looking version nobody set, and a fallback of `0.1.0` would be exactly that. |
| 20 | |
| 21 | ## Two things the build system cannot do |
| 22 | |
| 23 | **It does not read git tags.** A plain `go build .` can never report `0.1.0-14-g88a4c38`, however the code is written. It reports `devel` plus the commit, and the documentation says so rather than implying every build is equal. Anything that wants a tag has to be stamped, which is why the Makefile and the installer both do it. |
| 24 | |
| 25 | **What it reports instead is a pseudo-version** — `v0.1.1-0.20260831165958-88a4c3859bf3` — which `isPseudoVersion` recognises and `fromBuildInfo` reports as `devel`. Shown as written it would claim a `0.1.1` patch release that does not exist. All three of the Go tool's forms end in the same 28-character tail; the character before the timestamp is a dash when no tag precedes the commit and a **dot** when one does, because the base then ends in `-0.` or `-pre.0.`. Getting that wrong is why the check has a test naming each form. |
| 26 | |
| 27 | ## `vcs.time` is not a build date |
| 28 | |
| 29 | It is when the *commit* was made. Every binary is linked later than the commit it was built from, so labelling it "Built" would be false on all of them. A build date appears only when a build stamped one, which is the same rule the About box follows: a fact nobody recorded gets no line rather than an empty one. |
| 30 | |
| 31 | ## Why resolve is separate from Current |
| 32 | |
| 33 | `Current` reads package-level variables the linker wrote and whatever the Go tool recorded — neither of which a test binary can be built into having. `resolve(stamp, commit, built, info)` takes all four as arguments, so every combination in the table above is an ordinary table-driven test with no build flags anywhere. |
| 34 | |
| 35 | ## Public API |
| 36 | |
| 37 | | Name | What it does | |
| 38 | | --- | --- | |
| 39 | | `Info{Number, Commit, Built}` | What a binary knows about its own build; `Commit` and `Built` are empty when nothing recorded them | |
| 40 | | `Current() Info` | What *this* binary knows about itself | |
| 41 | | `(Info) String() string` | Every known part on one line, for `-version` | |
| 42 | | `(Info) BuiltAt() string` | `Built` rendered for a person: `2026-08-31 18:04 UTC` | |
| 43 | |
| 44 | ```go |
| 45 | info := version.Current() |
| 46 | fmt.Printf("%s %s\n", app.Name, info) // Turbo Go 0.2.0 (88a4c38, built …) |
| 47 | |
| 48 | if info.Commit != "" { |
| 49 | fmt.Println("Commit:", info.Commit) |
| 50 | } |
| 51 | ``` |
| 52 | |
| 53 | Stamp it like this — the Makefile and `scripts/install.sh` both do: |
| 54 | |
| 55 | ```sh |
| 56 | go build -ldflags "-X 'codeberg.org/turbo-editors/turbo-core/version.stamp=$(git describe --tags --dirty)'" . |
| 57 | ``` |
| 58 | |
| 59 | ## Anything that ships has to be stamped |
| 60 | |
| 61 | Removing the constant moved a cost that used to be invisible: a build with no `-ldflags` used to carry the last number somebody typed, and now carries `devel`. That is better everywhere except in a **cross-compile**, where nothing else would have noticed — the host binary is stamped and correct while the five downloads say `devel`. |
| 62 | |
| 63 | So `03-build-releases.sh` stamps every platform, taking the flags from `make ldflags` rather than repeating the `-X` paths, and runs the staged binary for its own machine before calling the release built. `release_test.go` holds that line. |
| 64 | |
| 65 | ## Tests |
| 66 | |
| 67 | ```sh |
| 68 | make test |
| 69 | go test ./version/ |
| 70 | ``` |