diff --git a/pkg/parser/mcp.go b/pkg/parser/mcp.go index 92761f0d38..d0d18010e0 100644 --- a/pkg/parser/mcp.go +++ b/pkg/parser/mcp.go @@ -8,6 +8,7 @@ import ( "github.com/githubnext/gh-aw/pkg/constants" "github.com/githubnext/gh-aw/pkg/logger" + "github.com/githubnext/gh-aw/pkg/stringutil" "github.com/modelcontextprotocol/go-sdk/mcp" ) @@ -369,21 +370,7 @@ func processBuiltinMCPTool(toolName string, toolValue any, serverFilter string) // Check for custom Docker image version (only applicable in local/Docker mode) if !useRemote { if version, exists := toolConfig["version"]; exists { - var versionStr string - switch v := version.(type) { - case string: - versionStr = v - case int: - versionStr = fmt.Sprintf("%d", v) - case int64: - versionStr = fmt.Sprintf("%d", v) - case uint64: - versionStr = fmt.Sprintf("%d", v) - case float64: - // Use %g to avoid trailing zeros and scientific notation for simple numbers - versionStr = fmt.Sprintf("%g", v) - } - if versionStr != "" { + if versionStr := stringutil.ParseVersionValue(version); versionStr != "" { dockerImage := "ghcr.io/github/github-mcp-server:" + versionStr // Update the Docker image in args for i, arg := range config.Args { @@ -458,20 +445,7 @@ func processBuiltinMCPTool(toolName string, toolValue any, serverFilter string) // Check for custom Docker image version if version, exists := toolConfig["version"]; exists { - var versionStr string - switch v := version.(type) { - case string: - versionStr = v - case int: - versionStr = fmt.Sprintf("%d", v) - case int64: - versionStr = fmt.Sprintf("%d", v) - case uint64: - versionStr = fmt.Sprintf("%d", v) - case float64: - versionStr = fmt.Sprintf("%g", v) - } - if versionStr != "" { + if versionStr := stringutil.ParseVersionValue(version); versionStr != "" { dockerImage := "mcr.microsoft.com/playwright:" + versionStr // Update the Docker image in args for i, arg := range config.Args { diff --git a/pkg/stringutil/stringutil.go b/pkg/stringutil/stringutil.go index e44a06e81b..2462ce4c60 100644 --- a/pkg/stringutil/stringutil.go +++ b/pkg/stringutil/stringutil.go @@ -1,7 +1,10 @@ // Package stringutil provides utility functions for working with strings. package stringutil -import "strings" +import ( + "fmt" + "strings" +) // Truncate truncates a string to a maximum length, adding "..." if truncated. // If maxLen is 3 or less, the string is truncated without "...". @@ -33,3 +36,19 @@ func NormalizeWhitespace(content string) string { return normalized } + +// ParseVersionValue converts version values of various types to strings. +// Supports string, int, int64, uint64, and float64 types. +// Returns empty string for unsupported types. +func ParseVersionValue(version any) string { + switch v := version.(type) { + case string: + return v + case int, int64, uint64: + return fmt.Sprintf("%d", v) + case float64: + return fmt.Sprintf("%g", v) + default: + return "" + } +} diff --git a/pkg/stringutil/stringutil_test.go b/pkg/stringutil/stringutil_test.go index 460f2ad497..9824f2b444 100644 --- a/pkg/stringutil/stringutil_test.go +++ b/pkg/stringutil/stringutil_test.go @@ -324,3 +324,90 @@ func BenchmarkNormalizeWhitespace_ManyChanges(b *testing.B) { NormalizeWhitespace(content) } } + +func TestParseVersionValue(t *testing.T) { + tests := []struct { + name string + version any + expected string + }{ + // String versions + { + name: "string version", + version: "v1.2.3", + expected: "v1.2.3", + }, + { + name: "numeric string", + version: "123", + expected: "123", + }, + { + name: "empty string", + version: "", + expected: "", + }, + // Integer versions + { + name: "int version", + version: 42, + expected: "42", + }, + { + name: "int64 version", + version: int64(100), + expected: "100", + }, + { + name: "uint64 version", + version: uint64(999), + expected: "999", + }, + // Float versions + { + name: "float64 simple", + version: float64(1.5), + expected: "1.5", + }, + { + name: "float64 whole number", + version: float64(2.0), + expected: "2", + }, + { + name: "float64 with precision", + version: float64(1.234), + expected: "1.234", + }, + // Unsupported types + { + name: "nil", + version: nil, + expected: "", + }, + { + name: "bool", + version: true, + expected: "", + }, + { + name: "slice", + version: []string{"1", "2"}, + expected: "", + }, + { + name: "map", + version: map[string]string{"version": "1.0"}, + expected: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := ParseVersionValue(tt.version) + if result != tt.expected { + t.Errorf("ParseVersionValue(%v) = %q, expected %q", tt.version, result, tt.expected) + } + }) + } +} diff --git a/pkg/workflow/engine.go b/pkg/workflow/engine.go index 10f86d9b2f..a6447914e3 100644 --- a/pkg/workflow/engine.go +++ b/pkg/workflow/engine.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/githubnext/gh-aw/pkg/logger" + "github.com/githubnext/gh-aw/pkg/stringutil" ) var engineLog = logger.New("workflow:engine") @@ -64,14 +65,7 @@ func (c *Compiler) ExtractEngineConfig(frontmatter map[string]any) (string, *Eng // Extract optional 'version' field if version, hasVersion := engineObj["version"]; hasVersion { - switch v := version.(type) { - case string: - config.Version = v - case int, int64, uint64: - config.Version = fmt.Sprintf("%d", v) - case float64: - config.Version = fmt.Sprintf("%g", v) - } + config.Version = stringutil.ParseVersionValue(version) } // Extract optional 'model' field