Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ import (
"knative.dev/func/pkg/config"
fn "knative.dev/func/pkg/functions"
"knative.dev/func/pkg/k8s"
"knative.dev/func/pkg/version"
)

// DefaultVersion when building source directly (bypassing the Makefile)
const DefaultVersion = "v0.0.0+source"
// DefaultVersion when building source directly (bypassing the Makefile).
// Delegates to version.DefaultVers so the fallback is defined in one place.
const DefaultVersion = version.DefaultVers

// DefaultNamespace is the global static default namespace, and is equivalent
// to the Kubernetes default namespace.
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/AlecAivazis/survey/v2 v2.3.7
github.com/BurntSushi/toml v1.6.0
github.com/Masterminds/semver v1.5.0
github.com/Masterminds/semver/v3 v3.4.0
github.com/Microsoft/go-winio v0.6.2
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2
github.com/alecthomas/jsonschema v0.0.0-20220216202328-9eeeec9d044b
Expand Down Expand Up @@ -90,7 +91,6 @@ require (
github.com/Azure/go-autorest/autorest/date v0.3.1 // indirect
github.com/Azure/go-autorest/logger v0.2.2 // indirect
github.com/Azure/go-autorest/tracing v0.6.1 // indirect
github.com/Masterminds/semver/v3 v3.4.0 // indirect
github.com/OneOfOne/xxhash v1.2.8 // indirect
github.com/ProtonMail/go-crypto v1.4.0 // indirect
github.com/agext/levenshtein v1.2.3 // indirect
Expand Down
2 changes: 1 addition & 1 deletion pkg/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func Main() {
cfg := cmd.RootCommandConfig{
Name: "func",
Version: cmd.Version{
Vers: version.Vers,
Vers: version.Get().Original(),
Kver: version.Kver,
Hash: version.Hash,
}}
Expand Down
8 changes: 4 additions & 4 deletions pkg/mcp/mcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import (
"strings"

"github.com/modelcontextprotocol/go-sdk/mcp"
"knative.dev/func/pkg/version"
)

const (
name = "func"
title = "func"
version = "0.1.0"
name = "func"
title = "func"
)

// NOTE: Invoking prompts in some interfaces (such as Claude Code) when all
Expand Down Expand Up @@ -78,7 +78,7 @@ func New(options ...Option) *Server {
&mcp.Implementation{
Name: name,
Title: title,
Version: version},
Version: version.Get().String()},
&mcp.ServerOptions{
Instructions: instructions(s.readonly),
HasPrompts: true,
Expand Down
25 changes: 25 additions & 0 deletions pkg/version/version.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
package version

import "github.com/Masterminds/semver/v3"

var Vers, Kver, Hash string

// DefaultVers is the fallback version used when no build-time version was
// injected (e.g. source builds that bypass the Makefile).
const DefaultVers = "v0.0.0+source"

// Get returns the parsed semver for this binary. When no build-time version
// was injected via ldflags, DefaultVers is used. If the injected string is
// unparseable, DefaultVers is used as a safe fallback.
// String() returns a clean semver without the leading "v" (e.g. "0.0.0+source"),
// suitable for machine-readable consumers such as the MCP server.
// Original() round-trips the injected string verbatim, preserving the leading
// "v" preferred by human-readable output.
func Get() *semver.Version {
s := Vers
if s == "" {
s = DefaultVers
}
v, err := semver.NewVersion(s) // permissive: accepts leading 'v'
if err != nil {
v, _ = semver.NewVersion(DefaultVers)
}
return v
}
63 changes: 63 additions & 0 deletions pkg/version/version_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package version_test

import (
"testing"

"knative.dev/func/pkg/version"
)

// TestGet_Empty verifies that Get returns the DefaultVers fallback when no
// build-time version has been injected (Vers == "").
func TestGet_Empty(t *testing.T) {
orig := version.Vers
version.Vers = ""
defer func() { version.Vers = orig }()

v := version.Get()
if v == nil {
t.Fatal("expected non-nil *semver.Version")
}
// String() must be clean semver without a leading 'v'
if got := v.String(); got != "0.0.0+source" {
t.Errorf("String() = %q; want %q", got, "0.0.0+source")
}
// Original() must round-trip the full default string including 'v'
if got := v.Original(); got != "v0.0.0+source" {
t.Errorf("Original() = %q; want %q", got, "v0.0.0+source")
}
}

// TestGet_InjectedVersion verifies that a build-time version is parsed and
// exposed correctly.
func TestGet_InjectedVersion(t *testing.T) {
orig := version.Vers
version.Vers = "v1.2.3"
defer func() { version.Vers = orig }()

v := version.Get()
if v == nil {
t.Fatal("expected non-nil *semver.Version")
}
if got := v.String(); got != "1.2.3" {
t.Errorf("String() = %q; want %q", got, "1.2.3")
}
if got := v.Original(); got != "v1.2.3" {
t.Errorf("Original() = %q; want %q", got, "v1.2.3")
}
}

// TestGet_InvalidFallsBack verifies that an unparseable injected version does
// not panic and falls back to DefaultVers.
func TestGet_InvalidFallsBack(t *testing.T) {
orig := version.Vers
version.Vers = "not-a-semver!!!"
defer func() { version.Vers = orig }()

v := version.Get()
if v == nil {
t.Fatal("expected non-nil *semver.Version even for invalid input")
}
if got := v.String(); got != "0.0.0+source" {
t.Errorf("String() = %q; want %q on invalid input", got, "0.0.0+source")
}
}
Loading