feat:Modify the location where version is obtained, and insert version information into the context (#1300)
* feat:migrate version info from internal package to pkg/config * * fix lint issue
This commit is contained in:
parent
95716b106b
commit
680e845d61
14 changed files with 179 additions and 111 deletions
|
|
@ -18,10 +18,10 @@ builds:
|
|||
- stdjson
|
||||
ldflags:
|
||||
- -s -w
|
||||
- -X github.com/sipeed/picoclaw/cmd/picoclaw/internal.version={{ .Version }}
|
||||
- -X github.com/sipeed/picoclaw/cmd/picoclaw/internal.gitCommit={{ .ShortCommit }}
|
||||
- -X github.com/sipeed/picoclaw/cmd/picoclaw/internal.buildTime={{ .Date }}
|
||||
- -X github.com/sipeed/picoclaw/cmd/picoclaw/internal.goVersion={{ .Env.GOVERSION }}
|
||||
- -X github.com/sipeed/picoclaw/pkg/config.Version={{ .Version }}
|
||||
- -X github.com/sipeed/picoclaw/pkg/config.GitCommit={{ .ShortCommit }}
|
||||
- -X github.com/sipeed/picoclaw/pkg/config.BuildTime={{ .Date }}
|
||||
- -X github.com/sipeed/picoclaw/pkg/config.GoVersion={{ .Env.GOVERSION }}
|
||||
goos:
|
||||
- linux
|
||||
- windows
|
||||
|
|
|
|||
4
Makefile
4
Makefile
|
|
@ -11,8 +11,8 @@ VERSION?=$(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
|
|||
GIT_COMMIT=$(shell git rev-parse --short=8 HEAD 2>/dev/null || echo "dev")
|
||||
BUILD_TIME=$(shell date +%FT%T%z)
|
||||
GO_VERSION=$(shell $(GO) version | awk '{print $$3}')
|
||||
INTERNAL=github.com/sipeed/picoclaw/cmd/picoclaw/internal
|
||||
LDFLAGS=-ldflags "-X $(INTERNAL).version=$(VERSION) -X $(INTERNAL).gitCommit=$(GIT_COMMIT) -X $(INTERNAL).buildTime=$(BUILD_TIME) -X $(INTERNAL).goVersion=$(GO_VERSION) -s -w"
|
||||
CONFIG_PKG=github.com/sipeed/picoclaw/pkg/config
|
||||
LDFLAGS=-ldflags "-X $(CONFIG_PKG).Version=$(VERSION) -X $(CONFIG_PKG).GitCommit=$(GIT_COMMIT) -X $(CONFIG_PKG).BuildTime=$(BUILD_TIME) -X $(CONFIG_PKG).GoVersion=$(GO_VERSION) -s -w"
|
||||
|
||||
# Go variables
|
||||
GO?=CGO_ENABLED=0 go
|
||||
|
|
|
|||
|
|
@ -1,23 +1,14 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/sipeed/picoclaw/pkg/config"
|
||||
)
|
||||
|
||||
const Logo = "🦞"
|
||||
|
||||
var (
|
||||
version = "dev"
|
||||
gitCommit string
|
||||
buildTime string
|
||||
goVersion string
|
||||
)
|
||||
|
||||
// GetPicoclawHome returns the picoclaw home directory.
|
||||
// Priority: $PICOCLAW_HOME > ~/.picoclaw
|
||||
func GetPicoclawHome() string {
|
||||
|
|
@ -40,25 +31,19 @@ func LoadConfig() (*config.Config, error) {
|
|||
}
|
||||
|
||||
// FormatVersion returns the version string with optional git commit
|
||||
// Deprecated: Use pkg/config.FormatVersion instead
|
||||
func FormatVersion() string {
|
||||
v := version
|
||||
if gitCommit != "" {
|
||||
v += fmt.Sprintf(" (git: %s)", gitCommit)
|
||||
}
|
||||
return v
|
||||
return config.FormatVersion()
|
||||
}
|
||||
|
||||
// FormatBuildInfo returns build time and go version info
|
||||
// Deprecated: Use pkg/config.FormatBuildInfo instead
|
||||
func FormatBuildInfo() (string, string) {
|
||||
build := buildTime
|
||||
goVer := goVersion
|
||||
if goVer == "" {
|
||||
goVer = runtime.Version()
|
||||
}
|
||||
return build, goVer
|
||||
return config.FormatBuildInfo()
|
||||
}
|
||||
|
||||
// GetVersion returns the version string
|
||||
// Deprecated: Use pkg/config.GetVersion instead
|
||||
func GetVersion() string {
|
||||
return version
|
||||
return config.GetVersion()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,65 +40,6 @@ func TestGetConfigPath_WithPICOCLAW_CONFIG(t *testing.T) {
|
|||
assert.Equal(t, want, got)
|
||||
}
|
||||
|
||||
func TestFormatVersion_NoGitCommit(t *testing.T) {
|
||||
oldVersion, oldGit := version, gitCommit
|
||||
t.Cleanup(func() { version, gitCommit = oldVersion, oldGit })
|
||||
|
||||
version = "1.2.3"
|
||||
gitCommit = ""
|
||||
|
||||
assert.Equal(t, "1.2.3", FormatVersion())
|
||||
}
|
||||
|
||||
func TestFormatVersion_WithGitCommit(t *testing.T) {
|
||||
oldVersion, oldGit := version, gitCommit
|
||||
t.Cleanup(func() { version, gitCommit = oldVersion, oldGit })
|
||||
|
||||
version = "1.2.3"
|
||||
gitCommit = "abc123"
|
||||
|
||||
assert.Equal(t, "1.2.3 (git: abc123)", FormatVersion())
|
||||
}
|
||||
|
||||
func TestFormatBuildInfo_UsesBuildTimeAndGoVersion_WhenSet(t *testing.T) {
|
||||
oldBuildTime, oldGoVersion := buildTime, goVersion
|
||||
t.Cleanup(func() { buildTime, goVersion = oldBuildTime, oldGoVersion })
|
||||
|
||||
buildTime = "2026-02-20T00:00:00Z"
|
||||
goVersion = "go1.23.0"
|
||||
|
||||
build, goVer := FormatBuildInfo()
|
||||
|
||||
assert.Equal(t, buildTime, build)
|
||||
assert.Equal(t, goVersion, goVer)
|
||||
}
|
||||
|
||||
func TestFormatBuildInfo_EmptyBuildTime_ReturnsEmptyBuild(t *testing.T) {
|
||||
oldBuildTime, oldGoVersion := buildTime, goVersion
|
||||
t.Cleanup(func() { buildTime, goVersion = oldBuildTime, oldGoVersion })
|
||||
|
||||
buildTime = ""
|
||||
goVersion = "go1.23.0"
|
||||
|
||||
build, goVer := FormatBuildInfo()
|
||||
|
||||
assert.Empty(t, build)
|
||||
assert.Equal(t, goVersion, goVer)
|
||||
}
|
||||
|
||||
func TestFormatBuildInfo_EmptyGoVersion_FallsBackToRuntimeVersion(t *testing.T) {
|
||||
oldBuildTime, oldGoVersion := buildTime, goVersion
|
||||
t.Cleanup(func() { buildTime, goVersion = oldBuildTime, oldGoVersion })
|
||||
|
||||
buildTime = "x"
|
||||
goVersion = ""
|
||||
|
||||
build, goVer := FormatBuildInfo()
|
||||
|
||||
assert.Equal(t, "x", build)
|
||||
assert.Equal(t, runtime.Version(), goVer)
|
||||
}
|
||||
|
||||
func TestGetConfigPath_Windows(t *testing.T) {
|
||||
if runtime.GOOS != "windows" {
|
||||
t.Skip("windows-specific HOME behavior varies; run on windows")
|
||||
|
|
@ -112,17 +53,3 @@ func TestGetConfigPath_Windows(t *testing.T) {
|
|||
|
||||
require.True(t, strings.EqualFold(got, want), "GetConfigPath() = %q, want %q", got, want)
|
||||
}
|
||||
|
||||
func TestGetVersion(t *testing.T) {
|
||||
assert.Equal(t, "dev", GetVersion())
|
||||
}
|
||||
|
||||
func TestGetConfigPath_WithEnv(t *testing.T) {
|
||||
t.Setenv("PICOCLAW_CONFIG", "/tmp/custom/config.json")
|
||||
t.Setenv("HOME", "/tmp/home") // Also set home to ensure env is preferred
|
||||
|
||||
got := GetConfigPath()
|
||||
want := "/tmp/custom/config.json"
|
||||
|
||||
assert.Equal(t, want, got)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/sipeed/picoclaw/cmd/picoclaw/internal"
|
||||
"github.com/sipeed/picoclaw/pkg/auth"
|
||||
"github.com/sipeed/picoclaw/pkg/config"
|
||||
)
|
||||
|
||||
func statusCmd() {
|
||||
|
|
@ -18,8 +19,8 @@ func statusCmd() {
|
|||
configPath := internal.GetConfigPath()
|
||||
|
||||
fmt.Printf("%s picoclaw Status\n", internal.Logo)
|
||||
fmt.Printf("Version: %s\n", internal.FormatVersion())
|
||||
build, _ := internal.FormatBuildInfo()
|
||||
fmt.Printf("Version: %s\n", config.FormatVersion())
|
||||
build, _ := config.FormatBuildInfo()
|
||||
if build != "" {
|
||||
fmt.Printf("Build: %s\n", build)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/sipeed/picoclaw/cmd/picoclaw/internal"
|
||||
"github.com/sipeed/picoclaw/pkg/config"
|
||||
)
|
||||
|
||||
func NewVersionCommand() *cobra.Command {
|
||||
|
|
@ -22,8 +23,8 @@ func NewVersionCommand() *cobra.Command {
|
|||
}
|
||||
|
||||
func printVersion() {
|
||||
fmt.Printf("%s picoclaw %s\n", internal.Logo, internal.FormatVersion())
|
||||
build, goVer := internal.FormatBuildInfo()
|
||||
fmt.Printf("%s picoclaw %s\n", internal.Logo, config.FormatVersion())
|
||||
build, goVer := config.FormatBuildInfo()
|
||||
if build != "" {
|
||||
fmt.Printf(" Build: %s\n", build)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,10 +22,11 @@ import (
|
|||
"github.com/sipeed/picoclaw/cmd/picoclaw/internal/skills"
|
||||
"github.com/sipeed/picoclaw/cmd/picoclaw/internal/status"
|
||||
"github.com/sipeed/picoclaw/cmd/picoclaw/internal/version"
|
||||
"github.com/sipeed/picoclaw/pkg/config"
|
||||
)
|
||||
|
||||
func NewPicoclawCommand() *cobra.Command {
|
||||
short := fmt.Sprintf("%s picoclaw - Personal AI Assistant v%s\n\n", internal.Logo, internal.GetVersion())
|
||||
short := fmt.Sprintf("%s picoclaw - Personal AI Assistant v%s\n\n", internal.Logo, config.GetVersion())
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "picoclaw",
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/sipeed/picoclaw/cmd/picoclaw/internal"
|
||||
"github.com/sipeed/picoclaw/pkg/config"
|
||||
)
|
||||
|
||||
func TestNewPicoclawCommand(t *testing.T) {
|
||||
|
|
@ -16,7 +17,7 @@ func TestNewPicoclawCommand(t *testing.T) {
|
|||
|
||||
require.NotNil(t, cmd)
|
||||
|
||||
short := fmt.Sprintf("%s picoclaw - Personal AI Assistant v%s\n\n", internal.Logo, internal.GetVersion())
|
||||
short := fmt.Sprintf("%s picoclaw - Personal AI Assistant v%s\n\n", internal.Logo, config.GetVersion())
|
||||
|
||||
assert.Equal(t, "picoclaw", cmd.Use)
|
||||
assert.Equal(t, short, cmd.Short)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/sipeed/picoclaw/pkg/config"
|
||||
"github.com/sipeed/picoclaw/pkg/logger"
|
||||
"github.com/sipeed/picoclaw/pkg/providers"
|
||||
"github.com/sipeed/picoclaw/pkg/skills"
|
||||
|
|
@ -80,8 +81,10 @@ func NewContextBuilder(workspace string) *ContextBuilder {
|
|||
func (cb *ContextBuilder) getIdentity() string {
|
||||
workspacePath, _ := filepath.Abs(filepath.Join(cb.workspace))
|
||||
toolDiscovery := cb.getDiscoveryRule()
|
||||
version := config.FormatVersion()
|
||||
|
||||
return fmt.Sprintf(`# picoclaw 🦞
|
||||
return fmt.Sprintf(
|
||||
`# picoclaw 🦞 (%s)
|
||||
|
||||
You are picoclaw, a helpful AI assistant.
|
||||
|
||||
|
|
@ -102,7 +105,7 @@ Your workspace is at: %s
|
|||
4. **Context summaries** - Conversation summaries provided as context are approximate references only. They may be incomplete or outdated. Always defer to explicit user instructions over summary content.
|
||||
|
||||
%s`,
|
||||
workspacePath, workspacePath, workspacePath, workspacePath, workspacePath, toolDiscovery)
|
||||
version, workspacePath, workspacePath, workspacePath, workspacePath, workspacePath, toolDiscovery)
|
||||
}
|
||||
|
||||
func (cb *ContextBuilder) getDiscoveryRule() string {
|
||||
|
|
|
|||
|
|
@ -59,6 +59,16 @@ type Config struct {
|
|||
Tools ToolsConfig `json:"tools"`
|
||||
Heartbeat HeartbeatConfig `json:"heartbeat"`
|
||||
Devices DevicesConfig `json:"devices"`
|
||||
// BuildInfo contains build-time version information
|
||||
BuildInfo BuildInfo `json:"build_info,omitempty"`
|
||||
}
|
||||
|
||||
// BuildInfo contains build-time version information
|
||||
type BuildInfo struct {
|
||||
Version string `json:"version"`
|
||||
GitCommit string `json:"git_commit"`
|
||||
BuildTime string `json:"build_time"`
|
||||
GoVersion string `json:"go_version"`
|
||||
}
|
||||
|
||||
// MarshalJSON implements custom JSON marshaling for Config
|
||||
|
|
|
|||
|
|
@ -510,5 +510,11 @@ func DefaultConfig() *Config {
|
|||
Enabled: false,
|
||||
MonitorUSB: true,
|
||||
},
|
||||
BuildInfo: BuildInfo{
|
||||
Version: Version,
|
||||
GitCommit: GitCommit,
|
||||
BuildTime: BuildTime,
|
||||
GoVersion: GoVersion,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
44
pkg/config/version.go
Normal file
44
pkg/config/version.go
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// Build-time variables injected via ldflags during build process.
|
||||
// These are set by the Makefile or .goreleaser.yaml using the -X flag:
|
||||
//
|
||||
// -X github.com/sipeed/picoclaw/pkg/config.Version=<version>
|
||||
// -X github.com/sipeed/picoclaw/pkg/config.GitCommit=<commit>
|
||||
// -X github.com/sipeed/picoclaw/pkg/config.BuildTime=<timestamp>
|
||||
// -X github.com/sipeed/picoclaw/pkg/config.GoVersion=<go-version>
|
||||
var (
|
||||
Version = "dev" // Default value when not built with ldflags
|
||||
GitCommit string // Git commit SHA (short)
|
||||
BuildTime string // Build timestamp in RFC3339 format
|
||||
GoVersion string // Go version used for building
|
||||
)
|
||||
|
||||
// FormatVersion returns the version string with optional git commit
|
||||
func FormatVersion() string {
|
||||
v := Version
|
||||
if GitCommit != "" {
|
||||
v += fmt.Sprintf(" (git: %s)", GitCommit)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// FormatBuildInfo returns build time and go version info
|
||||
func FormatBuildInfo() (string, string) {
|
||||
build := BuildTime
|
||||
goVer := GoVersion
|
||||
if goVer == "" {
|
||||
goVer = runtime.Version()
|
||||
}
|
||||
return build, goVer
|
||||
}
|
||||
|
||||
// GetVersion returns the version string
|
||||
func GetVersion() string {
|
||||
return Version
|
||||
}
|
||||
92
pkg/config/version_test.go
Normal file
92
pkg/config/version_test.go
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestFormatVersion_NoGitCommit(t *testing.T) {
|
||||
oldVersion, oldGit := Version, GitCommit
|
||||
t.Cleanup(func() { Version, GitCommit = oldVersion, oldGit })
|
||||
|
||||
Version = "1.2.3"
|
||||
GitCommit = ""
|
||||
|
||||
assert.Equal(t, "1.2.3", FormatVersion())
|
||||
}
|
||||
|
||||
func TestFormatVersion_WithGitCommit(t *testing.T) {
|
||||
oldVersion, oldGit := Version, GitCommit
|
||||
t.Cleanup(func() { Version, GitCommit = oldVersion, oldGit })
|
||||
|
||||
Version = "1.2.3"
|
||||
GitCommit = "abc123"
|
||||
|
||||
assert.Equal(t, "1.2.3 (git: abc123)", FormatVersion())
|
||||
}
|
||||
|
||||
func TestFormatBuildInfo_UsesBuildTimeAndGoVersion_WhenSet(t *testing.T) {
|
||||
oldBuildTime, oldGoVersion := BuildTime, GoVersion
|
||||
t.Cleanup(func() { BuildTime, GoVersion = oldBuildTime, oldGoVersion })
|
||||
|
||||
BuildTime = "2026-02-20T00:00:00Z"
|
||||
GoVersion = "go1.23.0"
|
||||
|
||||
build, goVer := FormatBuildInfo()
|
||||
|
||||
assert.Equal(t, BuildTime, build)
|
||||
assert.Equal(t, GoVersion, goVer)
|
||||
}
|
||||
|
||||
func TestFormatBuildInfo_EmptyBuildTime_ReturnsEmptyBuild(t *testing.T) {
|
||||
oldBuildTime, oldGoVersion := BuildTime, GoVersion
|
||||
t.Cleanup(func() { BuildTime, GoVersion = oldBuildTime, oldGoVersion })
|
||||
|
||||
BuildTime = ""
|
||||
GoVersion = "go1.23.0"
|
||||
|
||||
build, goVer := FormatBuildInfo()
|
||||
|
||||
assert.Empty(t, build)
|
||||
assert.Equal(t, GoVersion, goVer)
|
||||
}
|
||||
|
||||
func TestFormatBuildInfo_EmptyGoVersion_FallsBackToRuntimeVersion(t *testing.T) {
|
||||
oldBuildTime, oldGoVersion := BuildTime, GoVersion
|
||||
t.Cleanup(func() { BuildTime, GoVersion = oldBuildTime, oldGoVersion })
|
||||
|
||||
BuildTime = "x"
|
||||
GoVersion = ""
|
||||
|
||||
build, goVer := FormatBuildInfo()
|
||||
|
||||
assert.Equal(t, "x", build)
|
||||
assert.Equal(t, runtime.Version(), goVer)
|
||||
}
|
||||
|
||||
func TestGetVersion(t *testing.T) {
|
||||
oldVersion := Version
|
||||
t.Cleanup(func() { Version = oldVersion })
|
||||
|
||||
Version = "dev"
|
||||
assert.Equal(t, "dev", GetVersion())
|
||||
}
|
||||
|
||||
func TestGetVersion_Custom(t *testing.T) {
|
||||
oldVersion := Version
|
||||
t.Cleanup(func() { Version = oldVersion })
|
||||
|
||||
Version = "v1.0.0"
|
||||
assert.Equal(t, "v1.0.0", GetVersion())
|
||||
}
|
||||
|
||||
func TestVersion_DefaultIsDev(t *testing.T) {
|
||||
// Reset to default values
|
||||
oldVersion := Version
|
||||
Version = "dev"
|
||||
t.Cleanup(func() { Version = oldVersion })
|
||||
|
||||
assert.Equal(t, "dev", Version)
|
||||
}
|
||||
|
|
@ -6,9 +6,6 @@ PicoClaw 🦞
|
|||
## Description
|
||||
Ultra-lightweight personal AI assistant written in Go, inspired by nanobot.
|
||||
|
||||
## Version
|
||||
0.1.0
|
||||
|
||||
## Purpose
|
||||
- Provide intelligent AI assistance with minimal resource usage
|
||||
- Support multiple LLM providers (OpenAI, Anthropic, Zhipu, etc.)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue