Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
4d1f0c1
Fixed crash: "panic: runtime error: slice bounds out of range [:12] w…
end2endzone Aug 16, 2026
1988b83
Creating a go.mod in `cmd\bedrock_helper` directory so that directory…
end2endzone Aug 17, 2026
c63f70c
Revert "Creating a go.mod in `cmd\bedrock_helper` directory so that d…
end2endzone Aug 17, 2026
7415e90
Bump up VERSION to 0.3.1.
end2endzone Aug 17, 2026
861a1a0
Moved `/cmd/bedrock_helper/version.go` to `/version.go`.
end2endzone Aug 17, 2026
af4af6a
Now building an incomplete ProductVersion based on content of file VE…
end2endzone Aug 17, 2026
9ac361d
Created a test to make sure `GetProductVersionString()` and `VERSION`…
end2endzone Aug 17, 2026
48500b1
Bump up VERSION to 0.3.1-beta.
end2endzone Aug 17, 2026
e11f5d8
Created an internal build package to check if debug metadata is inje…
end2endzone Aug 17, 2026
525428f
Bump version to 0.3.1-rc1
end2endzone Aug 17, 2026
c3f1c5f
Implemented `GetBuildTagFromMetadata()`.
end2endzone Aug 17, 2026
4ec7314
Moved functions `getVersionControlValuesFromMetadata()` and `GetProdu…
end2endzone Aug 17, 2026
ea77e80
Renamed some function and updated documentation.
end2endzone Aug 17, 2026
820b508
- Moved `/version.go` and `/version_test.go` back to `cmd/bedrock_hel…
end2endzone Aug 18, 2026
bf92524
- Reordered the order of steps in GetProductVersionFromMetadata().
end2endzone Aug 18, 2026
e9c326e
- Implemented fallback to build version string when tagName == "(deve…
end2endzone Aug 18, 2026
1c6f730
Bump up version to 0.3.1-rc2.
end2endzone Aug 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.2.0
0.3.1-rc2
5 changes: 3 additions & 2 deletions cmd/bedrock_helper/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"strings"
"text/tabwriter"

"github.com/end2endzone/BedrockHelper/internal/build"
lib "github.com/end2endzone/BedrockHelper/minecraftbedrock"
)

Expand Down Expand Up @@ -39,8 +40,8 @@ func printVersion(verbose bool) {
fmt.Fprintf(os.Stdout, "Version %s.\n", GetProductVersionString())

if verbose {
verboseVersion := GetProductVersionVerboseString()
fmt.Fprintf(os.Stdout, "%s", verboseVersion)
metadata := build.GetBuildMetadata()
fmt.Fprintf(os.Stdout, "Build metadata:%s\n", metadata)
}
}

Expand Down
115 changes: 47 additions & 68 deletions cmd/bedrock_helper/version.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package main

import (
"encoding/json"
"fmt"
"runtime/debug"
"strings"
"time"

root "github.com/end2endzone/BedrockHelper"
"github.com/end2endzone/BedrockHelper/internal/build"

"golang.org/x/mod/semver"
)

Expand Down Expand Up @@ -149,34 +150,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,
Expand All @@ -186,15 +159,16 @@ 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, 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
}
Expand All @@ -204,8 +178,17 @@ 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]
// 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))]
}

// Parse datetime
{
Expand All @@ -221,12 +204,6 @@ func GetPseudoVersionFromMetadata() 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"
Expand Down Expand Up @@ -284,41 +261,43 @@ func GetProductVersion() ProductVersion {
}

// Get a valid the product version from metadata
metadata := GetPseudoVersionFromMetadata()
metadata := GetProductVersionFromMetadata()
if metadata.IsValid() {
return metadata
}

// Return an invalid version.
return CreateInvalidProductVersion()
}
// Try to build a ProductVersion from the version metadata.
tagName := build.GetVersionFromMetadata()
if tagName != "" && tagName != "(devel)" {
// Strip the leading "v" to only get the digits and pre-release labels
tagName = strings.TrimPrefix(tagName, "v")

func GetProductVersionString() string {
p := GetProductVersion()
// 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
}

msg := fmt.Sprintf("%s (%s) compiled on %s", p.Version, p.CommitHash, p.BuildDate)
return msg
// 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()
p.Version = root.GetVersionFromVersionFile()
return p
}

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)
func GetProductVersionString() string {
p := GetProductVersion()

// Serialize BuildSettings to json
jsonData, err := json.MarshalIndent(info.Settings, "", " ")
if err != nil {
msg += fmt.Sprintf("error: %v\n", err)
return msg
var msg string
if p.IsValid() {
// 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)
}

// Add BuildSettings info to string
msg += fmt.Sprintf("%v\n", string(jsonData))

return msg
}
17 changes: 17 additions & 0 deletions cmd/bedrock_helper/version_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package main

import (
"testing"

root "github.com/end2endzone/BedrockHelper"

"github.com/stretchr/testify/require"
)

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() which is '%s' does not contains the VERSION which is '%s'. The VERSION file might be outdated.", productVersion, versionFileContent)
}
6 changes: 4 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ go 1.26
// Modules. Use `go get <URL>` 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
)
86 changes: 86 additions & 0 deletions internal/build/build.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package build

import (
"runtime/debug"
)

// 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 {
// build-info metadata not available
return ""
}

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
}
}

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 ""
}

metadata := info.String()
return metadata
}
12 changes: 12 additions & 0 deletions root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package root

import (
_ "embed"
)

//go:embed VERSION
var FileVersion string

func GetVersionFromVersionFile() string {
return FileVersion
}