Add Revision to version CLI output and add JSON support
Also add JSON format support
This commit is contained in:
parent
d7e3156972
commit
ca169ef6ed
|
@ -220,6 +220,6 @@ func init() {
|
||||||
Register("tls cert", func(ui cli.Ui) (cli.Command, error) { return tlscert.New(), nil })
|
Register("tls cert", func(ui cli.Ui) (cli.Command, error) { return tlscert.New(), nil })
|
||||||
Register("tls cert create", func(ui cli.Ui) (cli.Command, error) { return tlscertcreate.New(ui), nil })
|
Register("tls cert create", func(ui cli.Ui) (cli.Command, error) { return tlscertcreate.New(ui), nil })
|
||||||
Register("validate", func(ui cli.Ui) (cli.Command, error) { return validate.New(ui), nil })
|
Register("validate", func(ui cli.Ui) (cli.Command, error) { return validate.New(ui), nil })
|
||||||
Register("version", func(ui cli.Ui) (cli.Command, error) { return version.New(ui, verHuman), nil })
|
Register("version", func(ui cli.Ui) (cli.Command, error) { return version.New(ui), nil })
|
||||||
Register("watch", func(ui cli.Ui) (cli.Command, error) { return watch.New(ui, MakeShutdownCh()), nil })
|
Register("watch", func(ui cli.Ui) (cli.Command, error) { return watch.New(ui, MakeShutdownCh()), nil })
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
package version
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
PrettyFormat string = "pretty"
|
||||||
|
JSONFormat string = "json"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Formatter interface {
|
||||||
|
Format(info *VersionInfo) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSupportedFormats() []string {
|
||||||
|
return []string{PrettyFormat, JSONFormat}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFormatter(format string) (Formatter, error) {
|
||||||
|
switch format {
|
||||||
|
case PrettyFormat:
|
||||||
|
return newPrettyFormatter(), nil
|
||||||
|
case JSONFormat:
|
||||||
|
return newJSONFormatter(), nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("Unknown format: %s", format)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type prettyFormatter struct{}
|
||||||
|
|
||||||
|
func newPrettyFormatter() Formatter {
|
||||||
|
return &prettyFormatter{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_ *prettyFormatter) Format(info *VersionInfo) (string, error) {
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
buffer.WriteString(fmt.Sprintf("Consul %s\n", info.HumanVersion))
|
||||||
|
if info.Revision != "" {
|
||||||
|
buffer.WriteString(fmt.Sprintf("Revision %s\n", info.Revision))
|
||||||
|
}
|
||||||
|
|
||||||
|
var supplement string
|
||||||
|
if info.RPC.Default < info.RPC.Max {
|
||||||
|
supplement = fmt.Sprintf(" (agent will automatically use protocol >%d when speaking to compatible agents)",
|
||||||
|
info.RPC.Default)
|
||||||
|
}
|
||||||
|
buffer.WriteString(fmt.Sprintf("Protocol %d spoken by default, understands %d to %d%s\n",
|
||||||
|
info.RPC.Default, info.RPC.Min, info.RPC.Max, supplement))
|
||||||
|
|
||||||
|
return buffer.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type jsonFormatter struct{}
|
||||||
|
|
||||||
|
func newJSONFormatter() Formatter {
|
||||||
|
return &jsonFormatter{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_ *jsonFormatter) Format(info *VersionInfo) (string, error) {
|
||||||
|
b, err := json.MarshalIndent(info, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("Failed to marshal version info: %v", err)
|
||||||
|
}
|
||||||
|
return string(b), nil
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
package version
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
// update allows golden files to be updated based on the current output.
|
||||||
|
var update = flag.Bool("update", false, "update golden files")
|
||||||
|
|
||||||
|
// golden reads and optionally writes the expected data to the golden file,
|
||||||
|
// returning the contents as a string.
|
||||||
|
func golden(t *testing.T, name, got string) string {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
golden := filepath.Join("testdata", name+".golden")
|
||||||
|
if *update && got != "" {
|
||||||
|
err := ioutil.WriteFile(golden, []byte(got), 0644)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected, err := ioutil.ReadFile(golden)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
return string(expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFormat(t *testing.T) {
|
||||||
|
info := VersionInfo{
|
||||||
|
HumanVersion: "1.99.3-beta1",
|
||||||
|
Version: "1.99.3",
|
||||||
|
Prerelease: "beta1",
|
||||||
|
Revision: "5e5dbedd47a5f875b60e241c5555a9caab595246",
|
||||||
|
RPC: RPCVersionInfo{
|
||||||
|
Default: 2,
|
||||||
|
Min: 1,
|
||||||
|
Max: 3,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
formatters := map[string]Formatter{
|
||||||
|
"pretty": newPrettyFormatter(),
|
||||||
|
// the JSON formatter ignores the showMeta
|
||||||
|
"json": newJSONFormatter(),
|
||||||
|
}
|
||||||
|
|
||||||
|
for fmtName, formatter := range formatters {
|
||||||
|
t.Run(fmtName, func(t *testing.T) {
|
||||||
|
actual, err := formatter.Format(&info)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
gName := fmt.Sprintf("%s", fmtName)
|
||||||
|
|
||||||
|
expected := golden(t, gName, actual)
|
||||||
|
require.Equal(t, expected, actual)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"Version": "1.99.3",
|
||||||
|
"Revision": "5e5dbedd47a5f875b60e241c5555a9caab595246",
|
||||||
|
"Prerelease": "beta1",
|
||||||
|
"RPC": {
|
||||||
|
"Default": 2,
|
||||||
|
"Min": 1,
|
||||||
|
"Max": 3
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
Consul 1.99.3-beta1
|
||||||
|
Revision 5e5dbedd47a5f875b60e241c5555a9caab595246
|
||||||
|
Protocol 2 spoken by default, understands 1 to 3 (agent will automatically use protocol >2 when speaking to compatible agents)
|
|
@ -1,34 +1,80 @@
|
||||||
package version
|
package version
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/consul/agent/consul"
|
"github.com/hashicorp/consul/agent/consul"
|
||||||
|
"github.com/hashicorp/consul/command/flags"
|
||||||
|
"github.com/hashicorp/consul/version"
|
||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
func New(ui cli.Ui, version string) *cmd {
|
func New(ui cli.Ui) *cmd {
|
||||||
return &cmd{UI: ui, version: version}
|
c := &cmd{UI: ui}
|
||||||
|
c.init()
|
||||||
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
type cmd struct {
|
type cmd struct {
|
||||||
UI cli.Ui
|
UI cli.Ui
|
||||||
version string
|
flags *flag.FlagSet
|
||||||
|
format string
|
||||||
|
help string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cmd) Run(_ []string) int {
|
func (c *cmd) init() {
|
||||||
c.UI.Output(fmt.Sprintf("Consul %s", c.version))
|
c.flags = flag.NewFlagSet("", flag.ContinueOnError)
|
||||||
|
c.flags.StringVar(
|
||||||
|
&c.format,
|
||||||
|
"format",
|
||||||
|
PrettyFormat,
|
||||||
|
fmt.Sprintf("Output format {%s}", strings.Join(GetSupportedFormats(), "|")))
|
||||||
|
c.help = flags.Usage(help, c.flags)
|
||||||
|
|
||||||
const rpcProtocol = consul.DefaultRPCProtocol
|
}
|
||||||
|
|
||||||
var supplement string
|
type RPCVersionInfo struct {
|
||||||
if rpcProtocol < consul.ProtocolVersionMax {
|
Default int
|
||||||
supplement = fmt.Sprintf(" (agent will automatically use protocol >%d when speaking to compatible agents)",
|
Min int
|
||||||
rpcProtocol)
|
Max int
|
||||||
|
}
|
||||||
|
|
||||||
|
type VersionInfo struct {
|
||||||
|
HumanVersion string `json:"-"`
|
||||||
|
Version string
|
||||||
|
Revision string
|
||||||
|
Prerelease string
|
||||||
|
RPC RPCVersionInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cmd) Run(args []string) int {
|
||||||
|
if err := c.flags.Parse(args); err != nil {
|
||||||
|
return 1
|
||||||
}
|
}
|
||||||
c.UI.Output(fmt.Sprintf("Protocol %d spoken by default, understands %d to %d%s",
|
|
||||||
rpcProtocol, consul.ProtocolVersionMin, consul.ProtocolVersionMax, supplement))
|
|
||||||
|
|
||||||
|
formatter, err := NewFormatter(c.format)
|
||||||
|
if err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
out, err := formatter.Format(&VersionInfo{
|
||||||
|
HumanVersion: version.GetHumanVersion(),
|
||||||
|
Version: version.Version,
|
||||||
|
Revision: version.GitCommit,
|
||||||
|
Prerelease: version.VersionPrerelease,
|
||||||
|
RPC: RPCVersionInfo{
|
||||||
|
Default: consul.DefaultRPCProtocol,
|
||||||
|
Min: int(consul.ProtocolVersionMin),
|
||||||
|
Max: consul.ProtocolVersionMax,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
c.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
c.UI.Output(out)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,5 +83,10 @@ func (c *cmd) Synopsis() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cmd) Help() string {
|
func (c *cmd) Help() string {
|
||||||
return ""
|
return flags.Usage(c.help, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const synopsis = "Output Consul version information"
|
||||||
|
const help = `
|
||||||
|
Usage: consul version [options]
|
||||||
|
`
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
|
|
||||||
func TestVersionCommand_noTabs(t *testing.T) {
|
func TestVersionCommand_noTabs(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
if strings.ContainsRune(New(cli.NewMockUi(), "").Help(), '\t') {
|
if strings.ContainsRune(New(cli.NewMockUi()).Help(), '\t') {
|
||||||
t.Fatal("help has tabs")
|
t.Fatal("help has tabs")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
3
main.go
3
main.go
|
@ -10,7 +10,6 @@ import (
|
||||||
"github.com/hashicorp/consul/command/version"
|
"github.com/hashicorp/consul/command/version"
|
||||||
"github.com/hashicorp/consul/lib"
|
"github.com/hashicorp/consul/lib"
|
||||||
_ "github.com/hashicorp/consul/service_os"
|
_ "github.com/hashicorp/consul/service_os"
|
||||||
consulversion "github.com/hashicorp/consul/version"
|
|
||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -43,7 +42,7 @@ func realMain() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
if cli.IsVersion() {
|
if cli.IsVersion() {
|
||||||
cmd := version.New(ui, consulversion.GetHumanVersion())
|
cmd := version.New(ui)
|
||||||
return cmd.Run(nil)
|
return cmd.Run(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,33 @@ Command: `consul version`
|
||||||
|
|
||||||
The `version` command prints the version of Consul and the protocol versions it understands for speaking to other agents.
|
The `version` command prints the version of Consul and the protocol versions it understands for speaking to other agents.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Usage: `consul version [options]`
|
||||||
|
|
||||||
|
### Command Options
|
||||||
|
|
||||||
|
- `-format={pretty|json}` - Command output format. The default value is `pretty`.
|
||||||
|
|
||||||
|
## Plain Output
|
||||||
```shell-session
|
```shell-session
|
||||||
$ consul version
|
$ consul version
|
||||||
Consul v0.7.4
|
Consul v1.7.0
|
||||||
|
Revision d1fc59061
|
||||||
Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use protocol >2 when speaking to compatible agents)
|
Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use protocol >2 when speaking to compatible agents)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## JSON Output
|
||||||
|
```shell-session
|
||||||
|
$ consul version -format=json
|
||||||
|
{
|
||||||
|
"Version": "1.8.0",
|
||||||
|
"Revision": "d1fc59061",
|
||||||
|
"Prerelease": "dev",
|
||||||
|
"RPC": {
|
||||||
|
"Default": 2,
|
||||||
|
"Min": 2,
|
||||||
|
"Max": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
Loading…
Reference in New Issue