mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 08:36:13 +00:00
feat(service): expose build version on GET / mirroring /health
Extract a buildVersionInfo helper from HandleHealth so both endpoints emit identical version + VCS metadata. JSON callers hitting / now get the same release context they get from /health; under go run/test where debug.ReadBuildInfo lacks VCS settings, version falls back to "0.0.1" and the vcs_* keys are omitted (instead of empty strings). The HTML branch of / is unchanged — the embedded index.html keeps its own version-display story. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
776e0cfe44
commit
e3cd5a3459
@@ -7,45 +7,53 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// HandleHealth returns the health status of the service.
|
||||
func (s *Server) HandleHealth(w http.ResponseWriter, _ *http.Request) {
|
||||
version := "0.0.1"
|
||||
vcsRevision := ""
|
||||
vcsTime := ""
|
||||
vcsModified := ""
|
||||
// buildVersionInfo extracts module version + VCS metadata from the
|
||||
// runtime/debug build info, falling back to "0.0.1" when the binary
|
||||
// wasn't built with module info (e.g. local `go run`). Shared between
|
||||
// HandleHealth and HandleRoot so both endpoints report identical
|
||||
// release context; keys present-when-non-empty so a `go run` response
|
||||
// stays minimal instead of carrying empty strings.
|
||||
func buildVersionInfo() map[string]string {
|
||||
info := map[string]string{"version": "0.0.1"}
|
||||
|
||||
if info, ok := debug.ReadBuildInfo(); ok {
|
||||
if info.Main.Version != "" && info.Main.Version != "(devel)" {
|
||||
version = info.Main.Version
|
||||
}
|
||||
build, ok := debug.ReadBuildInfo()
|
||||
if !ok {
|
||||
return info
|
||||
}
|
||||
|
||||
for _, setting := range info.Settings {
|
||||
switch setting.Key {
|
||||
case "vcs.revision":
|
||||
vcsRevision = setting.Value
|
||||
case "vcs.time":
|
||||
vcsTime = setting.Value
|
||||
case "vcs.modified":
|
||||
vcsModified = setting.Value
|
||||
if build.Main.Version != "" && build.Main.Version != "(devel)" {
|
||||
info["version"] = build.Main.Version
|
||||
}
|
||||
|
||||
for _, setting := range build.Settings {
|
||||
switch setting.Key {
|
||||
case "vcs.revision":
|
||||
if setting.Value != "" {
|
||||
info["vcs_revision"] = setting.Value
|
||||
}
|
||||
case "vcs.time":
|
||||
if setting.Value != "" {
|
||||
info["vcs_time"] = setting.Value
|
||||
}
|
||||
case "vcs.modified":
|
||||
if setting.Value != "" {
|
||||
info["vcs_modified"] = setting.Value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
// HandleHealth returns the health status of the service.
|
||||
func (s *Server) HandleHealth(w http.ResponseWriter, _ *http.Request) {
|
||||
status := map[string]interface{}{
|
||||
"status": "up",
|
||||
"timestamp": time.Now().Format(time.RFC3339),
|
||||
"version": version,
|
||||
}
|
||||
if vcsRevision != "" {
|
||||
status["vcs_revision"] = vcsRevision
|
||||
}
|
||||
|
||||
if vcsTime != "" {
|
||||
status["vcs_time"] = vcsTime
|
||||
}
|
||||
|
||||
if vcsModified != "" {
|
||||
status["vcs_modified"] = vcsModified
|
||||
for k, v := range buildVersionInfo() {
|
||||
status[k] = v
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
@@ -2,7 +2,7 @@ package handlers
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
"encoding/json"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -36,8 +36,25 @@ var swUpdateXML []byte
|
||||
func (s *Server) HandleRoot(w http.ResponseWriter, r *http.Request) {
|
||||
accept := r.Header.Get("Accept")
|
||||
if !strings.Contains(accept, "text/html") && (strings.Contains(accept, "application/json") || accept == "*/*" || accept == "") {
|
||||
// Mirror the version + VCS metadata exposed by /health so any
|
||||
// caller hitting "/" gets identical release context. Keys that
|
||||
// would carry empty strings are omitted by buildVersionInfo.
|
||||
payload := map[string]string{
|
||||
"Bose": "AfterTouch",
|
||||
"service": "Go/Chi",
|
||||
"docs": "https://gesellix.github.io/Bose-SoundTouch/",
|
||||
}
|
||||
|
||||
for k, v := range buildVersionInfo() {
|
||||
payload[k] = v
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = fmt.Fprintf(w, `{"Bose": "AfterTouch", "service": "Go/Chi", "docs": "https://gesellix.github.io/Bose-SoundTouch/"}`)
|
||||
|
||||
if err := json.NewEncoder(w).Encode(payload); err != nil {
|
||||
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -66,10 +67,26 @@ func TestRootEndpointJSON(t *testing.T) {
|
||||
t.Errorf("Expected application/json content type, got %s", contentType)
|
||||
}
|
||||
|
||||
body, _ := io.ReadAll(res.Body)
|
||||
expected := `{"Bose": "AfterTouch", "service": "Go/Chi", "docs": "https://gesellix.github.io/Bose-SoundTouch/"}`
|
||||
if strings.TrimSpace(string(body)) != expected {
|
||||
t.Errorf("Expected body %s, got %s", expected, string(body))
|
||||
var got map[string]string
|
||||
if err := json.NewDecoder(res.Body).Decode(&got); err != nil {
|
||||
t.Fatalf("failed to decode root response: %v", err)
|
||||
}
|
||||
|
||||
for _, want := range []struct{ key, value string }{
|
||||
{"Bose", "AfterTouch"},
|
||||
{"service", "Go/Chi"},
|
||||
{"docs", "https://gesellix.github.io/Bose-SoundTouch/"},
|
||||
} {
|
||||
if got[want.key] != want.value {
|
||||
t.Errorf("payload[%q] = %q, want %q", want.key, got[want.key], want.value)
|
||||
}
|
||||
}
|
||||
|
||||
// Version mirrors /health — falls back to "0.0.1" under `go test`
|
||||
// (debug.ReadBuildInfo reports Main.Version="(devel)") but must
|
||||
// always be present so monitoring tools can pin a release.
|
||||
if got["version"] == "" {
|
||||
t.Error("expected version field to be present")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user