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

Extend version command to help troubleshoot porter #642

Merged
merged 10 commits into from
Sep 30, 2019
3 changes: 2 additions & 1 deletion cmd/porter/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
)

func buildVersionCommand(p *porter.Porter) *cobra.Command {
opts := version.Options{}
opts := porter.VersionOpts{}
cmd := &cobra.Command{
Use: "version",
Short: "Print the application version",
Expand All @@ -25,6 +25,7 @@ func buildVersionCommand(p *porter.Porter) *cobra.Command {
f := cmd.Flags()
f.StringVarP(&opts.RawFormat, "output", "o", string(version.DefaultVersionFormat),
"Specify an output format. Allowed values: json, plaintext")
f.BoolVarP(&opts.System, "system", "s", false, "Print system debug information")

return cmd
}
1 change: 1 addition & 0 deletions docs/content/cli/version.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ porter version [flags]
```
-h, --help help for version
-o, --output string Specify an output format. Allowed values: json, plaintext (default "plaintext")
-s, --system Print system debug information
```

### Options inherited from parent commands
Expand Down
101 changes: 99 additions & 2 deletions pkg/porter/version.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,115 @@
package porter

import (
"bytes"
"fmt"
"github.com/deislabs/porter/pkg"
"github.com/deislabs/porter/pkg/context"
"github.com/deislabs/porter/pkg/mixin"
"github.com/deislabs/porter/pkg/porter/version"
"github.com/deislabs/porter/pkg/printer"
"github.com/pkg/errors"
"runtime"
"text/template"
)

func (p *Porter) PrintVersion(opts version.Options) error {
type VersionOpts struct {
version.Options
System bool
}

type SystemInfo struct {
OS string
Arch string
}

type Mixins []mixin.Metadata

type SystemDebugInfo struct {
Version mixin.Metadata `json:"version"`
SysInfo SystemInfo `json:"system"`
Mixins Mixins `json:"mixins"`
}

func (mixins Mixins) PrintMixinsTable() string {
buffer := &bytes.Buffer{}
printMixinRow :=
func(v interface{}) []interface{} {
m, ok := v.(mixin.Metadata)
if !ok {
return nil
}
return []interface{}{m.Name, m.VersionInfo.Version, m.VersionInfo.Author}
}
err := printer.PrintTable(buffer, mixins, printMixinRow, "Name", "Version", "Author")
if err != nil {
return ""
}
return buffer.String()
}

func (p *Porter) PrintVersion(opts VersionOpts) error {
metadata := mixin.Metadata{
Name: "porter",
VersionInfo: mixin.VersionInfo{
Version: pkg.Version,
Commit: pkg.Commit,
},
}
return version.PrintVersion(p.Context, opts, metadata)

if opts.System {
return p.PrintDebugInfo(p.Context, opts, metadata)
}

return version.PrintVersion(p.Context, opts.Options, metadata)
}

func getSystemInfo() *SystemInfo {
return &SystemInfo{
OS: runtime.GOOS,
Arch: runtime.GOARCH,
}
}

func (p *Porter) PrintDebugInfo(ctx *context.Context, opts VersionOpts, versionMetadata mixin.Metadata) error {
opts.RawFormat = string(printer.FormatPlaintext)
sysInfo := getSystemInfo()
mixins, err := p.ListMixins()
if err != nil {
if p.Debug {
fmt.Fprint(p.Err, err.Error())
}
return nil
}

sysDebugInfo := SystemDebugInfo{
Version: versionMetadata,
SysInfo: *sysInfo,
Mixins: mixins,
}

switch opts.Format {
case printer.FormatJson:
return printer.PrintJson(ctx.Out, sysDebugInfo)
case printer.FormatPlaintext:
plaintextTmpl := `{{.Version.Name}} {{.Version.VersionInfo.Version}} ({{.Version.VersionInfo.Commit}})

System
-------
os: {{.SysInfo.OS}}
arch: {{.SysInfo.Arch}}
{{if .Mixins}}
Mixins
-------
{{.Mixins.PrintMixinsTable}}{{end}}
`
tmpl, err := template.New("systemDebugInfo").Parse(plaintextTmpl)
if err != nil {
return errors.Wrap(err, "Failed to parse plaintext template")
}
err = tmpl.Execute(ctx.Out, sysDebugInfo)
return err
default:
return fmt.Errorf("unsupported format: %s", opts.Format)
}
}
67 changes: 64 additions & 3 deletions pkg/porter/version_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package porter

import (
"fmt"
"github.com/stretchr/testify/assert"
"runtime"
"strings"
"testing"

"github.com/deislabs/porter/pkg"
"github.com/deislabs/porter/pkg/porter/version"
"github.com/deislabs/porter/pkg/printer"
"github.com/stretchr/testify/require"
)
Expand All @@ -16,7 +18,7 @@ func TestPrintVersion(t *testing.T) {

p := NewTestPorter(t)

opts := version.Options{}
opts := VersionOpts{}
err := opts.Validate()
require.NoError(t, err)
p.PrintVersion(opts)
Expand All @@ -34,7 +36,7 @@ func TestPrintJsonVersion(t *testing.T) {

p := NewTestPorter(t)

opts := version.Options{}
opts := VersionOpts{}
opts.RawFormat = string(printer.FormatJson)
err := opts.Validate()
require.NoError(t, err)
Expand All @@ -51,3 +53,62 @@ func TestPrintJsonVersion(t *testing.T) {
t.Fatalf("invalid output:\nWANT:\t%q\nGOT:\t%q\n", wantOutput, gotOutput)
}
}

func TestPrintDebugInfoJsonVersion(t *testing.T) {
pkg.Commit = "abc123"
pkg.Version = "v1.2.3"

p := NewTestPorter(t)

opts := VersionOpts{System: true}
p.TestConfig.SetupPorterHome()
opts.RawFormat = string(printer.FormatJson)
err := opts.Validate()
require.Nil(t, err)
p.PrintVersion(opts)

gotOutput := p.TestConfig.TestContext.GetOutput()
wantOutput := fmt.Sprintf(`{
"version": {
"name": "porter",
"version": "v1.2.3",
"commit": "abc123"
},
"system": {
"OS": "%s",
"Arch": "%s"
},
"mixins": [
{
"name": "exec",
"version": "v1.0",
"commit": "abc123",
"author": "Deis Labs"
}
]
}
`, runtime.GOOS, runtime.GOARCH)
assert.Equal(t, wantOutput, gotOutput)
}

func TestPrintDebugInfoPlainTextVersion(t *testing.T) {
pkg.Commit = "abc123"
pkg.Version = "v1.2.3"

p := NewTestPorter(t)

opts := VersionOpts{System: true}
p.TestConfig.SetupPorterHome()
err := opts.Validate()
require.Nil(t, err)
p.PrintVersion(opts)

versionOutput := "porter v1.2.3 (abc123)"
mixinsOutput := "exec v1.0 Deis Labs"
systemOutput := fmt.Sprintf("os: %s\narch: %s", runtime.GOOS, runtime.GOARCH)

gotOutput := p.TestConfig.TestContext.GetOutput()
assert.Contains(t, gotOutput, versionOutput)
assert.Contains(t, gotOutput, mixinsOutput)
assert.Contains(t, gotOutput, systemOutput)
}