Skip to content

Commit

Permalink
chore: update version command additions (#27)
Browse files Browse the repository at this point in the history
Signed-off-by: Keith Zantow <[email protected]>
  • Loading branch information
kzantow authored Sep 15, 2023
1 parent c42d666 commit f1acbce
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 66 deletions.
157 changes: 91 additions & 66 deletions version.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"bytes"
"encoding/json"
"fmt"
"os"
"runtime"

"github.com/iancoleman/strcase"
Expand All @@ -27,79 +26,29 @@ type runtimeInfo struct {
Platform string `json:"platform,omitempty"` // GOOS and GOARCH at build-time
}

type additions = func() (name string, value string)
type versionAddition = func() (name string, value any)

func VersionCommand(id Identification, additions ...additions) *cobra.Command {
func VersionCommand(id Identification, additions ...versionAddition) *cobra.Command {
var format string

info := runtimeInfo{
Identification: id,
GoVersion: runtime.Version(),
Compiler: runtime.Compiler,
Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH),
}

cmd := &cobra.Command{
Use: "version",
Short: "show version information",
Args: cobra.NoArgs,
// note: we intentionally do not execute through the application infrastructure (no app config is required for this command)
RunE: func(cmd *cobra.Command, args []string) error {
switch format {
case "text", "":
printIfNotEmpty("Application", info.Name)
printIfNotEmpty("Version", info.Identification.Version)
printIfNotEmpty("BuildDate", info.BuildDate)
printIfNotEmpty("GitCommit", info.GitCommit)
printIfNotEmpty("GitDescription", info.GitDescription)
printIfNotEmpty("Platform", info.Platform)
printIfNotEmpty("GoVersion", info.GoVersion)
printIfNotEmpty("Compiler", info.Compiler)

for _, addition := range additions {
name, value := addition()
printIfNotEmpty(name, value)
}
case "json":
var info any = info

if len(additions) > 0 {
buf := &bytes.Buffer{}
enc := json.NewEncoder(buf)
enc.SetEscapeHTML(false)
err := enc.Encode(info)
if err != nil {
return fmt.Errorf("failed to show version information: %w", err)
}

var data map[string]any
dec := json.NewDecoder(buf)
err = dec.Decode(&data)
if err != nil {
return fmt.Errorf("failed to show version information: %w", err)
}

for _, addition := range additions {
name, value := addition()
name = strcase.ToLowerCamel(name)
data[name] = value
}

info = data
}

enc := json.NewEncoder(os.Stdout)
enc.SetEscapeHTML(false)
enc.SetIndent("", " ")
err := enc.Encode(info)
if err != nil {
return fmt.Errorf("failed to show version information: %w", err)
}
default:
return fmt.Errorf("unsupported output format: %s", format)
info := runtimeInfo{
Identification: id,
GoVersion: runtime.Version(),
Compiler: runtime.Compiler,
Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH),
}

return nil
value, err := versionInfo(info, format, additions...)
if err == nil {
fmt.Print(value)
}
return err
},
}

Expand All @@ -109,10 +58,86 @@ func VersionCommand(id Identification, additions ...additions) *cobra.Command {
return cmd
}

func printIfNotEmpty(title, value string) {
if value == "" {
func versionInfo(info runtimeInfo, format string, additions ...versionAddition) (string, error) {
buf := &bytes.Buffer{}

switch format {
case "text", "":
type additionType struct {
name string
value any
}
var add []additionType
pad := 10
for _, addition := range additions {
name, value := addition()
if fmt.Sprintf("%v", value) == "" {
continue
}
if pad < len(name) {
pad = len(name)
}
add = append(add, additionType{name: name, value: value})
}

appendLine(buf, "Application", pad, info.Name)
appendLine(buf, "Version", pad, info.Identification.Version)
appendLine(buf, "BuildDate", pad, info.BuildDate)
appendLine(buf, "GitCommit", pad, info.GitCommit)
appendLine(buf, "GitDescription", pad, info.GitDescription)
appendLine(buf, "Platform", pad, info.Platform)
appendLine(buf, "GoVersion", pad, info.GoVersion)
appendLine(buf, "Compiler", pad, info.Compiler)

for _, a := range add {
appendLine(buf, a.name, pad, a.value)
}
case "json":
var info any = info

if len(additions) > 0 {
buf := &bytes.Buffer{}
enc := json.NewEncoder(buf)
enc.SetEscapeHTML(false)
err := enc.Encode(info)
if err != nil {
return "", fmt.Errorf("failed to show version information: %w", err)
}

var data map[string]any
dec := json.NewDecoder(buf)
err = dec.Decode(&data)
if err != nil {
return "", fmt.Errorf("failed to show version information: %w", err)
}

for _, addition := range additions {
name, value := addition()
name = strcase.ToLowerCamel(name)
data[name] = value
}

info = data
}

enc := json.NewEncoder(buf)
enc.SetEscapeHTML(false)
enc.SetIndent("", " ")
err := enc.Encode(info)
if err != nil {
return "", fmt.Errorf("failed to show version information: %w", err)
}
default:
return "", fmt.Errorf("unsupported output format: %s", format)
}

return buf.String(), nil
}

func appendLine(buf *bytes.Buffer, title string, width int, value any) {
if fmt.Sprintf("%v", value) == "" {
return
}

fmt.Printf("%-16s %s\n", title+":", value)
_, _ = fmt.Fprintf(buf, "%-*s %v\n", width+1, title+":", value)
}
69 changes: 69 additions & 0 deletions version_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package clio

import (
"testing"

"github.com/stretchr/testify/require"
)

func Test_versionInfoText(t *testing.T) {
expected := `Application: the-name
Version: the-version
BuildDate: the-build-date
GitCommit: the-commit
GitDescription: the-description
Platform: linux/amd64
GoVersion: go1.21.1
Compiler: gc
Addition With A Long Line: some-value
`
got, err := versionInfo(runtimeInfo{
Identification: Identification{
Name: "the-name",
Version: "the-version",
GitCommit: "the-commit",
GitDescription: "the-description",
BuildDate: "the-build-date",
},
GoVersion: "go1.21.1",
Compiler: "gc",
Platform: "linux/amd64",
}, "text", func() (name string, value any) {
return "Addition With A Long Line", "some-value"
})
require.NoError(t, err)
require.Equal(t, expected, got)
}

func Test_versionInfoJSON(t *testing.T) {
expected := `{
"additionalValue": "some-value",
"someValueWithSpacesAndUpper": "some-other-value",
"application": "the-name",
"buildDate": "the-build-date",
"compiler": "gc",
"gitCommit": "the-commit",
"gitDescription": "the-description",
"goVersion": "go1.21.1",
"platform": "linux/amd64",
"version": "the-version"
}`
got, err := versionInfo(runtimeInfo{
Identification: Identification{
Name: "the-name",
Version: "the-version",
GitCommit: "the-commit",
GitDescription: "the-description",
BuildDate: "the-build-date",
},
GoVersion: "go1.21.1",
Compiler: "gc",
Platform: "linux/amd64",
}, "json", func() (name string, value any) {
return "additionalValue", "some-value"
}, func() (name string, value any) {
return "Some Value With Spaces and UPPER", "some-other-value"
})
require.NoError(t, err)
require.JSONEq(t, expected, got)
}

0 comments on commit f1acbce

Please sign in to comment.