add bridge version trace output

This commit is contained in:
Haitao Pan 2026-04-22 12:23:28 +08:00
parent bf1fcac528
commit cfd19f6626
5 changed files with 99 additions and 3 deletions

View File

@ -9,7 +9,7 @@ type imageVersionInfo struct {
Version string `json:"version,omitempty"`
}
func parseImageVersionInfo(imageRef string) imageVersionInfo {
func ParseImageVersionInfo(imageRef string) imageVersionInfo {
ref := strings.TrimSpace(imageRef)
info := imageVersionInfo{ImageRef: ref}
if ref == "" {

View File

@ -121,7 +121,7 @@ func (s *Server) Handler() http.Handler {
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
_, _ = w.Write([]byte("xworkmate-bridge is running"))
case "/api/ping":
info := parseImageVersionInfo(os.Getenv("IMAGE"))
info := ParseImageVersionInfo(os.Getenv("IMAGE"))
resp := map[string]any{
"status": "ok",
"image": info.ImageRef,

View File

@ -194,7 +194,7 @@ func TestHTTPHandlerBareAliasPathsServeRPC(t *testing.T) {
}
func TestParseImageVersionInfoHandlesTaggedImageRef(t *testing.T) {
info := parseImageVersionInfo("ghcr.io/x-evor/xworkmate-bridge:main-2026-04-12")
info := ParseImageVersionInfo("ghcr.io/x-evor/xworkmate-bridge:main-2026-04-12")
if info.ImageRef != "ghcr.io/x-evor/xworkmate-bridge:main-2026-04-12" {
t.Fatalf("expected full image ref, got %q", info.ImageRef)

28
main.go
View File

@ -1,6 +1,7 @@
package main
import (
"encoding/json"
"fmt"
"os"
@ -11,6 +12,16 @@ import (
)
func main() {
if len(os.Args) > 1 {
switch os.Args[1] {
case "-v", "--version":
if err := printBridgeVersionInfo(); err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)
}
return
}
}
if len(os.Args) > 1 && os.Args[1] == "serve" {
if err := acp.Serve(os.Args[2:]); err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
@ -39,3 +50,20 @@ func main() {
toolbridge.Run(os.Stdin, os.Stdout)
}
func printBridgeVersionInfo() error {
info := acp.ParseImageVersionInfo(os.Getenv("IMAGE"))
payload := map[string]any{
"status": "ok",
"image": info.ImageRef,
"tag": info.Tag,
"commit": info.Commit,
"version": info.Version,
}
encoded, err := json.Marshal(payload)
if err != nil {
return err
}
_, err = os.Stdout.Write(append(encoded, '\n'))
return err
}

View File

@ -2,10 +2,12 @@ package main
import (
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"
"time"
)
@ -129,3 +131,69 @@ func TestRunClaudeReviewSurfacesNonJSONStdout(t *testing.T) {
t.Fatal("expected non-json stdout error")
}
}
func TestPrintBridgeVersionInfoMatchesPingContract(t *testing.T) {
t.Setenv("IMAGE", "ghcr.io/x-evor/xworkmate-bridge:0123456789abcdef0123456789abcdef01234567")
output := captureStdout(t, printBridgeVersionInfo)
var payload map[string]any
if err := json.Unmarshal([]byte(output), &payload); err != nil {
t.Fatalf("decode version payload: %v", err)
}
if payload["status"] != "ok" {
t.Fatalf("expected status ok, got %#v", payload["status"])
}
if payload["image"] != "ghcr.io/x-evor/xworkmate-bridge:0123456789abcdef0123456789abcdef01234567" {
t.Fatalf("unexpected image ref: %#v", payload["image"])
}
if payload["tag"] != "0123456789abcdef0123456789abcdef01234567" {
t.Fatalf("unexpected tag: %#v", payload["tag"])
}
if payload["commit"] != "0123456789abcdef0123456789abcdef01234567" {
t.Fatalf("unexpected commit: %#v", payload["commit"])
}
if payload["version"] != "0123456789abcdef0123456789abcdef01234567" {
t.Fatalf("unexpected version: %#v", payload["version"])
}
}
func TestPrintBridgeVersionInfoWithoutImageEnv(t *testing.T) {
t.Setenv("IMAGE", "")
output := captureStdout(t, printBridgeVersionInfo)
if !strings.Contains(output, `"status":"ok"`) {
t.Fatalf("unexpected output: %q", output)
}
}
func captureStdout(t *testing.T, fn func() error) string {
t.Helper()
old := os.Stdout
r, w, err := os.Pipe()
if err != nil {
t.Fatalf("pipe stdout: %v", err)
}
os.Stdout = w
defer func() {
os.Stdout = old
}()
done := make(chan string, 1)
go func() {
var builder strings.Builder
_, _ = io.Copy(&builder, r)
done <- builder.String()
}()
callErr := fn()
_ = w.Close()
out := <-done
_ = r.Close()
if callErr != nil {
t.Fatalf("call failed: %v", callErr)
}
return strings.TrimSpace(out)
}