Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: update version command additions #27

Merged
merged 2 commits into from
Sep 15, 2023
Merged
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
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 {
wagoodman marked this conversation as resolved.
Show resolved Hide resolved
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)
}