From ddd5dbcc1d9adfe7cbc1908e0c0262600b9e3845 Mon Sep 17 00:00:00 2001 From: Evan Culver Date: Tue, 2 May 2017 15:02:38 -0700 Subject: [PATCH] Build meta (#140) --- Makefile | 12 +++++++++--- VERSION.txt | 1 + cmd/dosa/main.go | 43 +++++++++++++++++++++++++++++++++++++++++-- cmd/dosa/main_test.go | 26 ++++++++++++++++++++++++-- mocks/client.go | 1 + mocks/connector.go | 1 + mocks/doc.go | 36 ++++++++++++++++++++++++++++++++++++ 7 files changed, 113 insertions(+), 7 deletions(-) create mode 100644 VERSION.txt create mode 100644 mocks/doc.go diff --git a/Makefile b/Makefile index aef7d398..e61a8a73 100644 --- a/Makefile +++ b/Makefile @@ -92,14 +92,19 @@ fmt: $(GOIMPORTS) -w $(ALL_SRC) ; \ fi +CLI_BUILD_VERSION=$(shell cat VERSION.txt) +CLI_BUILD_TIMESTAMP=$(shell date -u '+%Y-%m-%d_%I:%M:%S%p') +CLI_BUILD_REF=$(shell git rev-parse --short HEAD) +CLI_LINKER_FLAGS="-X main.version=$(CLI_BUILD_VERSION) -X main.timestamp=$(CLI_BUILD_TIMESTAMP) -X main.githash=$(CLI_BUILD_REF)" + .PHONY: cli cli: - $(ECHO_V)go install ./cmd/dosa + $(ECHO_V)go build -ldflags $(CLI_LINKER_FLAGS) -o $$GOPATH/bin/dosa ./cmd/dosa ifdef target ifeq ($(target), Darwin) - $(ECHO_V)GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -o ./out/cli/darwin/dosa ./cmd/dosa + $(ECHO_V)GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -ldflags $(CLI_LINKER_FLAGS) -o ./out/cli/darwin/dosa ./cmd/dosa else ifeq ($(target), Linux) - $(ECHO_V)GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o ./out/cli/linux/dosa ./cmd/dosa + $(ECHO_V)GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags $(CLI_LINKER_FLAGS) -o ./out/cli/linux/dosa ./cmd/dosa endif endif @@ -111,3 +116,4 @@ mocks/connector.go: .PHONY: mocks mocks: mocks/client.go mocks/connector.go + python ./script/license-headers.py -t LICENSE.txt -d mocks diff --git a/VERSION.txt b/VERSION.txt new file mode 100644 index 00000000..1ee76d11 --- /dev/null +++ b/VERSION.txt @@ -0,0 +1 @@ +v2.0.0-rc1 diff --git a/cmd/dosa/main.go b/cmd/dosa/main.go index 46f640fd..4196addc 100644 --- a/cmd/dosa/main.go +++ b/cmd/dosa/main.go @@ -33,6 +33,31 @@ type exiter func(int) var exit = os.Exit +// these are overridden at build-time w/ the -ldflags -X option +var ( + version = "0.0.0" + githash = "master" + timestamp = "now" +) + +// BuildInfo reports information about the binary build environment +type BuildInfo struct { + Version string + Githash string + Timestamp string +} + +// String satisfies Stringer interface +func (b BuildInfo) String() string { + return fmt.Sprintf("Version:\t%s\nGit Commit:\t%s\nUTC Build Time:\t%s", version, githash, timestamp) +} + +// Execute is ran for the version subcommand +func (b BuildInfo) Execute(args []string) error { + fmt.Printf("%s\n", b) + return nil +} + // GlobalOptions are options for all subcommands type GlobalOptions struct { Host string `long:"host" default:"127.0.0.1" description:"The hostname or IP for the gateway."` @@ -42,18 +67,25 @@ type GlobalOptions struct { CallerName string `long:"caller" default:"dosacli-$USER" description:"Caller will override the default caller name (which is dosacli-$USER)."` Timeout timeFlag `long:"timeout" default:"60s" description:"The timeout for gateway requests. E.g., 100ms, 0.5s, 1s. If no unit is specified, milliseconds are assumed."` Connector string `hidden:"true" long:"connector" default:"yarpc" description:"Name of connector to use"` + Version bool `long:"version" description:"Display version info"` } -var options GlobalOptions +var ( + options GlobalOptions + buildInfo BuildInfo +) // OptionsParser holds the global parser func main() { + buildInfo := &BuildInfo{} OptionsParser := flags.NewParser(&options, flags.PassAfterNonOption|flags.HelpFlag) OptionsParser.ShortDescription = "DOSA CLI - The command-line tool for your DOSA client" OptionsParser.LongDescription = ` dosa manages your schema both in production and development scopes` - c, _ := OptionsParser.AddCommand("scope", "commands to manage scope", "create, drop, or truncate development scopes", &ScopeOptions{}) + c, _ := OptionsParser.AddCommand("version", "display build info", "display build info", &BuildInfo{}) + + c, _ = OptionsParser.AddCommand("scope", "commands to manage scope", "create, drop, or truncate development scopes", &ScopeOptions{}) _, _ = c.AddCommand("create", "Create scope", "creates a new scope", &ScopeCreate{}) _, _ = c.AddCommand("drop", "Drop scope", "drops a scope", &ScopeDrop{}) _, _ = c.AddCommand("truncate", "Truncate scope", "truncates a scope", &ScopeTruncate{}) @@ -65,6 +97,13 @@ dosa manages your schema both in production and development scopes` _, _ = c.AddCommand("status", "Check schema status", "Check application status of schema", &SchemaStatus{}) _, err := OptionsParser.Parse() + + if options.Version { + fmt.Fprintf(os.Stdout, "%s\n", buildInfo.String()) + options.Version = false // for tests, we leak state between runs + exit(0) + } + if err != nil { fmt.Fprintf(os.Stderr, "Error: %s\n", err) exit(1) diff --git a/cmd/dosa/main_test.go b/cmd/dosa/main_test.go index a5bee7bd..61b02d7f 100644 --- a/cmd/dosa/main_test.go +++ b/cmd/dosa/main_test.go @@ -34,7 +34,7 @@ func TestNoSubcommand(t *testing.T) { } os.Args = []string{"dosa"} main() - assert.Contains(t, c.stop(true), "schema or scope") + assert.Contains(t, c.stop(true), "schema, scope or version") } func TestMissingSubcommands(t *testing.T) { @@ -50,7 +50,7 @@ func TestHostOptionButNothingElse(t *testing.T) { exit = func(r int) {} os.Args = []string{"dosa", "--host", "10.10.10.10"} main() - assert.Contains(t, c.stop(true), "schema or scope") + assert.Contains(t, c.stop(true), "schema, scope or version") } // this test uses a trailing dot in the hostname to avoid multiple DNS lookups @@ -86,6 +86,28 @@ func TestInvalidTransport(t *testing.T) { assert.Contains(t, output, "invalid transport") } +func TestVersionFlag(t *testing.T) { + c := StartCapture() + exit = func(r int) {} + os.Args = []string{"dosa", "--version"} + main() + output := c.stop(false) + assert.Contains(t, output, "Version:") + assert.Contains(t, output, "Git Commit:") + assert.Contains(t, output, "UTC Build Time:") +} + +func TestVersionCommand(t *testing.T) { + c := StartCapture() + exit = func(r int) {} + os.Args = []string{"dosa", "version"} + main() + output := c.stop(false) + assert.Contains(t, output, "Version:") + assert.Contains(t, output, "Git Commit:") + assert.Contains(t, output, "UTC Build Time:") +} + /* TODO: implement these integration test cases // expect: top-level usage, transport=tchannel diff --git a/mocks/client.go b/mocks/client.go index 0109e6d2..1c8abbb2 100644 --- a/mocks/client.go +++ b/mocks/client.go @@ -25,6 +25,7 @@ package mocks import ( context "context" + gomock "github.com/golang/mock/gomock" dosa "github.com/uber-go/dosa" ) diff --git a/mocks/connector.go b/mocks/connector.go index bcb10319..4ccf49d6 100644 --- a/mocks/connector.go +++ b/mocks/connector.go @@ -25,6 +25,7 @@ package mocks import ( context "context" + gomock "github.com/golang/mock/gomock" dosa "github.com/uber-go/dosa" ) diff --git a/mocks/doc.go b/mocks/doc.go new file mode 100644 index 00000000..114fdfa0 --- /dev/null +++ b/mocks/doc.go @@ -0,0 +1,36 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// Package mocks is the Mocks generated by mockgen.. +// +// These are the commands used to generate the mocks found here: +// +// mocks/client.go: +// +// mockgen -package mocks github.com/uber-go/dosa Client,AdminClient > mocks/client.go +// +// mocks/connector.go: +// +// mockgen -package mocks github.com/uber-go/dosa Connector > mocks/connector.go +// +// OR just run make mocks +// +// +package mocks