feat(api): M-04 添加版本信息端点
- 添加 /version 端点返回版本信息 - 版本变量支持构建时 ldflags 注入 - 返回 version、commit、build_time、go_version
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -25,6 +26,13 @@ import (
|
||||
"sub2api-cn-relay-manager/internal/access"
|
||||
)
|
||||
|
||||
// 版本信息变量,在构建时通过 -ldflags 注入
|
||||
var (
|
||||
version = "dev"
|
||||
commit = "unknown"
|
||||
buildTime = "unknown"
|
||||
)
|
||||
|
||||
type ActionSet struct {
|
||||
CreateBatchImportRun func(context.Context, CreateBatchImportRunRequest) (BatchImportRunCreateResponse, error)
|
||||
ListBatchImportRuns func(context.Context, ListBatchImportRunsRequest) (ListBatchImportRunsResponse, error)
|
||||
@@ -327,6 +335,7 @@ func NewAPIHandler(adminToken string, actions ActionSet) http.Handler {
|
||||
func NewAPIHandlerWithAuth(adminAuth AdminAuthConfig, actions ActionSet) http.Handler {
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("GET /healthz", healthz)
|
||||
mux.HandleFunc("GET /version", handleVersion)
|
||||
mux.HandleFunc("GET /api/admin/session", func(w http.ResponseWriter, r *http.Request) {
|
||||
handleAdminSessionState(w, r, adminAuth)
|
||||
})
|
||||
@@ -557,6 +566,24 @@ func healthz(w http.ResponseWriter, _ *http.Request) {
|
||||
_, _ = w.Write([]byte("ok"))
|
||||
}
|
||||
|
||||
// VersionInfo 包含版本信息响应
|
||||
type VersionInfo struct {
|
||||
Version string `json:"version"`
|
||||
Commit string `json:"commit"`
|
||||
BuildTime string `json:"build_time"`
|
||||
GoVersion string `json:"go_version"`
|
||||
}
|
||||
|
||||
func handleVersion(w http.ResponseWriter, r *http.Request) {
|
||||
info := VersionInfo{
|
||||
Version: version,
|
||||
Commit: commit,
|
||||
BuildTime: buildTime,
|
||||
GoVersion: runtime.Version(),
|
||||
}
|
||||
writeJSON(w, http.StatusOK, info)
|
||||
}
|
||||
|
||||
func handleCreateProviderDraft(w http.ResponseWriter, r *http.Request, fn func(context.Context, CreateProviderDraftRequest) (ProviderDraftInfo, error)) {
|
||||
if fn == nil {
|
||||
writeHTTPError(w, &httpError{StatusCode: http.StatusInternalServerError, Code: "server_misconfigured", Message: "create-provider-draft action is not configured"})
|
||||
|
||||
73
internal/app/version_test.go
Normal file
73
internal/app/version_test.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHandleVersion(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", "/version", nil)
|
||||
rr := httptest.NewRecorder()
|
||||
|
||||
handleVersion(rr, req)
|
||||
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Errorf("Expected status 200, got %d", rr.Code)
|
||||
}
|
||||
|
||||
contentType := rr.Header().Get("Content-Type")
|
||||
if contentType != "application/json" {
|
||||
t.Errorf("Expected Content-Type application/json, got %s", contentType)
|
||||
}
|
||||
|
||||
var info VersionInfo
|
||||
if err := json.Unmarshal(rr.Body.Bytes(), &info); err != nil {
|
||||
t.Fatalf("Failed to decode response: %v", err)
|
||||
}
|
||||
|
||||
// 验证版本字段
|
||||
if info.Version == "" {
|
||||
t.Error("Version should not be empty")
|
||||
}
|
||||
if info.Version != version {
|
||||
t.Errorf("Version = %q, want %q", info.Version, version)
|
||||
}
|
||||
|
||||
// 验证 Go 版本
|
||||
if info.GoVersion != runtime.Version() {
|
||||
t.Errorf("GoVersion = %q, want %q", info.GoVersion, runtime.Version())
|
||||
}
|
||||
|
||||
// Commit 和 BuildTime 可能为默认值
|
||||
if info.Commit == "" {
|
||||
t.Error("Commit should not be empty (may be 'unknown' during development)")
|
||||
}
|
||||
if info.BuildTime == "" {
|
||||
t.Error("BuildTime should not be empty (may be 'unknown' during development)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersionEndpoint_Integration(t *testing.T) {
|
||||
handler := NewAPIHandler("", ActionSet{})
|
||||
|
||||
req := httptest.NewRequest("GET", "/version", nil)
|
||||
rr := httptest.NewRecorder()
|
||||
|
||||
handler.ServeHTTP(rr, req)
|
||||
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Errorf("Expected status 200, got %d", rr.Code)
|
||||
}
|
||||
|
||||
var info VersionInfo
|
||||
if err := json.Unmarshal(rr.Body.Bytes(), &info); err != nil {
|
||||
t.Fatalf("Failed to decode response: %v", err)
|
||||
}
|
||||
|
||||
if info.Version != version {
|
||||
t.Errorf("Version = %q, want %q", info.Version, version)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user