chore: semver-compliant version for dev and nightly builds (#32663)

This commit is contained in:
andig 2026-08-09 15:00:31 +02:00 • committed by GitHub
parent c1fac30171
commit 09c2ce3055
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 103 additions and 64 deletions

View file

@ -11,7 +11,7 @@ builds:
- -trimpath
- -tags=release
ldflags:
- -X github.com/evcc-io/evcc/util.Version={{ .Tag }} -X github.com/evcc-io/evcc/util.Commit={{ .ShortCommit }} -s -w
- -X github.com/evcc-io/evcc/util.Version={{ .Version }} -X github.com/evcc-io/evcc/util.Commit={{ .ShortCommit }} -s -w
env:
- CGO_ENABLED=0
goos:
@ -56,7 +56,8 @@ checksum:
name_template: "checksums.txt"
snapshot:
version_template: '{{ .Version }}{{ if eq (len (split .Version ".")) 2 }}.0{{ end }}+{{ .Timestamp }}'
# semver pre-release of the upcoming version
version_template: "{{ incminor .Version }}-dev+{{ .ShortCommit }}"
changelog:
sort: asc

View file

@ -63,7 +63,8 @@ checksum:
name_template: "checksums.txt"
snapshot:
version_template: "{{ .Tag }}-next"
# semver pre-release of the upcoming version
version_template: "{{ incminor .Version }}-dev+{{ .ShortCommit }}"
changelog:
sort: asc

View file

@ -1,6 +1,13 @@
# build vars
TAG_NAME ?= $(shell test -d .git && git describe --abbrev=0 --tags)
# part of the latest tag incremented for untagged builds: minor or patch
BUMP ?= minor
SHA ?= $(shell test -d .git && git rev-parse --short HEAD)
GIT_TAG := $(shell test -d .git && git describe --abbrev=0 --tags)
# commits since the latest tag, empty or 0 means the commit is tagged
GIT_DIST := $(shell test -n "$(GIT_TAG)" && git rev-list --count $(GIT_TAG)..HEAD)
NEXT_TAG = $(shell echo $(GIT_TAG) | awk -F. -v b='$(BUMP)' '{if (b == "patch") $$NF++; else {$$2++; $$3=0}} 1' OFS=.)
# untagged builds are semver pre-releases of the upcoming version
TAG_NAME ?= $(if $(filter-out 0,$(GIT_DIST)),$(NEXT_TAG)-dev+$(SHA),$(GIT_TAG))
COMMIT := $(SHA)
# hide commit for releases
ifeq ($(RELEASE),1)

View file

@ -47,7 +47,6 @@ export default {
component: AboutModal,
argTypes: {
installed: { control: "text" },
commit: { control: "text" },
availableVersion: { control: "text" },
releaseNotes: { control: "text" },
hasUpdater: { control: "boolean" },
@ -95,9 +94,7 @@ StableUpdateWithUpdater.args = {
export const Nightly = Template.bind({});
Nightly.args = {
installed: "0.303.1",
commit: "5ce7be4a9f3b2c1d",
availableVersion: "0.303.1",
installed: "0.304.0-dev+5ce7be4",
};
export const DevBuild = Template.bind({});

View file

@ -36,25 +36,14 @@
<td v-if="development">---</td>
<td v-else>
<div class="d-flex flex-wrap column-gap-2 align-items-baseline">
<span class="text-nowrap">
<a
:href="releaseNotesUrl(installed)"
class="text-nowrap"
:href="nightly ? githubCommitUrl : releaseNotesUrl(installed)"
target="_blank"
rel="noopener noreferrer"
>
v{{ installed }}
</a>
<template v-if="nightly">
(<a
:href="githubCommitUrl"
target="_blank"
rel="noopener noreferrer"
><span class="font-monospace">{{
shortCommit
}}</span></a
>)
</template>
</span>
<span
v-if="!nightly && !newVersionAvailable"
class="text-muted text-nowrap"
@ -162,7 +151,7 @@ import {
isDevelopment,
isNightly,
getReleaseName,
shortCommit,
commitFromVersion,
isNewVersionAvailable,
} from "@/utils/version";
import { defineComponent } from "vue";
@ -175,7 +164,6 @@ export default defineComponent({
components: { GenericModal, Logo },
props: {
installed: { type: String, default: "" },
commit: String,
availableVersion: String,
releaseNotes: String,
hasUpdater: Boolean,
@ -198,10 +186,10 @@ export default defineComponent({
return isDevelopment(this.installed);
},
nightly() {
return isNightly(this.installed, this.commit);
return isNightly(this.installed);
},
releaseName() {
return getReleaseName(this.installed, this.commit);
return getReleaseName(this.installed);
},
websiteUrl() {
return this.customWebsite || EVCC_WEBSITE;
@ -219,11 +207,8 @@ export default defineComponent({
githubDependenciesUrl() {
return `${GITHUB_REPO}/network/dependencies`;
},
shortCommit() {
return shortCommit(this.commit);
},
githubCommitUrl() {
return `${GITHUB_REPO}/commit/${this.commit}`;
return `${GITHUB_REPO}/commit/${commitFromVersion(this.installed)}`;
},
modalSize() {
return this.newVersionAvailable ? undefined : "sm";

View file

@ -36,7 +36,6 @@
:auth-disabled="authDisabled"
:evopt="evopt"
:installed="installed"
:commit="commit"
:available-version="availableVersion"
:custom-brand="customBrand"
/>
@ -77,7 +76,6 @@ export default defineComponent({
startupCompleted: Boolean,
evopt: { type: Object as PropType<EvOpt>, required: false },
installed: String,
commit: String,
availableVersion: String,
customBrand: String,
},

View file

@ -19,7 +19,6 @@
:auth-disabled="authDisabled"
:evopt="evopt"
:installed="installed"
:commit="commit"
:available-version="availableVersion"
:custom-brand="customBrand"
@close="open = false"
@ -51,7 +50,6 @@ export default defineComponent({
authDisabled: Boolean,
evopt: { type: Object as PropType<EvOpt>, required: false },
installed: String,
commit: String,
availableVersion: String,
customBrand: String,
},

View file

@ -110,7 +110,6 @@ export default defineComponent({
authDisabled: Boolean,
evopt: { type: Object as PropType<EvOpt>, required: false },
installed: String,
commit: String,
availableVersion: String,
customBrand: String,
},
@ -144,7 +143,7 @@ export default defineComponent({
return "bg-warning";
},
versionLabel() {
return getShortVersion(this.installed || "", this.commit);
return getShortVersion(this.installed || "");
},
newVersionAvailable() {
return isNewVersionAvailable(this.installed, this.availableVersion);

View file

@ -8,7 +8,6 @@ declare global {
app: any;
evcc?: {
version: string;
commit: string;
customCss: boolean;
customLogo: boolean;
customBrand: string;

View file

@ -0,0 +1,63 @@
import { describe, expect, test } from "vite-plus/test";
import {
isDevelopment,
isNightly,
commitFromVersion,
getReleaseName,
getShortVersion,
isNewVersionAvailable,
} from "./version";
const DEV = "0.0.0";
const NIGHTLY = "0.304.0-dev+abc1234";
const STABLE = "0.303.1";
describe("isDevelopment", () => {
test("only dev builds", () => {
expect(isDevelopment(DEV)).toBe(true);
expect(isDevelopment(NIGHTLY)).toBe(false);
expect(isDevelopment(STABLE)).toBe(false);
});
});
describe("isNightly", () => {
test("only versions with build metadata", () => {
expect(isNightly(DEV)).toBe(false);
expect(isNightly(NIGHTLY)).toBe(true);
expect(isNightly(STABLE)).toBe(false);
});
});
describe("commitFromVersion", () => {
test("extracts build metadata", () => {
expect(commitFromVersion(NIGHTLY)).toBe("abc1234");
expect(commitFromVersion(STABLE)).toBe("");
});
});
describe("getReleaseName", () => {
test("maps version to release name", () => {
expect(getReleaseName(DEV)).toBe("development");
expect(getReleaseName(NIGHTLY)).toBe("nightly");
expect(getReleaseName(STABLE)).toBe("stable");
});
});
describe("getShortVersion", () => {
test("formats version", () => {
expect(getShortVersion(DEV)).toBe("dev build");
expect(getShortVersion(NIGHTLY)).toBe("v0.304.0-dev+abc1234");
expect(getShortVersion(STABLE)).toBe("v0.303.1");
});
});
describe("isNewVersionAvailable", () => {
test("never for dev builds", () => {
expect(isNewVersionAvailable(DEV, "0.303.1")).toBe(false);
});
test("only when available differs", () => {
expect(isNewVersionAvailable(STABLE, "0.303.1")).toBe(false);
expect(isNewVersionAvailable("0.303.0", "0.303.1")).toBe(true);
expect(isNewVersionAvailable(STABLE, undefined)).toBe(false);
});
});

View file

@ -1,24 +1,24 @@
export function isDevelopment(version: string): boolean {
return version === "[[.Version]]" || version === "0.0.0";
return version === "0.0.0";
}
export function isNightly(version: string, commit?: string): boolean {
return !isDevelopment(version) && !!commit;
// untagged builds carry the commit as build metadata: 0.304.0-dev+abc1234
export function isNightly(version: string): boolean {
return version.includes("+");
}
export function getReleaseName(version: string, commit?: string): string {
export function commitFromVersion(version: string): string {
return version.split("+")[1] ?? "";
}
export function getReleaseName(version: string): string {
if (isDevelopment(version)) return "development";
if (isNightly(version, commit)) return "nightly";
if (isNightly(version)) return "nightly";
return "stable";
}
export function shortCommit(commit?: string): string {
return commit?.substring(0, 7) || "";
}
export function getShortVersion(version: string, commit?: string): string {
export function getShortVersion(version: string): string {
if (isDevelopment(version)) return "dev build";
if (isNightly(version, commit)) return `v${version} (${shortCommit(commit)})`;
return `v${version}`;
}

View file

@ -105,7 +105,6 @@ export default defineComponent({
aboutModalProps() {
return {
installed: window.evcc?.version,
commit: window.evcc?.commit,
customLogo: this.custom.logo,
customBrand: this.custom.brand,
customWebsite: this.custom.website,
@ -117,7 +116,6 @@ export default defineComponent({
bottomTabBarProps() {
return {
installed: window.evcc?.version,
commit: window.evcc?.commit,
customBrand: this.custom.brand,
...this.collectProps(BottomTabBar, this.state),
};

View file

@ -45,7 +45,6 @@ func getPreferredLanguage(header string) string {
func globalsJsHandler(custom Customization) http.HandlerFunc {
globals := struct {
Version string `json:"version"`
Commit string `json:"commit"`
CustomCss bool `json:"customCss"`
CustomLogo bool `json:"customLogo"`
Brand string `json:"customBrand"`
@ -54,7 +53,6 @@ func globalsJsHandler(custom Customization) http.HandlerFunc {
Phone string `json:"customPhone"`
}{
Version: util.Version,
Commit: util.Commit,
CustomCss: custom.Css != "",
CustomLogo: custom.LogoLight != "",
Brand: custom.Brand,

View file

@ -1,9 +1,6 @@
package util
import (
"fmt"
"runtime"
)
import "runtime"
const DevVersion = "0.0.0"
@ -15,10 +12,8 @@ var (
Commit = ""
)
// FormattedVersion returns the version, untagged builds carry the commit as build metadata
func FormattedVersion() string {
if Commit != "" {
return fmt.Sprintf("%s (%s)", Version, Commit)
}
return Version
}