From 4d1f0c15959701208b921130c7d25a3371ec9d4a Mon Sep 17 00:00:00 2001 From: Antoine Beauchamp Date: Sun, 16 Aug 2026 14:34:40 -0400 Subject: [PATCH 01/17] Fixed crash: "panic: runtime error: slice bounds out of range [:12] with length 0". --- cmd/bedrock_helper/version.go | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/cmd/bedrock_helper/version.go b/cmd/bedrock_helper/version.go index 7c62533..8fb160c 100644 --- a/cmd/bedrock_helper/version.go +++ b/cmd/bedrock_helper/version.go @@ -204,8 +204,10 @@ func GetPseudoVersionFromMetadata() ProductVersion { // For example, if you run your app using `go run .` or compile it locally without tags, Go sets info.Main.Version to the string "(devel)". p.Version = version - // Truncate revision to 12 characters - p.CommitHash = revision[0:12] + // Truncate revision to 12 characters or less + if revision != "" { + p.CommitHash = revision[0:min(12, len(revision))] + } // Parse datetime { @@ -310,15 +312,23 @@ func GetProductVersionVerboseString() string { // Add detailed version string msg := fmt.Sprintf("%s\n", info.Main.Version) - // Serialize BuildSettings to json + // Serialize info.BuildSettings to json and add to msg jsonData, err := json.MarshalIndent(info.Settings, "", " ") if err != nil { msg += fmt.Sprintf("error: %v\n", err) return msg } - - // Add BuildSettings info to string - msg += fmt.Sprintf("%v\n", string(jsonData)) + msg += fmt.Sprintf("Settings: %v\n", string(jsonData)) + + /* + // Serialize info.Deps to json and add to msg + jsonData, err = json.MarshalIndent(info.Deps, "", " ") + if err != nil { + msg += fmt.Sprintf("error: %v\n", err) + return msg + } + msg += fmt.Sprintf("Deps: %v\n", string(jsonData)) + */ return msg } From 1988b83ace86f93be47fa679a996a449b6114319 Mon Sep 17 00:00:00 2001 From: Antoine Beauchamp Date: Sun, 16 Aug 2026 21:19:36 -0400 Subject: [PATCH 02/17] Creating a go.mod in `cmd\bedrock_helper` directory so that directory becomes a root module directory that depends on the library using a relative path. This should allows building using `go install`. --- cmd/bedrock_helper/go.mod | 12 ++++++++++++ cmd/bedrock_helper/go.sum | 14 ++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 cmd/bedrock_helper/go.mod create mode 100644 cmd/bedrock_helper/go.sum diff --git a/cmd/bedrock_helper/go.mod b/cmd/bedrock_helper/go.mod new file mode 100644 index 0000000..e063827 --- /dev/null +++ b/cmd/bedrock_helper/go.mod @@ -0,0 +1,12 @@ +module github.com/end2endzone/BedrockHelper/cmd/bedrock_helper + +go 1.26 + +require ( + github.com/end2endzone/BedrockHelper v0.0.0 + golang.org/x/mod v0.40.0 +) + +require github.com/tailscale/hujson v0.0.0-20260727124030-b80ff77dac4f // indirect + +replace github.com/end2endzone/BedrockHelper => ../../ diff --git a/cmd/bedrock_helper/go.sum b/cmd/bedrock_helper/go.sum new file mode 100644 index 0000000..859d0e8 --- /dev/null +++ b/cmd/bedrock_helper/go.sum @@ -0,0 +1,14 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tailscale/hujson v0.0.0-20260727124030-b80ff77dac4f h1:9hiVElpCmKzsBKQHkBqZ8LGzt82iLfM8egxr4sew+Ys= +github.com/tailscale/hujson v0.0.0-20260727124030-b80ff77dac4f/go.mod h1:8/zr1Tv0+cKpVtGCEB/7YfRXr2TszsMxMXLaT8YuBgU= +golang.org/x/mod v0.40.0 h1:hUv+3cXcdRHz08UmSiOob7sadHig73uo5bkXxQ/tvUs= +golang.org/x/mod v0.40.0/go.mod h1:0/weTWkPWGBikyTWAX3dkjVztMmBA5hM0DH6BElSupE= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From c63f70cd34edc6e4883597d80e4348305435d228 Mon Sep 17 00:00:00 2001 From: Antoine Beauchamp Date: Mon, 17 Aug 2026 14:16:24 -0400 Subject: [PATCH 03/17] Revert "Creating a go.mod in `cmd\bedrock_helper` directory so that directory becomes a root module directory that depends on the library using a relative path. This should allows building using `go install`." This reverts commit 1988b83ace86f93be47fa679a996a449b6114319. --- cmd/bedrock_helper/go.mod | 12 ------------ cmd/bedrock_helper/go.sum | 14 -------------- 2 files changed, 26 deletions(-) delete mode 100644 cmd/bedrock_helper/go.mod delete mode 100644 cmd/bedrock_helper/go.sum diff --git a/cmd/bedrock_helper/go.mod b/cmd/bedrock_helper/go.mod deleted file mode 100644 index e063827..0000000 --- a/cmd/bedrock_helper/go.mod +++ /dev/null @@ -1,12 +0,0 @@ -module github.com/end2endzone/BedrockHelper/cmd/bedrock_helper - -go 1.26 - -require ( - github.com/end2endzone/BedrockHelper v0.0.0 - golang.org/x/mod v0.40.0 -) - -require github.com/tailscale/hujson v0.0.0-20260727124030-b80ff77dac4f // indirect - -replace github.com/end2endzone/BedrockHelper => ../../ diff --git a/cmd/bedrock_helper/go.sum b/cmd/bedrock_helper/go.sum deleted file mode 100644 index 859d0e8..0000000 --- a/cmd/bedrock_helper/go.sum +++ /dev/null @@ -1,14 +0,0 @@ -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= -github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/tailscale/hujson v0.0.0-20260727124030-b80ff77dac4f h1:9hiVElpCmKzsBKQHkBqZ8LGzt82iLfM8egxr4sew+Ys= -github.com/tailscale/hujson v0.0.0-20260727124030-b80ff77dac4f/go.mod h1:8/zr1Tv0+cKpVtGCEB/7YfRXr2TszsMxMXLaT8YuBgU= -golang.org/x/mod v0.40.0 h1:hUv+3cXcdRHz08UmSiOob7sadHig73uo5bkXxQ/tvUs= -golang.org/x/mod v0.40.0/go.mod h1:0/weTWkPWGBikyTWAX3dkjVztMmBA5hM0DH6BElSupE= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From 7415e9025510a4dd7093ffbb75ef88a390e35663 Mon Sep 17 00:00:00 2001 From: Antoine Beauchamp Date: Mon, 17 Aug 2026 15:44:35 -0400 Subject: [PATCH 04/17] Bump up VERSION to 0.3.1. --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 341cf11..a2268e2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.2.0 \ No newline at end of file +0.3.1 \ No newline at end of file From 861a1a0011c80b3d25b07d07107a66d662c0db80 Mon Sep 17 00:00:00 2001 From: Antoine Beauchamp Date: Mon, 17 Aug 2026 15:49:56 -0400 Subject: [PATCH 05/17] Moved `/cmd/bedrock_helper/version.go` to `/version.go`. --- cmd/bedrock_helper/main.go | 5 +++-- go.mod | 6 ++++-- cmd/bedrock_helper/version.go => version.go | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) rename cmd/bedrock_helper/version.go => version.go (99%) diff --git a/cmd/bedrock_helper/main.go b/cmd/bedrock_helper/main.go index ee1a620..6ff99b8 100644 --- a/cmd/bedrock_helper/main.go +++ b/cmd/bedrock_helper/main.go @@ -8,6 +8,7 @@ import ( "strings" "text/tabwriter" + version "github.com/end2endzone/BedrockHelper" lib "github.com/end2endzone/BedrockHelper/minecraftbedrock" ) @@ -36,10 +37,10 @@ func printHeader() { } func printVersion(verbose bool) { - fmt.Fprintf(os.Stdout, "Version %s.\n", GetProductVersionString()) + fmt.Fprintf(os.Stdout, "Version %s.\n", version.GetProductVersionString()) if verbose { - verboseVersion := GetProductVersionVerboseString() + verboseVersion := version.GetProductVersionVerboseString() fmt.Fprintf(os.Stdout, "%s", verboseVersion) } } diff --git a/go.mod b/go.mod index 265256b..23e4401 100644 --- a/go.mod +++ b/go.mod @@ -5,11 +5,13 @@ go 1.26 // Modules. Use `go get ` to add more. require github.com/stretchr/testify v1.11.1 -require github.com/tailscale/hujson v0.0.0-20260727124030-b80ff77dac4f +require ( + github.com/tailscale/hujson v0.0.0-20260727124030-b80ff77dac4f + golang.org/x/mod v0.40.0 +) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/mod v0.40.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/cmd/bedrock_helper/version.go b/version.go similarity index 99% rename from cmd/bedrock_helper/version.go rename to version.go index 8fb160c..d567ad4 100644 --- a/cmd/bedrock_helper/version.go +++ b/version.go @@ -1,4 +1,4 @@ -package main +package version import ( "encoding/json" From af4af6a3975417a60f303d707f046f54c8e255c0 Mon Sep 17 00:00:00 2001 From: Antoine Beauchamp Date: Mon, 17 Aug 2026 16:10:01 -0400 Subject: [PATCH 06/17] Now building an incomplete ProductVersion based on content of file VERSION if build from source code outside of git. For example, when the source code is downloaded as a zip file. --- version.go | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/version.go b/version.go index d567ad4..1eb9b22 100644 --- a/version.go +++ b/version.go @@ -7,9 +7,14 @@ import ( "strings" "time" + _ "embed" + "golang.org/x/mod/semver" ) +//go:embed VERSION +var fileVersion string + const ( InvalidVersion = "0.0.0" InvalidCommitHash = "0000000" @@ -291,14 +296,26 @@ func GetProductVersion() ProductVersion { return metadata } - // Return an invalid version. - return CreateInvalidProductVersion() + // Build a ProductVersion without automatic versionning from git tags. + // Use VERSION file instead. This product version is still invalid because it has no CommitHash and no BuildDate. + // It will require a different formatting + p := CreateInvalidProductVersion() + p.Version = fileVersion + + return p } func GetProductVersionString() string { p := GetProductVersion() - msg := fmt.Sprintf("%s (%s) compiled on %s", p.Version, p.CommitHash, p.BuildDate) + var msg string + if p.IsValid() { + msg = fmt.Sprintf("%s (%s) last modified on %s", p.Version, p.CommitHash, p.BuildDate) + } else { + // Invalid version. Assume only p.Version is valid. + msg = fmt.Sprintf("%s", p.Version) + } + return msg } From 9ac361ddcd8fa7c49a40a458d6725a3274dfbb2f Mon Sep 17 00:00:00 2001 From: Antoine Beauchamp Date: Mon, 17 Aug 2026 16:17:22 -0400 Subject: [PATCH 07/17] Created a test to make sure `GetProductVersionString()` and `VERSION` file are always in sync. --- version_test.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 version_test.go diff --git a/version_test.go b/version_test.go new file mode 100644 index 0000000..4a5fdf6 --- /dev/null +++ b/version_test.go @@ -0,0 +1,19 @@ +package version + +import ( + "testing" + + _ "embed" + + "github.com/stretchr/testify/require" +) + +//go:embed VERSION +var versionFileContent string + +func TestGetProductVersionStringContainsVERSIONFile(t *testing.T) { + productVersion := GetProductVersionString() + + // Assert the string returned from GetProductVersionString() contains the actual VERSION string. + require.Contains(t, productVersion, versionFileContent, "GetProductVersionString() does not contains the VERSION. The VERSION file might be outdated.") +} From 48500b1c89838b17c1dc62c2ca78b0b6b83128e5 Mon Sep 17 00:00:00 2001 From: Antoine Beauchamp Date: Mon, 17 Aug 2026 16:31:04 -0400 Subject: [PATCH 08/17] Bump up VERSION to 0.3.1-beta. --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index a2268e2..c404f6f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.3.1 \ No newline at end of file +0.3.1-beta \ No newline at end of file From e11f5d8523c901799c3362536c0fa763d3e9a4d4 Mon Sep 17 00:00:00 2001 From: Antoine Beauchamp Date: Mon, 17 Aug 2026 16:33:55 -0400 Subject: [PATCH 09/17] Created an internal build package to check if debug metadata is injected in build when using `go install` command. --- cmd/bedrock_helper/main.go | 4 ++++ internal/build/build.go | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 internal/build/build.go diff --git a/cmd/bedrock_helper/main.go b/cmd/bedrock_helper/main.go index 6ff99b8..5e08560 100644 --- a/cmd/bedrock_helper/main.go +++ b/cmd/bedrock_helper/main.go @@ -9,6 +9,7 @@ import ( "text/tabwriter" version "github.com/end2endzone/BedrockHelper" + "github.com/end2endzone/BedrockHelper/internal/build" lib "github.com/end2endzone/BedrockHelper/minecraftbedrock" ) @@ -42,6 +43,9 @@ func printVersion(verbose bool) { if verbose { verboseVersion := version.GetProductVersionVerboseString() fmt.Fprintf(os.Stdout, "%s", verboseVersion) + + fmt.Fprintf(os.Stdout, "Build metadata:\n") + build.PrintBuildInfoMetadata() } } diff --git a/internal/build/build.go b/internal/build/build.go new file mode 100644 index 0000000..5410d30 --- /dev/null +++ b/internal/build/build.go @@ -0,0 +1,37 @@ +package build + +import ( + "encoding/json" + "fmt" + "os" + "runtime/debug" +) + +func PrintBuildInfoMetadata() { + info, ok := debug.ReadBuildInfo() + if !ok { + fmt.Fprintf(os.Stderr, "build-info-metadata not available\n") + return + } + + // Add detailed version string + fmt.Fprintf(os.Stdout, "info.Main.Version=%s\n", info.Main.Version) + fmt.Fprintf(os.Stdout, "info.Path=%s\n", info.Path) + fmt.Fprintf(os.Stdout, "info.Main.Path=%s\n", info.Main.Path) + + // Serialize info.BuildSettings to json and add to msg + jsonData, err := json.MarshalIndent(info.Settings, "", " ") + if err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + return + } + fmt.Fprintf(os.Stdout, "info.Settings=%s\n", string(jsonData)) + + // Serialize info.Deps to json and add to msg + jsonData, err = json.MarshalIndent(info.Deps, "", " ") + if err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + return + } + fmt.Fprintf(os.Stdout, "info.Deps=%s\n", string(jsonData)) +} From 525428f241753105386fb67ea7e42baa570d6d2a Mon Sep 17 00:00:00 2001 From: Antoine Beauchamp Date: Mon, 17 Aug 2026 16:53:03 -0400 Subject: [PATCH 10/17] Bump version to 0.3.1-rc1 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index c404f6f..8403f23 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.3.1-beta \ No newline at end of file +0.3.1-rc1 \ No newline at end of file From c3f1c5fcf4db59091a6b87d6ac078849040f014d Mon Sep 17 00:00:00 2001 From: Antoine Beauchamp Date: Mon, 17 Aug 2026 16:55:21 -0400 Subject: [PATCH 11/17] Implemented `GetBuildTagFromMetadata()`. --- internal/build/build.go | 37 ++++++++++++++----------------------- version.go | 18 +++++++++++++++--- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/internal/build/build.go b/internal/build/build.go index 5410d30..90753dd 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -1,37 +1,28 @@ package build import ( - "encoding/json" "fmt" - "os" "runtime/debug" ) -func PrintBuildInfoMetadata() { +func GetBuildTagFromMetadata() (string, error) { info, ok := debug.ReadBuildInfo() if !ok { - fmt.Fprintf(os.Stderr, "build-info-metadata not available\n") - return + err := fmt.Errorf("build-info metadata not available") + return "", err } - // Add detailed version string - fmt.Fprintf(os.Stdout, "info.Main.Version=%s\n", info.Main.Version) - fmt.Fprintf(os.Stdout, "info.Path=%s\n", info.Path) - fmt.Fprintf(os.Stdout, "info.Main.Path=%s\n", info.Main.Path) + // When compiling using `go install URL@tag` the `info.Main.Version` variable contains the name of the tag used. + // For example, when running `go install github.com/username/reponame/cmd/my-app@v0.2.0-alpha` Go's toolchain/compiler + // will set info.Main.Version to `v0.2.0-alpha`. - // Serialize info.BuildSettings to json and add to msg - jsonData, err := json.MarshalIndent(info.Settings, "", " ") - if err != nil { - fmt.Fprintf(os.Stderr, "%v\n", err) - return - } - fmt.Fprintf(os.Stdout, "info.Settings=%s\n", string(jsonData)) + // When using `latest` for tag, Go's install command will find the latest tag that is not `alpha`, `beta`, etc. + // For example, when the following tag exists: + // - v0.2.0 + // - v0.3.0 + // - v0.3.1-alpha + // - v0.3.1-beta + // Go's toolchain/compiler will resolve the latest version as v0.3.0 and will set info.Main.Version to `v0.3.0`. - // Serialize info.Deps to json and add to msg - jsonData, err = json.MarshalIndent(info.Deps, "", " ") - if err != nil { - fmt.Fprintf(os.Stderr, "%v\n", err) - return - } - fmt.Fprintf(os.Stdout, "info.Deps=%s\n", string(jsonData)) + return info.Main.Version, nil } diff --git a/version.go b/version.go index 1eb9b22..5b86bd0 100644 --- a/version.go +++ b/version.go @@ -9,6 +9,8 @@ import ( _ "embed" + "github.com/end2endzone/BedrockHelper/internal/build" + "golang.org/x/mod/semver" ) @@ -296,12 +298,22 @@ func GetProductVersion() ProductVersion { return metadata } - // Build a ProductVersion without automatic versionning from git tags. - // Use VERSION file instead. This product version is still invalid because it has no CommitHash and no BuildDate. + // Try to build a ProductVersion from the internal build package. + tagName, err := build.GetBuildTagFromMetadata() + if err == nil { + // This product version is still invalid because it has no CommitHash and no BuildDate. + // It will require a different formatting + p := CreateInvalidProductVersion() + p.Version = tagName + return p + } + + // Build a ProductVersion without automatic versioning from git tags. + // Use VERSION file instead. + // This product version is still invalid because it has no CommitHash and no BuildDate. // It will require a different formatting p := CreateInvalidProductVersion() p.Version = fileVersion - return p } From 4ec73140bdd0cdb9883e882d46a3558e354b2a1a Mon Sep 17 00:00:00 2001 From: Antoine Beauchamp Date: Mon, 17 Aug 2026 18:10:54 -0400 Subject: [PATCH 12/17] Moved functions `getVersionControlValuesFromMetadata()` and `GetProductVersionVerboseString()` to build package. Functions were also properly renamed. --- cmd/bedrock_helper/main.go | 7 +-- internal/build/build.go | 88 +++++++++++++++++++++++++++++++------- version.go | 72 +++---------------------------- 3 files changed, 81 insertions(+), 86 deletions(-) diff --git a/cmd/bedrock_helper/main.go b/cmd/bedrock_helper/main.go index 5e08560..e3ac722 100644 --- a/cmd/bedrock_helper/main.go +++ b/cmd/bedrock_helper/main.go @@ -41,11 +41,8 @@ func printVersion(verbose bool) { fmt.Fprintf(os.Stdout, "Version %s.\n", version.GetProductVersionString()) if verbose { - verboseVersion := version.GetProductVersionVerboseString() - fmt.Fprintf(os.Stdout, "%s", verboseVersion) - - fmt.Fprintf(os.Stdout, "Build metadata:\n") - build.PrintBuildInfoMetadata() + metadata := build.GetBuildMetadata() + fmt.Fprintf(os.Stdout, "Build metadata:%s\n", metadata) } } diff --git a/internal/build/build.go b/internal/build/build.go index 90753dd..b1a7fe1 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -1,28 +1,86 @@ package build import ( - "fmt" "runtime/debug" ) -func GetBuildTagFromMetadata() (string, error) { +// GetVersionFromMetadata get the version value from the metadata injected at build time. +// For example: +// - v0.1.1-0.20260815155314-4ad116a8bdf3 +// - v0.2.0-alpha +// +// When compiled from soure code in git version control, the version will be formattated such as `v0.1.1-0.20260815155314-4ad116a8bdf3`. +// +// When compiled using `go install URL@tag`, the version variable contains the name of the tag used. +// For example, when compiled with command +// `go install github.com/username/reponame/cmd/my-app@v0.2.0-alpha`, the returned version will be `v0.2.0-alpha`. +// +// When using `latest` for tag, the version metadata contains the latest tag that is not `alpha`, `beta`, etc. +// For example, when the following tag exists: +// - v0.2.0 +// - v0.3.0 +// - v0.3.1-alpha +// - v0.3.1-beta +// Go's toolchain/compiler will resolve the latest version as v0.3.0 and will set version metadata to `v0.3.0`. +// +// Warning: version can default to `(devel)` if compilation of source code is make outside of a version control system. +// +// Returns empty values on error or when metadata is not available. +func GetVersionFromMetadata() string { info, ok := debug.ReadBuildInfo() if !ok { - err := fmt.Errorf("build-info metadata not available") - return "", err + // build-info metadata not available + return "" } - // When compiling using `go install URL@tag` the `info.Main.Version` variable contains the name of the tag used. - // For example, when running `go install github.com/username/reponame/cmd/my-app@v0.2.0-alpha` Go's toolchain/compiler - // will set info.Main.Version to `v0.2.0-alpha`. + return info.Main.Version +} + +// GetGitHashAndDateFromMetadata get the values from git's version control system from the metadata injected at build time. +// For example: +// - revision: `6cb0ce064a20aeb026d039c12e7ab83b10ad1c63` +// - datetime: `2026-08-16T15:12:22Z` +// +// Returns empty values on error or when metadata is not available. +func GetGitHashAndDateFromMetadata() (revision, datetime string) { + info, ok := debug.ReadBuildInfo() + if !ok { + // Metadata not available + return + } + + // Is compiled from source code in Git ? + isGitVersionControl := false + var tmp_revision string + var tmp_datetime string + for _, setting := range info.Settings { + switch setting.Key { + case "vcs": + isGitVersionControl = (setting.Value == "git") + case "vcs.revision": + tmp_revision = setting.Value + case "vcs.time": + tmp_datetime = setting.Value + } + } - // When using `latest` for tag, Go's install command will find the latest tag that is not `alpha`, `beta`, etc. - // For example, when the following tag exists: - // - v0.2.0 - // - v0.3.0 - // - v0.3.1-alpha - // - v0.3.1-beta - // Go's toolchain/compiler will resolve the latest version as v0.3.0 and will set info.Main.Version to `v0.3.0`. + if isGitVersionControl { + revision = tmp_revision + datetime = tmp_datetime + } + + return +} + +// GetBuildMetadata get the full metadata json data as a string. +// Returns empty values on error or when metadata is not available. +func GetBuildMetadata() string { + info, ok := debug.ReadBuildInfo() + if !ok { + // Metadata not available + return "" + } - return info.Main.Version, nil + metadata := info.String() + return metadata } diff --git a/version.go b/version.go index 5b86bd0..3dcb391 100644 --- a/version.go +++ b/version.go @@ -1,9 +1,7 @@ package version import ( - "encoding/json" "fmt" - "runtime/debug" "strings" "time" @@ -156,34 +154,6 @@ func findGitHashInSemVer(input string) string { } */ -// getVersionControlRevisionFromMetadata get the values from version control system from the metadata injected at build time. -// For example: -// - version : `v0.1.1-0.20260815155314-4ad116a8bdf3` -// - revision: `6cb0ce064a20aeb026d039c12e7ab83b10ad1c63` -// - datetime: `2026-08-16T15:12:22Z` -// -// Returns empty value on error or when metadata is not available. -func getVersionControlValuesFromMetadata() (version, revision, datetime string) { - info, ok := debug.ReadBuildInfo() - if !ok { - // Metadata not available - return - } - - version = info.Main.Version - - for _, setting := range info.Settings { - switch setting.Key { - case "vcs.revision": - revision = setting.Value - case "vcs.time": - datetime = setting.Value - } - } - - return -} - func CreateInvalidProductVersion() ProductVersion { p := ProductVersion{ Version: InvalidVersion, @@ -199,9 +169,10 @@ func CreateInvalidProductVersion() ProductVersion { func GetPseudoVersionFromMetadata() ProductVersion { p := CreateInvalidProductVersion() - version, revision, datetime := getVersionControlValuesFromMetadata() - if version == "" { - // Metadata not available + version := build.GetVersionFromMetadata() + revision, datetime := build.GetGitHashAndDateFromMetadata() + if version == "" || revision == "" || datetime == "" { + // Metadata not available or not compiled from git version control. // Return an invalid ProductVersion return p } @@ -299,8 +270,8 @@ func GetProductVersion() ProductVersion { } // Try to build a ProductVersion from the internal build package. - tagName, err := build.GetBuildTagFromMetadata() - if err == nil { + tagName := build.GetVersionFromMetadata() + if tagName != "" { // This product version is still invalid because it has no CommitHash and no BuildDate. // It will require a different formatting p := CreateInvalidProductVersion() @@ -330,34 +301,3 @@ func GetProductVersionString() string { return msg } - -func GetProductVersionVerboseString() string { - info, ok := debug.ReadBuildInfo() - if !ok { - // Can't do better - return "" - } - - // Add detailed version string - msg := fmt.Sprintf("%s\n", info.Main.Version) - - // Serialize info.BuildSettings to json and add to msg - jsonData, err := json.MarshalIndent(info.Settings, "", " ") - if err != nil { - msg += fmt.Sprintf("error: %v\n", err) - return msg - } - msg += fmt.Sprintf("Settings: %v\n", string(jsonData)) - - /* - // Serialize info.Deps to json and add to msg - jsonData, err = json.MarshalIndent(info.Deps, "", " ") - if err != nil { - msg += fmt.Sprintf("error: %v\n", err) - return msg - } - msg += fmt.Sprintf("Deps: %v\n", string(jsonData)) - */ - - return msg -} From ea77e8020470bf1172c2f6fcd7473c68b5ee5a26 Mon Sep 17 00:00:00 2001 From: Antoine Beauchamp Date: Mon, 17 Aug 2026 18:17:23 -0400 Subject: [PATCH 13/17] Renamed some function and updated documentation. --- version.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/version.go b/version.go index 3dcb391..d85a4f7 100644 --- a/version.go +++ b/version.go @@ -163,10 +163,10 @@ func CreateInvalidProductVersion() ProductVersion { return p } -// GetPseudoVersionFromMetadata parses the go pseudo-version into a ProductVersion. +// GetProductVersionFromMetadata parses the go pseudo-version into a ProductVersion. // A pseudo-version is a string in format "v[version]-[datetime]-[revision][dirtybit]". // For example: "v1.2.3-20260815131415-de3798c09c08+dirty". -func GetPseudoVersionFromMetadata() ProductVersion { +func GetProductVersionFromMetadata() ProductVersion { p := CreateInvalidProductVersion() version := build.GetVersionFromMetadata() @@ -264,12 +264,12 @@ func GetProductVersion() ProductVersion { } // Get a valid the product version from metadata - metadata := GetPseudoVersionFromMetadata() + metadata := GetProductVersionFromMetadata() if metadata.IsValid() { return metadata } - // Try to build a ProductVersion from the internal build package. + // Try to build a ProductVersion from the version metadata. tagName := build.GetVersionFromMetadata() if tagName != "" { // This product version is still invalid because it has no CommitHash and no BuildDate. @@ -279,8 +279,7 @@ func GetProductVersion() ProductVersion { return p } - // Build a ProductVersion without automatic versioning from git tags. - // Use VERSION file instead. + // Build a ProductVersion from the VERSION file instead. // This product version is still invalid because it has no CommitHash and no BuildDate. // It will require a different formatting p := CreateInvalidProductVersion() @@ -295,7 +294,7 @@ func GetProductVersionString() string { if p.IsValid() { msg = fmt.Sprintf("%s (%s) last modified on %s", p.Version, p.CommitHash, p.BuildDate) } else { - // Invalid version. Assume only p.Version is valid. + // Invalid product version. Assume only p.Version is valid. msg = fmt.Sprintf("%s", p.Version) } From 820b508a0f53d6034dbcd83ff83e1a921353d659 Mon Sep 17 00:00:00 2001 From: Antoine Beauchamp Date: Mon, 17 Aug 2026 20:43:24 -0400 Subject: [PATCH 14/17] - Moved `/version.go` and `/version_test.go` back to `cmd/bedrock_helper` directory. - Created root package to embed the VERSION file content. - Modified `GetProductVersion()` to fall back to the content of file `/VERSION` if all other version identification method fails. --- cmd/bedrock_helper/main.go | 3 +-- version.go => cmd/bedrock_helper/version.go | 10 +++------- .../bedrock_helper/version_test.go | 8 +++----- root.go | 12 ++++++++++++ 4 files changed, 19 insertions(+), 14 deletions(-) rename version.go => cmd/bedrock_helper/version.go (98%) rename version_test.go => cmd/bedrock_helper/version_test.go (79%) create mode 100644 root.go diff --git a/cmd/bedrock_helper/main.go b/cmd/bedrock_helper/main.go index e3ac722..d38822f 100644 --- a/cmd/bedrock_helper/main.go +++ b/cmd/bedrock_helper/main.go @@ -8,7 +8,6 @@ import ( "strings" "text/tabwriter" - version "github.com/end2endzone/BedrockHelper" "github.com/end2endzone/BedrockHelper/internal/build" lib "github.com/end2endzone/BedrockHelper/minecraftbedrock" ) @@ -38,7 +37,7 @@ func printHeader() { } func printVersion(verbose bool) { - fmt.Fprintf(os.Stdout, "Version %s.\n", version.GetProductVersionString()) + fmt.Fprintf(os.Stdout, "Version %s.\n", GetProductVersionString()) if verbose { metadata := build.GetBuildMetadata() diff --git a/version.go b/cmd/bedrock_helper/version.go similarity index 98% rename from version.go rename to cmd/bedrock_helper/version.go index d85a4f7..f9db0e3 100644 --- a/version.go +++ b/cmd/bedrock_helper/version.go @@ -1,20 +1,16 @@ -package version +package main import ( "fmt" "strings" "time" - _ "embed" - + root "github.com/end2endzone/BedrockHelper" "github.com/end2endzone/BedrockHelper/internal/build" "golang.org/x/mod/semver" ) -//go:embed VERSION -var fileVersion string - const ( InvalidVersion = "0.0.0" InvalidCommitHash = "0000000" @@ -283,7 +279,7 @@ func GetProductVersion() ProductVersion { // This product version is still invalid because it has no CommitHash and no BuildDate. // It will require a different formatting p := CreateInvalidProductVersion() - p.Version = fileVersion + p.Version = root.GetVersionFromVersionFile() return p } diff --git a/version_test.go b/cmd/bedrock_helper/version_test.go similarity index 79% rename from version_test.go rename to cmd/bedrock_helper/version_test.go index 4a5fdf6..4cef452 100644 --- a/version_test.go +++ b/cmd/bedrock_helper/version_test.go @@ -1,18 +1,16 @@ -package version +package main import ( "testing" - _ "embed" + root "github.com/end2endzone/BedrockHelper" "github.com/stretchr/testify/require" ) -//go:embed VERSION -var versionFileContent string - func TestGetProductVersionStringContainsVERSIONFile(t *testing.T) { productVersion := GetProductVersionString() + versionFileContent := root.GetVersionFromVersionFile() // Assert the string returned from GetProductVersionString() contains the actual VERSION string. require.Contains(t, productVersion, versionFileContent, "GetProductVersionString() does not contains the VERSION. The VERSION file might be outdated.") diff --git a/root.go b/root.go new file mode 100644 index 0000000..f9eef59 --- /dev/null +++ b/root.go @@ -0,0 +1,12 @@ +package root + +import ( + _ "embed" +) + +//go:embed VERSION +var FileVersion string + +func GetVersionFromVersionFile() string { + return FileVersion +} From bf92524e4f37d17c52fc54df6d1a8c2389ef234f Mon Sep 17 00:00:00 2001 From: Antoine Beauchamp Date: Tue, 18 Aug 2026 09:12:37 -0400 Subject: [PATCH 15/17] - Reordered the order of steps in GetProductVersionFromMetadata(). - Strip the leading "v" to only get the digits and pre-release labels when getting the fall back version from the tag name. --- cmd/bedrock_helper/version.go | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/cmd/bedrock_helper/version.go b/cmd/bedrock_helper/version.go index f9db0e3..88d9eda 100644 --- a/cmd/bedrock_helper/version.go +++ b/cmd/bedrock_helper/version.go @@ -178,8 +178,15 @@ func GetProductVersionFromMetadata() ProductVersion { // For example, if you run your app using `go run .` or compile it locally without tags, Go sets info.Main.Version to the string "(devel)". p.Version = version - // Truncate revision to 12 characters or less + // Remove `+dirty` from version and standardizes it + p.Version = semver.Canonical(p.Version) + + // Strip the leading "v" to only get the digits and pre-release labels + p.Version = strings.TrimPrefix(p.Version, "v") + + // Parse revision if revision != "" { + // Truncate revision to 12 characters or less p.CommitHash = revision[0:min(12, len(revision))] } @@ -197,12 +204,6 @@ func GetProductVersionFromMetadata() ProductVersion { } } - // Remove `+dirty` from version and standardizes it - p.Version = semver.Canonical(p.Version) - - // Strip the leading "v" if you strictly want the digits and pre-release labels - p.Version = strings.TrimPrefix(p.Version, "v") - // Remove datetime from version string { // datetime == "2026-08-16T15:12:22Z" @@ -268,6 +269,9 @@ func GetProductVersion() ProductVersion { // Try to build a ProductVersion from the version metadata. tagName := build.GetVersionFromMetadata() if tagName != "" { + // Strip the leading "v" to only get the digits and pre-release labels + tagName = strings.TrimPrefix(tagName, "v") + // This product version is still invalid because it has no CommitHash and no BuildDate. // It will require a different formatting p := CreateInvalidProductVersion() @@ -288,7 +292,8 @@ func GetProductVersionString() string { var msg string if p.IsValid() { - msg = fmt.Sprintf("%s (%s) last modified on %s", p.Version, p.CommitHash, p.BuildDate) + // Version 0.3.1-rc1 (820b508a0f53, released 2026-08-18) + msg = fmt.Sprintf("%s (%s, released %s)", p.Version, p.CommitHash, p.BuildDate) } else { // Invalid product version. Assume only p.Version is valid. msg = fmt.Sprintf("%s", p.Version) From e9c326e863fc74ea4e63a03d8de9c518b9edb7d9 Mon Sep 17 00:00:00 2001 From: Antoine Beauchamp Date: Tue, 18 Aug 2026 09:38:53 -0400 Subject: [PATCH 16/17] - Implemented fallback to build version string when tagName == "(devel)". - Fixed failing test TestGetProductVersionStringContainsVERSIONFile() --- cmd/bedrock_helper/version.go | 2 +- cmd/bedrock_helper/version_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/bedrock_helper/version.go b/cmd/bedrock_helper/version.go index 88d9eda..ee56a46 100644 --- a/cmd/bedrock_helper/version.go +++ b/cmd/bedrock_helper/version.go @@ -268,7 +268,7 @@ func GetProductVersion() ProductVersion { // Try to build a ProductVersion from the version metadata. tagName := build.GetVersionFromMetadata() - if tagName != "" { + if tagName != "" && tagName != "(devel)" { // Strip the leading "v" to only get the digits and pre-release labels tagName = strings.TrimPrefix(tagName, "v") diff --git a/cmd/bedrock_helper/version_test.go b/cmd/bedrock_helper/version_test.go index 4cef452..ba0c206 100644 --- a/cmd/bedrock_helper/version_test.go +++ b/cmd/bedrock_helper/version_test.go @@ -13,5 +13,5 @@ func TestGetProductVersionStringContainsVERSIONFile(t *testing.T) { versionFileContent := root.GetVersionFromVersionFile() // Assert the string returned from GetProductVersionString() contains the actual VERSION string. - require.Contains(t, productVersion, versionFileContent, "GetProductVersionString() does not contains the VERSION. The VERSION file might be outdated.") + require.Contains(t, productVersion, versionFileContent, "GetProductVersionString() which is '%s' does not contains the VERSION which is '%s'. The VERSION file might be outdated.", productVersion, versionFileContent) } From 1c6f730b599654fa3fb671eef1e3e4c02cee108f Mon Sep 17 00:00:00 2001 From: Antoine Beauchamp Date: Tue, 18 Aug 2026 09:39:17 -0400 Subject: [PATCH 17/17] Bump up version to 0.3.1-rc2. --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 8403f23..5a3f665 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.3.1-rc1 \ No newline at end of file +0.3.1-rc2 \ No newline at end of file