Skip to content

Commit

Permalink
Improve juju version help text
Browse files Browse the repository at this point in the history
  • Loading branch information
wallyworld committed Jul 30, 2020
1 parent f9ee871 commit 92e829f
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 67 deletions.
1 change: 1 addition & 0 deletions cmd/juju/commands/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ type commandRegistry interface {

// registerCommands registers commands in the specified registry.
func registerCommands(r commandRegistry, ctx *cmd.Context) {
r.Register(newVersionCommand())
// Creation commands.
r.Register(newBootstrapCommand())
r.Register(application.NewAddRelationCommand())
Expand Down
2 changes: 1 addition & 1 deletion cmd/juju/commands/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -793,7 +793,7 @@ func (s *MainSuite) TestRegisterCommands(c *gc.C) {
}

registry := &stubRegistry{stub: stub}
registry.names = append(registry.names, "help", "version") // implicit
registry.names = append(registry.names, "help") // implicit
registerCommands(registry, cmdtesting.Context(c))
sort.Strings(registry.names)

Expand Down
101 changes: 101 additions & 0 deletions cmd/juju/commands/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package commands

import (
"github.com/juju/cmd"
"github.com/juju/gnuflag"
"github.com/juju/os/series"
"github.com/juju/utils/arch"
"github.com/juju/version"

jujuversion "github.com/juju/juju/version"
)

const versionDoc = `
Print only the Juju CLI client version.
To see the version of Juju running on a particular controller, use
juju show-controller
To see the version of Juju running on a particular model, use
juju show-model
See also:
show-controller
show-model`

// versionDetail is populated with version information from juju/juju/cmd
// and passed into each SuperCommand. It can be printed using `juju version --all`.
type versionDetail struct {
// Version of the current binary.
Version version.Binary `json:"version" yaml:"version"`
// GitCommit of tree used to build the binary.
GitCommit string `json:"git-commit,omitempty" yaml:"git-commit,omitempty"`
// GitTreeState is "clean" if the working copy used to build the binary had no
// uncommitted changes or untracked files, otherwise "dirty".
GitTreeState string `json:"git-tree-state,omitempty" yaml:"git-tree-state,omitempty"`
// Compiler reported by runtime.Compiler
Compiler string `json:"compiler" yaml:"compiler"`
// OfficialBuild is a monotonic integer set by Jenkins.
OfficialBuild int `json:"official-build,omitempty" yaml:"official-build,omitempty"`
}

// versionCommand is a cmd.Command that prints the current version.
type versionCommand struct {
cmd.CommandBase
out cmd.Output
version version.Binary
versionDetail interface{}

showAll bool
}

func newVersionCommand() *versionCommand {
return &versionCommand{}
}

func (v *versionCommand) Info() *cmd.Info {
return &cmd.Info{
Name: "version",
Purpose: "Print the Juju CLI client version.",
Doc: versionDoc,
}
}

func (v *versionCommand) SetFlags(f *gnuflag.FlagSet) {
formatters := make(map[string]cmd.Formatter, len(cmd.DefaultFormatters))
for k, v := range cmd.DefaultFormatters {
formatters[k] = v.Formatter
}
v.out.AddFlags(f, "smart", formatters)
f.BoolVar(&v.showAll, "all", false, "Prints all version information")
}

func (v *versionCommand) Init(args []string) error {
current := version.Binary{
Number: jujuversion.Current,
Arch: arch.HostArch(),
Series: series.MustHostSeries(),
}
detail := versionDetail{
Version: current,
GitCommit: jujuversion.GitCommit,
GitTreeState: jujuversion.GitTreeState,
Compiler: jujuversion.Compiler,
OfficialBuild: jujuversion.OfficialBuild,
}

v.version = detail.Version
v.versionDetail = detail

return v.CommandBase.Init(args)
}

func (v *versionCommand) Run(ctxt *cmd.Context) error {
if v.showAll {
return v.out.Write(ctxt, v.versionDetail)
}
return v.out.Write(ctxt, v.version)
}
44 changes: 15 additions & 29 deletions cmd/supercommand_test.go → cmd/juju/commands/version_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
// Copyright 2019 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package cmd_test
package commands

import (
"bytes"
"fmt"

"github.com/juju/cmd"
"github.com/juju/cmd/cmdtesting"
"github.com/juju/os/series"
"github.com/juju/testing"
Expand All @@ -16,23 +15,19 @@ import (
"github.com/juju/version"
gc "gopkg.in/check.v1"

jujucmd "github.com/juju/juju/cmd"
jujuversion "github.com/juju/juju/version"
)

type SuperCommandSuite struct {
type VersionSuite struct {
testing.IsolationSuite
}

var _ = gc.Suite(&SuperCommandSuite{})
var _ = gc.Suite(&VersionSuite{})

func (s *SuperCommandSuite) TestVersion(c *gc.C) {
func (s *VersionSuite) TestVersion(c *gc.C) {
s.PatchValue(&jujuversion.Current, version.MustParse("2.99.0"))
params := cmd.SuperCommandParams{
Name: "juju-test-command",
}
command := jujucmd.NewSuperCommand(params)
cctx, err := cmdtesting.RunCommand(c, command, "version")
command := newVersionCommand()
cctx, err := cmdtesting.RunCommand(c, command)
c.Assert(err, jc.ErrorIsNil)
output := fmt.Sprintf("2.99.0-%s-%s\n",
series.MustHostSeries(), arch.HostArch())
Expand All @@ -41,16 +36,13 @@ func (s *SuperCommandSuite) TestVersion(c *gc.C) {
c.Assert(cctx.Stderr.(*bytes.Buffer).String(), gc.Equals, "")
}

func (s *SuperCommandSuite) TestVersionDetail(c *gc.C) {
func (s *VersionSuite) TestVersionDetail(c *gc.C) {
s.PatchValue(&jujuversion.Current, version.MustParse("2.99.0"))
s.PatchValue(&jujuversion.GitCommit, "0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f")
s.PatchValue(&jujuversion.GitTreeState, "clean")
s.PatchValue(&jujuversion.Compiler, "gc")
params := cmd.SuperCommandParams{
Name: "juju-test-command",
}
command := jujucmd.NewSuperCommand(params)
cctx, err := cmdtesting.RunCommand(c, command, "version", "--all")
command := newVersionCommand()
cctx, err := cmdtesting.RunCommand(c, command, "--all")
c.Assert(err, jc.ErrorIsNil)
outputTemplate := `
version: 2.99.0-%s-%s
Expand All @@ -64,16 +56,13 @@ compiler: gc
c.Assert(cctx.Stderr.(*bytes.Buffer).String(), gc.Equals, "")
}

func (s *SuperCommandSuite) TestVersionDetailJSON(c *gc.C) {
func (s *VersionSuite) TestVersionDetailJSON(c *gc.C) {
s.PatchValue(&jujuversion.Current, version.MustParse("2.99.0"))
s.PatchValue(&jujuversion.GitCommit, "0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f")
s.PatchValue(&jujuversion.GitTreeState, "clean")
s.PatchValue(&jujuversion.Compiler, "gc")
params := cmd.SuperCommandParams{
Name: "juju-test-command",
}
command := jujucmd.NewSuperCommand(params)
cctx, err := cmdtesting.RunCommand(c, command, "version", "--all", "--format", "json")
command := newVersionCommand()
cctx, err := cmdtesting.RunCommand(c, command, "--all", "--format", "json")
c.Assert(err, jc.ErrorIsNil)
outputTemplate := `
{"version":"2.99.0-%s-%s","git-commit":"0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f","git-tree-state":"clean","compiler":"gc"}
Expand All @@ -84,16 +73,13 @@ func (s *SuperCommandSuite) TestVersionDetailJSON(c *gc.C) {
c.Assert(cctx.Stderr.(*bytes.Buffer).String(), gc.Equals, "")
}

func (s *SuperCommandSuite) TestVersionDetailYAML(c *gc.C) {
func (s *VersionSuite) TestVersionDetailYAML(c *gc.C) {
s.PatchValue(&jujuversion.Current, version.MustParse("2.99.0"))
s.PatchValue(&jujuversion.GitCommit, "0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f")
s.PatchValue(&jujuversion.GitTreeState, "clean")
s.PatchValue(&jujuversion.Compiler, "gc")
params := cmd.SuperCommandParams{
Name: "juju-test-command",
}
command := jujucmd.NewSuperCommand(params)
cctx, err := cmdtesting.RunCommand(c, command, "version", "--all", "--format", "yaml")
command := newVersionCommand()
cctx, err := cmdtesting.RunCommand(c, command, "--all", "--format", "yaml")
c.Assert(err, jc.ErrorIsNil)
outputTemplate := `
version: 2.99.0-%s-%s
Expand Down
38 changes: 38 additions & 0 deletions cmd/jujud/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ import (
"github.com/juju/errors"
"github.com/juju/loggo"
"github.com/juju/names/v4"
"github.com/juju/os/series"
proxyutils "github.com/juju/proxy"
"github.com/juju/utils/arch"
"github.com/juju/utils/exec"
"github.com/juju/version"

jujucmd "github.com/juju/juju/cmd"
agentcmd "github.com/juju/juju/cmd/jujud/agent"
Expand All @@ -34,6 +37,7 @@ import (
"github.com/juju/juju/core/machinelock"
jujunames "github.com/juju/juju/juju/names"
"github.com/juju/juju/juju/sockets"
jujuversion "github.com/juju/juju/version"

k8sexec "github.com/juju/juju/caas/kubernetes/provider/exec"

Expand Down Expand Up @@ -190,6 +194,22 @@ func hookToolMain(commandName string, ctx *cmd.Context, args []string) (code int
return resp.Code, nil
}

// versionDetail is populated with version information from juju/juju/cmd
// and passed into each SuperCommand. It can be printed using `juju version --all`.
type versionDetail struct {
// Version of the current binary.
Version string `json:"version" yaml:"version"`
// GitCommit of tree used to build the binary.
GitCommit string `json:"git-commit,omitempty" yaml:"git-commit,omitempty"`
// GitTreeState is "clean" if the working copy used to build the binary had no
// uncommitted changes or untracked files, otherwise "dirty".
GitTreeState string `json:"git-tree-state,omitempty" yaml:"git-tree-state,omitempty"`
// Compiler reported by runtime.Compiler
Compiler string `json:"compiler" yaml:"compiler"`
// OfficialBuild is a monotonic integer set by Jenkins.
OfficialBuild int `json:"official-build,omitempty" yaml:"official-build,omitempty"`
}

// Main registers subcommands for the jujud executable, and hands over control
// to the cmd package.
func jujuDMain(args []string, ctx *cmd.Context) (code int, err error) {
Expand All @@ -210,9 +230,27 @@ func jujuDMain(args []string, ctx *cmd.Context) (code int, err error) {
return 1, errors.Trace(err)
}

current := version.Binary{
Number: jujuversion.Current,
Arch: arch.HostArch(),
Series: series.MustHostSeries(),
}
detail := versionDetail{
Version: current.String(),
GitCommit: jujuversion.GitCommit,
GitTreeState: jujuversion.GitTreeState,
Compiler: jujuversion.Compiler,
OfficialBuild: jujuversion.OfficialBuild,
}

jujud := jujucmd.NewSuperCommand(cmd.SuperCommandParams{
Name: "jujud",
Doc: jujudDoc,
// p.Version should be a version.Binary, but juju/cmd does not
// import juju/juju/version so this cannot happen. We have
// tests to assert that this string value is correct.
Version: detail.Version,
VersionDetail: detail,
})

jujud.Log.NewWriter = func(target io.Writer) loggo.Writer {
Expand Down
37 changes: 0 additions & 37 deletions cmd/supercommand.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ import (

"github.com/juju/cmd"
"github.com/juju/loggo"
"github.com/juju/os/series"
"github.com/juju/utils/arch"
"github.com/juju/version"
"golang.org/x/crypto/ssh/terminal"

"github.com/juju/juju/juju/osenv"
Expand All @@ -30,22 +27,6 @@ func init() {

var logger = loggo.GetLogger("juju.cmd")

// versionDetail is populated with version information from juju/juju/cmd
// and passed into each SuperCommand. It can be printed using `juju version --all`.
type versionDetail struct {
// Version of the current binary.
Version string `json:"version" yaml:"version"`
// GitCommit of tree used to build the binary.
GitCommit string `json:"git-commit,omitempty" yaml:"git-commit,omitempty"`
// GitTreeState is "clean" if the working copy used to build the binary had no
// uncommitted changes or untracked files, otherwise "dirty".
GitTreeState string `json:"git-tree-state,omitempty" yaml:"git-tree-state,omitempty"`
// Compiler reported by runtime.Compiler
Compiler string `json:"compiler" yaml:"compiler"`
// OfficialBuild is a monotonic integer set by Jenkins.
OfficialBuild int `json:"official-build,omitempty" yaml:"official-build,omitempty"`
}

// NewSuperCommand is like cmd.NewSuperCommand but
// it adds juju-specific functionality:
// - The default logging configuration is taken from the environment;
Expand All @@ -56,24 +37,6 @@ func NewSuperCommand(p cmd.SuperCommandParams) *cmd.SuperCommand {
p.Log = &cmd.Log{
DefaultConfig: os.Getenv(osenv.JujuLoggingConfigEnvKey),
}
current := version.Binary{
Number: jujuversion.Current,
Arch: arch.HostArch(),
Series: series.MustHostSeries(),
}
detail := versionDetail{
Version: current.String(),
GitCommit: jujuversion.GitCommit,
GitTreeState: jujuversion.GitTreeState,
Compiler: jujuversion.Compiler,
OfficialBuild: jujuversion.OfficialBuild,
}

// p.Version should be a version.Binary, but juju/cmd does not
// import juju/juju/version so this cannot happen. We have
// tests to assert that this string value is correct.
p.Version = detail.Version
p.VersionDetail = detail
if p.NotifyRun != nil {
messenger := p.NotifyRun
p.NotifyRun = func(str string) {
Expand Down

0 comments on commit 92e829f

Please sign in to comment.