Report development builds as such, not as the release version
Only a release build (the commit tagged v<VERSION>, unchanged) gives a version number. Others print 'dev <commit> (3 commits after v0.2.0-rc.1)', from git describe (the Makefile's DESCRIBE), in jarld version, jarl --version, jarl status, jarl whoami and the startup log; a build without git says '(source build)'. The CLI's User-Agent and the footer's tooltip follow suit, and /status's build gains since and ahead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
88bb89a9ff
commit
fb1ee09250
7 files changed
+123
-23
No files matched your search
+7
-3
@@ -88,9 +88,13 @@ All notable changes to Jarl are documented here. The format follows
|
||||
linking to the release on Gitea. A build that isn't of a release tag
|
||||
shows its commit instead, linked to the commit and marked `-modified`
|
||||
with uncommitted changes. Before, every build of a commit after a
|
||||
release still showed the release's version. `jarld version`,
|
||||
`jarl --version`, `GET /status` and `/auth/whoami` report the same, the
|
||||
latter two as `build` (docs/development.md).
|
||||
release still showed the release's version. `GET /status` and
|
||||
`/auth/whoami` report the build as `build` (docs/development.md).
|
||||
- `jarld version`, `jarl --version`, `jarl status` and `jarl whoami` give
|
||||
a version number only for release builds. Other builds say they are
|
||||
development builds and how far past the last tag they are: `dev
|
||||
ca0f148b78b6 (3 commits after v0.2.0-rc.1)`. In 0.2.0-rc.1 they still
|
||||
printed `0.2.0-rc.1 (ca0f148b78b6)`.
|
||||
- The view in the zone list, and on the zone page, links to that view,
|
||||
and the views page highlights it. It used to be plain text, and the zone
|
||||
page linked to the views page as a whole.
|
||||
|
||||
@@ -18,7 +18,11 @@ VERSION ?= $(shell cat VERSION 2>/dev/null || echo 0.0.0-dev)
|
||||
# the release rather than the commit): set when HEAD is tagged v$(VERSION)
|
||||
# and no tracked file is changed.
|
||||
RELEASE_TAG ?= $(shell t=v$(VERSION); git tag --points-at HEAD 2>/dev/null | grep -qx "$$t" && git diff --quiet HEAD 2>/dev/null && echo $$t)
|
||||
LDFLAGS := -s -w -X jarl/internal/version.Version=$(VERSION) -X jarl/internal/version.Tag=$(RELEASE_TAG)
|
||||
# DESCRIBE places other builds relative to the last tag ("3 commits after
|
||||
# v0.2.0-rc.1").
|
||||
DESCRIBE ?= $(shell git describe --tags --long --match 'v[0-9]*' --abbrev=12 HEAD 2>/dev/null)
|
||||
LDFLAGS := -s -w -X jarl/internal/version.Version=$(VERSION) -X jarl/internal/version.Tag=$(RELEASE_TAG) \
|
||||
-X jarl/internal/version.Describe=$(DESCRIBE)
|
||||
GOFLAGS := -trimpath
|
||||
export CGO_ENABLED := 0
|
||||
|
||||
|
||||
+12
-6
@@ -232,17 +232,23 @@ runs it as a check before building.
|
||||
|
||||
### Which version a build reports
|
||||
|
||||
The footer of the web UI, `jarld version` and `jarl --version` say what a
|
||||
binary was built from, linking to it on Gitea:
|
||||
The footer of the web UI, `jarld version`, `jarl --version`, `jarl status`
|
||||
and `jarl whoami` say what a binary was built from (the footer links to
|
||||
it on Gitea). Only a release build reports a version number:
|
||||
|
||||
* **A release**: `make` run on the commit tagged `v<VERSION>` with no
|
||||
tracked file changed. The Makefile then sets `RELEASE_TAG`, and the
|
||||
footer reads "Powered by Jarl v0.2.0", linking to the release. The
|
||||
release workflow sets `RELEASE_TAG` itself.
|
||||
* **Any other build**: the commit, which Go records from git: "Powered by
|
||||
Jarl 1a2b3c4d5e6f", linking to the commit. With uncommitted changes it
|
||||
is marked `-modified`. The version commands print `0.2.0 (1a2b3c4d5e6f)`.
|
||||
* **No git** (a build from a source tarball): just `VERSION`.
|
||||
* **Any other build** is a development build, named by its commit (which
|
||||
Go records from git) rather than `VERSION`: "Powered by Jarl
|
||||
1a2b3c4d5e6f", linking to the commit. With uncommitted changes it is
|
||||
marked `-modified`. The other places add where it stands relative to
|
||||
the last tag, from `git describe` (the Makefile's `DESCRIBE`):
|
||||
`dev 1a2b3c4d5e6f (3 commits after v0.2.0-rc.1)`, or
|
||||
`dev 1a2b3c4d5e6f-modified (v0.2.0-rc.1 with uncommitted changes)`.
|
||||
* **No git** (a build from a source archive): `VERSION`, marked as such:
|
||||
`0.2.0 (source build)`.
|
||||
|
||||
`RELEASE_TAG=v0.2.0 make` forces the first case.
|
||||
|
||||
|
||||
@@ -183,7 +183,7 @@ func (c *Client) Do(ctx context.Context, method, path string, query url.Values,
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
}
|
||||
req.Header.Set("Accept", "application/json")
|
||||
req.Header.Set("User-Agent", "jarl-cli/"+version.Version)
|
||||
req.Header.Set("User-Agent", "jarl-cli/"+version.Short())
|
||||
if c.Token != "" {
|
||||
req.Header.Set("Authorization", "Bearer "+c.Token)
|
||||
}
|
||||
|
||||
@@ -4,12 +4,17 @@
|
||||
//
|
||||
// The Makefile sets Version from the VERSION file, and Tag only when the
|
||||
// build is of that release: HEAD is the tag v<VERSION> and no tracked file
|
||||
// is changed. Other builds are identified by their commit, which Go
|
||||
// records from git by itself.
|
||||
// is changed. Only such a build reports a version number. Other builds
|
||||
// are development builds, identified by their commit (which Go records
|
||||
// from git by itself) and by where they stand relative to the last tag
|
||||
// (Describe, from git describe).
|
||||
package version
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
@@ -23,6 +28,11 @@ var Tag = ""
|
||||
// information when not set at build time.
|
||||
var Commit = ""
|
||||
|
||||
// Describe is 'git describe --tags --long' of the build's commit
|
||||
// ("v0.2.0-rc.1-3-gca0f148b78b6"), set by the Makefile; it says how many
|
||||
// commits a development build is past the last tag.
|
||||
var Describe = ""
|
||||
|
||||
// Repo is Jarl's source repository.
|
||||
const Repo = "https://gitea.adbraun.lol/adam/jarl"
|
||||
|
||||
@@ -32,6 +42,11 @@ type Build struct {
|
||||
Tag string `json:"tag,omitempty"`
|
||||
Commit string `json:"commit,omitempty"`
|
||||
Modified bool `json:"modified,omitempty"` // built with uncommitted changes
|
||||
// Since is the last tag before a development build's commit, and
|
||||
// Ahead how many commits the build is past it (0: the tag's commit,
|
||||
// with uncommitted changes).
|
||||
Since string `json:"since,omitempty"`
|
||||
Ahead int `json:"ahead,omitempty"`
|
||||
// Label is the short form to show: the tag of a release, otherwise
|
||||
// the abbreviated commit (or the version when the commit is unknown).
|
||||
Label string `json:"label"`
|
||||
@@ -53,9 +68,23 @@ var info = sync.OnceValue(func() Build {
|
||||
}
|
||||
}
|
||||
}
|
||||
return describe(Version, Tag, commit, modified)
|
||||
b := describe(Version, Tag, commit, modified)
|
||||
b.Since, b.Ahead = parseDescribe(Describe, b.Commit)
|
||||
return b
|
||||
})
|
||||
|
||||
// parseDescribe splits git describe --long output, if it is of commit.
|
||||
func parseDescribe(d, commit string) (since string, ahead int) {
|
||||
m := describeRe.FindStringSubmatch(d)
|
||||
if m == nil || commit == "" || !strings.HasPrefix(commit, m[3]) {
|
||||
return "", 0
|
||||
}
|
||||
n, _ := strconv.Atoi(m[2])
|
||||
return m[1], n
|
||||
}
|
||||
|
||||
var describeRe = regexp.MustCompile(`^(v.+)-(\d+)-g([0-9a-f]+)$`)
|
||||
|
||||
func describe(version, tag, commit string, modified bool) Build {
|
||||
b := Build{Version: version, Tag: tag, Commit: commit, Modified: modified}
|
||||
switch {
|
||||
@@ -76,14 +105,41 @@ func describe(version, tag, commit string, modified bool) Build {
|
||||
// Info describes this build.
|
||||
func Info() Build { return info() }
|
||||
|
||||
// String is the version for logs and 'version' commands: "0.2.0" for a
|
||||
// release, otherwise the version and the commit ("0.2.0-dev (a1b2c3d4e5f6)").
|
||||
func String() string {
|
||||
b := Info()
|
||||
if b.Tag != "" || b.Commit == "" {
|
||||
// String is the version for logs and 'version' commands. Only a release
|
||||
// build gives a version ("0.2.0"); any other build says it's a
|
||||
// development build: "dev a1b2c3d4e5f6 (3 commits after v0.2.0-rc.1)".
|
||||
func String() string { return Info().String() }
|
||||
|
||||
func (b Build) String() string {
|
||||
switch {
|
||||
case b.Tag != "":
|
||||
return b.Version
|
||||
case b.Commit == "":
|
||||
// No git information (built from a source archive).
|
||||
return b.Version + " (source build)"
|
||||
}
|
||||
return b.Version + " (" + b.Label + ")"
|
||||
s := "dev " + b.Label
|
||||
switch {
|
||||
case b.Since == "":
|
||||
case b.Ahead == 1:
|
||||
s += " (1 commit after " + b.Since + ")"
|
||||
case b.Ahead > 1:
|
||||
s += " (" + strconv.Itoa(b.Ahead) + " commits after " + b.Since + ")"
|
||||
case b.Modified:
|
||||
s += " (" + b.Since + " with uncommitted changes)"
|
||||
default:
|
||||
s += " (at " + b.Since + ")"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Short is the version for a User-Agent: the version of a release,
|
||||
// otherwise the label ("a1b2c3d4e5f6").
|
||||
func Short() string {
|
||||
if b := Info(); b.Tag == "" && b.Commit != "" {
|
||||
return b.Label
|
||||
}
|
||||
return Version
|
||||
}
|
||||
|
||||
func short(commit string) string {
|
||||
|
||||
@@ -20,3 +20,30 @@ func TestDescribe(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestString(t *testing.T) {
|
||||
const c = "ca0f148b78b6e1f0a9b8c7d6e5f4a3b2c1d0e9f8"
|
||||
build := func(tag, commit string, modified bool, desc string) Build {
|
||||
b := describe("0.2.0-rc.1", tag, commit, modified)
|
||||
b.Since, b.Ahead = parseDescribe(desc, b.Commit)
|
||||
return b
|
||||
}
|
||||
for _, tc := range []struct {
|
||||
b Build
|
||||
want string
|
||||
}{
|
||||
{build("v0.2.0-rc.1", c, false, "v0.2.0-rc.1-0-gca0f148b78b6"), "0.2.0-rc.1"},
|
||||
{build("", c, false, "v0.2.0-rc.1-3-gca0f148b78b6"), "dev ca0f148b78b6 (3 commits after v0.2.0-rc.1)"},
|
||||
{build("", c, true, "v0.2.0-rc.1-1-gca0f148b78b6"), "dev ca0f148b78b6-modified (1 commit after v0.2.0-rc.1)"},
|
||||
{build("", c, true, "v0.2.0-rc.1-0-gca0f148b78b6"), "dev ca0f148b78b6-modified (v0.2.0-rc.1 with uncommitted changes)"},
|
||||
{build("", c, false, "v0.1.0-0-gca0f148b78b6"), "dev ca0f148b78b6 (at v0.1.0)"},
|
||||
{build("", c, false, ""), "dev ca0f148b78b6"},
|
||||
// A describe of another commit (stale ldflags) is ignored.
|
||||
{build("", c, false, "v0.2.0-rc.1-3-gdeadbeef0000"), "dev ca0f148b78b6"},
|
||||
{build("", "", false, ""), "0.2.0-rc.1 (source build)"},
|
||||
} {
|
||||
if got := tc.b.String(); got != tc.want {
|
||||
t.Errorf("String() = %q, want %q", got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -173,10 +173,13 @@ let modeHolder;
|
||||
// builds, linked to it in the repository.
|
||||
function footer(b) {
|
||||
if (!b) return null;
|
||||
const what = b.tag ? "release " + b.tag
|
||||
: b.commit ? "commit " + b.commit + (b.modified ? ", with uncommitted changes" : "") : "version " + b.version;
|
||||
let title = b.tag ? "Jarl " + b.version + " (release " + b.tag + ")" : "Jarl " + b.version + " (built without git)";
|
||||
if (!b.tag && b.commit) {
|
||||
title = "Development build of commit " + b.commit + (b.modified ? " with uncommitted changes" : "");
|
||||
if (b.since) title += b.ahead ? ", " + b.ahead + (b.ahead === 1 ? " commit" : " commits") + " after " + b.since : ", at " + b.since;
|
||||
}
|
||||
return h("footer", { class: "site" }, "Powered by ",
|
||||
h("a", { href: b.url, target: "_blank", rel: "noopener", title: "Jarl " + b.version + ", built from " + what }, "Jarl " + b.label));
|
||||
h("a", { href: b.url, target: "_blank", rel: "noopener", title }, "Jarl " + (b.tag || b.commit ? b.label : b.version)));
|
||||
}
|
||||
|
||||
function renderNav() {
|
||||
|
||||
Reference in new issue
Block a user