diff --git a/.vscode/settings.json b/.vscode/settings.json index 5d10564..312adea 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,7 +2,7 @@ "todohighlight.isEnable": true, "todohighlight.isCaseSensitive": true, "editor.formatOnSave": false, - "go.formatOnSave": true, + "go.formatOnSave": false, "todohighlight.keywords": [ { "text": "TODO:", @@ -96,4 +96,4 @@ "lan_data*": "explorerExcludedFiles", "debug_unifi.log": "explorerExcludedFiles" } -} \ No newline at end of file +} diff --git a/Dockerfile b/Dockerfile index 26fba73..ca3565a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,7 @@ LABEL REPO="https://github.com/bossjones/go-chatbot-lab" # PROJPATH=/go/src/github.com/bossjones/go-chatbot-lab ENV GOPATH=/go \ - GOBIN=/gop/bin \ + GOBIN=/go/bin \ PROJPATH=/go/src/github.com/bossjones/go-chatbot-lab # Because of https://github.com/docker/docker/issues/14914 diff --git a/Makefile b/Makefile index d45d683..2919ea0 100644 --- a/Makefile +++ b/Makefile @@ -63,13 +63,22 @@ default: help build: @echo "building ${BIN_NAME} ${VERSION}" @echo "GOPATH=${GOPATH}" - go build -ldflags "-X main.GitCommit=${GIT_SHA}${GIT_DIRTY} -X main.VersionPrerelease=DEV" -o bin/${BIN_NAME} +# re: ldflags - Link, typically invoked as “go tool link,” reads the Go archive or object for a package main, along with its dependencies, and combines them into an executable binary. +# SOURCE: https://golang.org/cmd/link/ + go build -ldflags "-X github.com/bossjones/go-chatbot-lab/shared/version.GitCommit=$$(git rev-parse HEAD) \ + -X github.com/bossjones/go-chatbot-lab/shared/version.Version=$$(git describe --tags --dirty) \ + -X github.com/bossjones/go-chatbot-lab/shared/version.VersionPrerelease=DEV \ + -X github.com/bossjones/go-chatbot-lab/shared/version.BuildDate=$$(date -u +'%FT%T%z')" \ + -o bin/${BIN_NAME} #REQUIRED-CI bin/go-chatbot-lab: $(SOURCES) @if [ "$$(uname)" == "Linux" ]; then \ CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -i -v \ - -ldflags "-X main.GitCommit=${GIT_SHA}${GIT_DIRTY} -X main.VersionPrerelease=DEV" \ + -ldflags "-X github.com/bossjones/go-chatbot-lab/shared/version.GitCommit=$$(git rev-parse HEAD) \ + -X github.com/bossjones/go-chatbot-lab/shared/version.Version=$$(git describe --tags --dirty) \ + -X github.com/bossjones/go-chatbot-lab/shared/version.VersionPrerelease=DEV \ + -X github.com/bossjones/go-chatbot-lab/shared/version.BuildDate=$$(date -u +'%FT%T%z')" \ -o bin/go-chatbot-lab \ ./ ; \ else \ diff --git a/README.md b/README.md index 43565d2..5cb2e2f 100644 --- a/README.md +++ b/README.md @@ -59,3 +59,7 @@ gofmt -w gomock/mock_matcher/mock_matcher.go sample/mock_user/mock_user.go echo >&2 "OK" ``` + +# A getting started guide for Go newcomers + +https://github.com/alco/gostart diff --git a/config/config.go b/config/config.go index a1d4301..6be1486 100644 --- a/config/config.go +++ b/config/config.go @@ -154,16 +154,18 @@ func setSliceValueFromEnv(field *[]string, envVar string) { *field = apps } } -func setIntValueFromEnv(field *int, envVar string) { - env := os.Getenv(envVar) - if len(env) > 0 { - var err error - *field, err = strconv.Atoi(env) - if err != nil { - log.Error("Invalid environment variable", "var", envVar, "value", env) - } - } -} + +// func setIntValueFromEnv(field *int, envVar string) { +// env := os.Getenv(envVar) +// if len(env) > 0 { +// var err error +// *field, err = strconv.Atoi(env) +// if err != nil { +// log.Error("Invalid environment variable", "var", envVar, "value", env) +// } +// } +// } + func setBoolValueFromEnv(field *bool, envVar string) { env := os.Getenv(envVar) if len(env) > 0 { diff --git a/main.go b/main.go index 0e7a096..180a572 100644 --- a/main.go +++ b/main.go @@ -5,6 +5,10 @@ package main // "fmt" // ) +// INFO: Package Main +// SOURCE: https://thenewstack.io/understanding-golang-packages/ +// When you build reusable pieces of code, you will develop a package as a shared library. But when you develop executable programs, you will use the package “main” for making the package as an executable program. The package “main” tells the Go compiler that the package should compile as an executable program instead of a shared library. The main function in the package “main” will be the entry point of our executable program. When you build shared libraries, you will not have any main package and main function in the package. + import ( "os" @@ -14,6 +18,7 @@ import ( // cli "github.com/behance/go-cli" "github.com/behance/go-logging/formatters" "github.com/behance/go-logging/log" + "github.com/bossjones/go-chatbot-lab/shared/version" ) type ConfigValue string @@ -40,6 +45,9 @@ func setupLogging(logLevel string, isDebug bool, logLocation string, logAppName } } +// Golang application auto build versioning +// SOURCE: https://stackoverflow.com/questions/11354518/golang-application-auto-build-versioning + func main() { versionFlag := flag.Bool("version", false, "Version") @@ -47,11 +55,12 @@ func main() { // SOURCE: https://github.com/onsi/ginkgo/issues/296#issuecomment-249924522 flag.Parse() + // If defined, show value if *versionFlag { - fmt.Println("Git Commit:", GitCommit) - fmt.Println("Version:", Version) - if VersionPrerelease != "" { - fmt.Println("Version PreRelease:", VersionPrerelease) + fmt.Println("Git Commit:", version.GitCommit) + fmt.Println("Version:", version.Version) + if version.VersionPrerelease != "" { + fmt.Println("Version PreRelease:", version.VersionPrerelease) } // Return multiple named results simply by return // versionFlag, flag, and fmt will be returned(?) diff --git a/shared/lib/util.go b/shared/lib/util.go index 11bac61..d6cc787 100644 --- a/shared/lib/util.go +++ b/shared/lib/util.go @@ -1,6 +1,11 @@ package lib import ( + "bytes" + "os/exec" + "time" + + "github.com/behance/go-common/log" "github.com/twinj/uuid" ) @@ -14,6 +19,58 @@ import ( // println(string(b)) // } +// Coalesce takes string arguments and returns the first one that is not empty +// This is useful for coalscing information from multiple sources +func Coalesce(args ...string) string { + for i := 0; i < len(args); i++ { + if args[i] != "" { + return args[i] + } + } + return "" +} + +// CoalesceDuration takes duration arguments and returns the first one that is not empty +// This is useful for coalescing information from multiple sources +func CoalesceDuration(args ...time.Duration) time.Duration { + for i := 0; i < len(args); i++ { + if args[i] != 0 { + return args[i] + } + } + return 0 +} + +// CoalesceBool takes bool arguments and returns the first one that is not false +// This is useful for coalescing information from multiple sources +func CoalesceBool(args ...bool) bool { + for i := 0; i < len(args); i++ { + if args[i] == true { + return args[i] + } + } + return false +} + +// CoalesceInt takes int arguments and returns the first one that is not zero +// This is useful for coalescing information from multiple sources +func CoalesceInt(args ...int) int { + for i := 0; i < len(args); i++ { + if args[i] > 0 { + return args[i] + } + } + return 0 +} + +// Iff is a go implemetation of ternary operations (condition ? iftrue : if false) +func Iff(condition bool, ifTrue interface{}, ifFalse interface{}) interface{} { + if condition { + return ifTrue + } + return ifFalse +} + // In - checks whether the string is in the array func In(val string, targ []string) bool { for _, cur := range targ { @@ -29,3 +86,22 @@ func CreateUUID() string { u1 := uuid.NewV1() return u1.String() } + +// ExecuteShellScript execs a specified script file and returns the output in a string +func ExecuteShellScript(scriptFile string) (string, error) { + cmd := exec.Command("bash", "-c", scriptFile) + + var out bytes.Buffer + var stderr bytes.Buffer + cmd.Stdout = &out + cmd.Stderr = &stderr + + if err := cmd.Run(); err != nil { + log.Error("Script execution error", "action", "execute shell script", "command", cmd, "error", err, "error_details", stderr.String()) + return stderr.String(), err + + } + log.Info("Executed: "+scriptFile, "action", "execute shell script", "details", out.String()) + + return out.String(), nil +} diff --git a/shared/version/version.go b/shared/version/version.go new file mode 100644 index 0000000..fd1028f --- /dev/null +++ b/shared/version/version.go @@ -0,0 +1,59 @@ +package version + +import ( + "fmt" + "math" + "runtime" + "strconv" + "strings" +) + +// // GitCommit - The git commit that was compiled. This will be filled in by the compiler. +// var GitCommit string + +// // Version - The main version number that is being run at the moment. +// const Version = "0.1.0" + +// VersionPrerelease - A pre-release marker for the version. If this is "" (empty string) +// then it means that it is a final release. Otherwise, this is a pre-release +// such as "dev" (in development) +var VersionPrerelease = "" + +// Version of this chatbot binary +var Version = "" + +// BuildDate is the build date of this chatbot binary +var BuildDate = "" + +// GitCommit is the git SHA of this chatbot binary +var GitCommit = "" + +// GoVersion is the version of Golang used to build flight-director +var GoVersion = runtime.Version() + +// FullVersion - +func FullVersion() string { + return Version + VersionPrerelease + " (" + GitCommit + ")" +} + +// DetailedVersionInfo returns a string with a bunch of info about go-chatbot-lab, +// meant for putting in a `Server` response header, a `User-Agent` +// request header, etc. +func DetailedVersionInfo() string { + return fmt.Sprintf( + "Go-Chatbot-Lab %s; buildDate=%s; sha=%s", + Version, BuildDate, GitCommit, + ) +} + +// ConvertToNumeric converts a version string (. separated) into a numeric value for easier > and < comparisons +func ConvertToNumeric(version string) float64 { + parts := strings.Split(version, ".") + var number float64 + for i, s := range parts { + part, _ := strconv.Atoi(s) + number += math.Pow(1000, float64(len(parts)-(i+1))) * float64(part) + } + + return number +} diff --git a/shared/version/version_suite_test.go b/shared/version/version_suite_test.go new file mode 100644 index 0000000..342abdc --- /dev/null +++ b/shared/version/version_suite_test.go @@ -0,0 +1,13 @@ +package version_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestVersion(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Version Suite") +} diff --git a/shared/version/version_test.go b/shared/version/version_test.go new file mode 100644 index 0000000..b035c25 --- /dev/null +++ b/shared/version/version_test.go @@ -0,0 +1,48 @@ +package version_test + +import ( + . "github.com/bossjones/go-chatbot-lab/shared/version" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Version", func() { + + Describe("Default Version variables", func() { + It("should be ", func() { + Expect(VersionPrerelease).To(Equal("")) + Expect(Version).To(Equal("")) + Expect(BuildDate).To(Equal("")) + Expect(GitCommit).To(Equal("")) + // Expect(GoVersion).To(BeNumerically(">", "go1.9.2")) + }) + }) + + Describe("Func FullVersion", func() { + It("returns a properly formatted string", func() { + full_version := FullVersion() + expected_full_version := " ()" + + Expect(full_version).To(Equal(expected_full_version)) + }) + }) + + Describe("Func DetailedVersionInfo", func() { + It("returns a properly formatted string", func() { + detailed_version_info := DetailedVersionInfo() + expected_detailed_version_info := "Go-Chatbot-Lab ; buildDate=; sha=" + + Expect(detailed_version_info).To(Equal(expected_detailed_version_info)) + }) + }) + + Describe("Func ConvertToNumeric", func() { + It("returns a properly formatted string", func() { + detailed_convert_to_numeric := ConvertToNumeric("1.2.1") + expected_detailed_convert_to_numeric := 1.002001e+06 + + Expect(detailed_convert_to_numeric).To(Equal(expected_detailed_convert_to_numeric)) + }) + }) + +}) diff --git a/version.go b/version.go deleted file mode 100644 index 7c75d0b..0000000 --- a/version.go +++ /dev/null @@ -1,17 +0,0 @@ -package main - -// GitCommit - The git commit that was compiled. This will be filled in by the compiler. -var GitCommit string - -// Version - The main version number that is being run at the moment. -const Version = "0.1.0" - -// VersionPrerelease - A pre-release marker for the version. If this is "" (empty string) -// then it means that it is a final release. Otherwise, this is a pre-release -// such as "dev" (in development) -var VersionPrerelease = "" - -// FullVersion - -func FullVersion() string { - return Version + VersionPrerelease + " (" + GitCommit + ")" -} diff --git a/version_test.go b/version_test.go deleted file mode 100644 index 83debc6..0000000 --- a/version_test.go +++ /dev/null @@ -1,15 +0,0 @@ -package main - -import ( - "testing" -) - -func TestFullVersion(t *testing.T) { - version := FullVersion() - - expected := Version + VersionPrerelease + " (" + GitCommit + ")" - - if version != expected { - t.Fatalf("invalid version returned: %s", version) - } -}