VOL-1978 - add golangci invocation and fixed issues it highlighted

Change-Id: I86f438f84e8ab7fae499a163d599b699c472afda
diff --git a/.gitignore b/.gitignore
index b9fff0d..11180da 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,4 @@
 voltctl.cp
 release
 *.log
+sca-report
diff --git a/Makefile b/Makefile
index 515273b..62332d7 100644
--- a/Makefile
+++ b/Makefile
@@ -3,8 +3,13 @@
 	@echo "build        - build the binary as a local executable"
 	@echo "install      - build and install the binary into \$$GOPATH/bin"
 	@echo "run          - runs voltctl using the command specified as \$$CMD"
+	@echo "lint-style   - Verify code is properly gofmt-ed"
+	@echo "lint-sanity  - Verify that 'go vet' doesn't report any issues"
+	@echo "lint-mod     - Verify the integrity of the 'mod' files"
 	@echo "lint         - run static code analysis"
+	@echo "sca          - Runs various SCA through golangci-lint tool"
 	@echo "test         - run unity tests"
+	@echo "check        - runs targets that should be run before a commit"
 	@echo "clean        - remove temporary and generated files"
 
 internal/pkg/commands/voltha_v1_pb.go: assets/protosets/voltha_v1.pb
@@ -55,6 +60,8 @@
 
 encode-protosets: internal/pkg/commands/voltha_v1_pb.go internal/pkg/commands/voltha_v2_pb.go
 
+SHELL=bash -e -o pipefail
+
 VERSION=$(shell cat ./VERSION)
 GITCOMMIT=$(shell git rev-parse HEAD)
 ifeq ($(shell git ls-files --others --modified --exclude-standard 2>/dev/null | wc -l | sed -e 's/ //g'),0)
@@ -132,7 +139,23 @@
 	@go vet -mod=vendor ./...
 	@echo "OK"
 
-lint: lint-style lint-sanity
+lint-mod:
+	@echo -n "Running dependency check ... "
+	@echo -n $(shell go mod verify)
+	@echo " ... OK"
+
+lint: lint-style lint-sanity lint-mod
+
+GOLANGCI_LINT_OUT_FORMAT ?= junit-xml
+GOLANGCI_LINT_TOOL:=$(shell which golangci-lint)
+sca:
+ifeq (,$(GOLANGCI_LINT_TOOL))
+	@echo "Please install golangci-lint tool to run sca"
+	exit 1
+endif
+	@rm -rf ./sca-report
+	@mkdir -p ./sca-report
+	$(GOLANGCI_LINT_TOOL) run --out-format $(GOLANGCI_LINT_OUT_FORMAT) ./... 2>&1 | tee ./sca-report/sca-report.xml
 
 test:
 	@mkdir -p ./tests/results
@@ -146,5 +169,7 @@
 view-coverage:
 	go tool cover -html ./tests/results/go-test-coverage.out
 
+check: lint sca test
+
 clean:
-	rm -rf voltctl voltctl.cp release
+	rm -rf voltctl voltctl.cp release sca-report
diff --git a/internal/pkg/commands/adapter.go b/internal/pkg/commands/adapter.go
index e848565..067b64c 100644
--- a/internal/pkg/commands/adapter.go
+++ b/internal/pkg/commands/adapter.go
@@ -22,6 +22,7 @@
 	"github.com/jhump/protoreflect/dynamic"
 	"github.com/opencord/voltctl/pkg/format"
 	"github.com/opencord/voltctl/pkg/model"
+	"log"
 )
 
 const (
@@ -39,7 +40,9 @@
 var adapterOpts = AdapterOpts{}
 
 func RegisterAdapterCommands(parent *flags.Parser) {
-	parent.AddCommand("adapter", "adapter commands", "Commands to query and manipulate VOLTHA adapters", &adapterOpts)
+	if _, err := parent.AddCommand("adapter", "adapter commands", "Commands to query and manipulate VOLTHA adapters", &adapterOpts); err != nil {
+		log.Fatalf("Unexpected error while attempting to register adapter commands : %s", err)
+	}
 }
 
 func (options *AdapterList) Execute(args []string) error {
diff --git a/internal/pkg/commands/command.go b/internal/pkg/commands/command.go
index 4693539..2331163 100644
--- a/internal/pkg/commands/command.go
+++ b/internal/pkg/commands/command.go
@@ -145,11 +145,6 @@
 	Data      interface{}
 }
 
-type config struct {
-	ApiVersion string `yaml:"apiVersion"`
-	Server     string `yaml:"server"`
-}
-
 func ProcessGlobalOptions() {
 	if len(GlobalOptions.Config) == 0 {
 		home, err := os.UserHomeDir()
@@ -222,7 +217,9 @@
 		}
 		if result.OutputAs == OUTPUT_TABLE {
 			tableFormat := format.Format(result.Format)
-			tableFormat.Execute(os.Stdout, true, result.NameLimit, data)
+			if err := tableFormat.Execute(os.Stdout, true, result.NameLimit, data); err != nil {
+				log.Fatalf("Unexpected error while attempting to format results as table : %s", err)
+			}
 		} else if result.OutputAs == OUTPUT_JSON {
 			asJson, err := json.Marshal(&data)
 			if err != nil {
diff --git a/internal/pkg/commands/completion.go b/internal/pkg/commands/completion.go
index c044b6a..17de063 100644
--- a/internal/pkg/commands/completion.go
+++ b/internal/pkg/commands/completion.go
@@ -19,6 +19,7 @@
 	"fmt"
 	flags "github.com/jessevdk/go-flags"
 	"github.com/opencord/voltctl/internal/pkg/completion"
+	"log"
 )
 
 type BashOptions struct{}
@@ -28,7 +29,9 @@
 }
 
 func RegisterCompletionCommands(parent *flags.Parser) {
-	parent.AddCommand("completion", "generate shell compleition", "Commands to generate shell compleition information", &CompletionOptions{})
+	if _, err := parent.AddCommand("completion", "generate shell compleition", "Commands to generate shell compleition information", &CompletionOptions{}); err != nil {
+		log.Fatalf("Unexpected error while attempting to register completion commands : %s", err)
+	}
 }
 
 func (options *BashOptions) Execute(args []string) error {
diff --git a/internal/pkg/commands/components.go b/internal/pkg/commands/components.go
index 2de4ee7..95cbd80 100644
--- a/internal/pkg/commands/components.go
+++ b/internal/pkg/commands/components.go
@@ -23,7 +23,7 @@
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/kubernetes"
 	"k8s.io/client-go/tools/clientcmd"
-	"os"
+	"log"
 )
 
 const (
@@ -43,7 +43,9 @@
 var componentOpts = ComponentOpts{}
 
 func RegisterComponentCommands(parser *flags.Parser) {
-	parser.AddCommand("component", "component instance commands", "Commands to query and manipulate VOLTHA component instances", &componentOpts)
+	if _, err := parser.AddCommand("component", "component instance commands", "Commands to query and manipulate VOLTHA component instances", &componentOpts); err != nil {
+		log.Fatalf("Unexpected error while attempting to register component commands : %s", err)
+	}
 }
 
 func (options *ComponentList) Execute(args []string) error {
@@ -100,10 +102,3 @@
 	GenerateOutput(&result)
 	return nil
 }
-
-func homeDir() string {
-	if h := os.Getenv("HOME"); h != "" {
-		return h
-	}
-	return os.Getenv("USERPROFILE") // windows
-}
diff --git a/internal/pkg/commands/config.go b/internal/pkg/commands/config.go
index d7e4409..aadc9d2 100644
--- a/internal/pkg/commands/config.go
+++ b/internal/pkg/commands/config.go
@@ -19,6 +19,7 @@
 	"fmt"
 	flags "github.com/jessevdk/go-flags"
 	"gopkg.in/yaml.v2"
+	"log"
 )
 
 const copyrightNotice = `
@@ -42,7 +43,9 @@
 }
 
 func RegisterConfigCommands(parent *flags.Parser) {
-	parent.AddCommand("config", "generate voltctl configuration", "Commands to generate voltctl configuration", &ConfigOptions{})
+	if _, err := parent.AddCommand("config", "generate voltctl configuration", "Commands to generate voltctl configuration", &ConfigOptions{}); err != nil {
+		log.Fatalf("Unexpected error while attempting to register config commands : %s", err)
+	}
 }
 
 func (options *ConfigOptions) Execute(args []string) error {
diff --git a/internal/pkg/commands/devicegroups.go b/internal/pkg/commands/devicegroups.go
index c499afc..7314b0a 100644
--- a/internal/pkg/commands/devicegroups.go
+++ b/internal/pkg/commands/devicegroups.go
@@ -22,6 +22,7 @@
 	"github.com/jhump/protoreflect/dynamic"
 	"github.com/opencord/voltctl/pkg/format"
 	"github.com/opencord/voltctl/pkg/model"
+	"log"
 )
 
 const (
@@ -39,8 +40,10 @@
 var deviceGroupOpts = DeviceGroupOpts{}
 
 func RegisterDeviceGroupCommands(parser *flags.Parser) {
-	parser.AddCommand("devicegroup", "device group commands", "Commands to query and manipulate VOLTHA device groups",
-		&deviceGroupOpts)
+	if _, err := parser.AddCommand("devicegroup", "device group commands", "Commands to query and manipulate VOLTHA device groups",
+		&deviceGroupOpts); err != nil {
+		log.Fatalf("Unexpected error while attempting to register device group commands : %s", err)
+	}
 }
 
 func (options *DeviceGroupList) Execute(args []string) error {
diff --git a/internal/pkg/commands/devices.go b/internal/pkg/commands/devices.go
index 9f836b4..78d1aca 100644
--- a/internal/pkg/commands/devices.go
+++ b/internal/pkg/commands/devices.go
@@ -23,6 +23,7 @@
 	"github.com/jhump/protoreflect/dynamic"
 	"github.com/opencord/voltctl/pkg/format"
 	"github.com/opencord/voltctl/pkg/model"
+	"log"
 	"strings"
 )
 
@@ -113,7 +114,9 @@
 var deviceOpts = DeviceOpts{}
 
 func RegisterDeviceCommands(parser *flags.Parser) {
-	parser.AddCommand("device", "device commands", "Commands to query and manipulate VOLTHA devices", &deviceOpts)
+	if _, err := parser.AddCommand("device", "device commands", "Commands to query and manipulate VOLTHA devices", &deviceOpts); err != nil {
+		log.Fatalf("Unexpected error while attempting to register device commands : %s", err)
+	}
 }
 
 func (i *DeviceId) Complete(match string) []flags.Completion {
diff --git a/internal/pkg/commands/flows.go b/internal/pkg/commands/flows.go
index acbb09c..d16abab 100644
--- a/internal/pkg/commands/flows.go
+++ b/internal/pkg/commands/flows.go
@@ -40,8 +40,6 @@
 }
 
 var (
-	flowOpts = FlowOpts{}
-
 	// Used to sort the table colums in a consistent order
 	SORT_ORDER = map[string]uint16{
 		"Id":                     0,
@@ -104,29 +102,6 @@
 	return b.String()
 }
 
-func toVlanId(vid uint32) string {
-	if vid == 0 {
-		return "untagged"
-	} else if vid&0x1000 > 0 {
-		return fmt.Sprintf("%d", vid-4096)
-	}
-	return fmt.Sprintf("%d", vid)
-}
-
-func appendInt32(base string, val int32) string {
-	if len(base) > 0 {
-		return fmt.Sprintf("%s,%d", base, val)
-	}
-	return fmt.Sprintf("%d", val)
-}
-
-func appendUint32(base string, val uint32) string {
-	if len(base) > 0 {
-		return fmt.Sprintf("%s,%d", base, val)
-	}
-	return fmt.Sprintf("%d", val)
-}
-
 func (options *FlowList) Execute(args []string) error {
 	if len(args) > 0 {
 		return fmt.Errorf("only a single argument 'DEVICE_ID' can be provided")
diff --git a/internal/pkg/commands/logicaldevices.go b/internal/pkg/commands/logicaldevices.go
index ce09035..16cd48a 100644
--- a/internal/pkg/commands/logicaldevices.go
+++ b/internal/pkg/commands/logicaldevices.go
@@ -23,6 +23,7 @@
 	"github.com/jhump/protoreflect/dynamic"
 	"github.com/opencord/voltctl/pkg/format"
 	"github.com/opencord/voltctl/pkg/model"
+	"log"
 	"strings"
 )
 
@@ -72,7 +73,9 @@
 var logicalDeviceOpts = LogicalDeviceOpts{}
 
 func RegisterLogicalDeviceCommands(parser *flags.Parser) {
-	parser.AddCommand("logicaldevice", "logical device commands", "Commands to query and manipulate VOLTHA logical devices", &logicalDeviceOpts)
+	if _, err := parser.AddCommand("logicaldevice", "logical device commands", "Commands to query and manipulate VOLTHA logical devices", &logicalDeviceOpts); err != nil {
+		log.Fatalf("Unexpected error while attempting to register logical device commands : %s", err)
+	}
 }
 
 func (i *LogicalDeviceId) Complete(match string) []flags.Completion {
diff --git a/pkg/filter/filter.go b/pkg/filter/filter.go
index 5aa24ad..4ced633 100644
--- a/pkg/filter/filter.go
+++ b/pkg/filter/filter.go
@@ -64,7 +64,7 @@
 
 type Filter map[string]FilterTerm
 
-var termRE = regexp.MustCompile("^\\s*([a-zA-Z_][.a-zA-Z0-9_]*)\\s*(~|<=|>=|<|>|!=|=)\\s*(.+)\\s*$")
+var termRE = regexp.MustCompile(`^\s*([a-zA-Z_][.a-zA-Z0-9_]*)\s*(~|<=|>=|<|>|!=|=)\s*(.+)\s*$`)
 
 // Parse parses a comma separated list of filter terms
 func Parse(spec string) (Filter, error) {
diff --git a/pkg/filter/filter_test.go b/pkg/filter/filter_test.go
index 3a718e0..a776e49 100644
--- a/pkg/filter/filter_test.go
+++ b/pkg/filter/filter_test.go
@@ -219,7 +219,9 @@
 		},
 	}
 
-	f.Process(data)
+	if _, err = f.Process(data); err != nil {
+		t.Errorf("Error processing data")
+	}
 }
 
 func TestBadRE(t *testing.T) {
diff --git a/pkg/format/formatter.go b/pkg/format/formatter.go
index af92a03..eaa42eb 100644
--- a/pkg/format/formatter.go
+++ b/pkg/format/formatter.go
@@ -71,18 +71,30 @@
 				}
 			}
 		}
-		tabWriter.Write([]byte(header))
-		tabWriter.Write([]byte("\n"))
+		if _, err = tabWriter.Write([]byte(header)); err != nil {
+			return err
+		}
+		if _, err = tabWriter.Write([]byte("\n")); err != nil {
+			return err
+		}
 
 		slice := reflect.ValueOf(data)
 		if slice.Kind() == reflect.Slice {
 			for i := 0; i < slice.Len(); i++ {
-				tmpl.Execute(tabWriter, slice.Index(i).Interface())
-				tabWriter.Write([]byte("\n"))
+				if err = tmpl.Execute(tabWriter, slice.Index(i).Interface()); err != nil {
+					return err
+				}
+				if _, err = tabWriter.Write([]byte("\n")); err != nil {
+					return err
+				}
 			}
 		} else {
-			tmpl.Execute(tabWriter, data)
-			tabWriter.Write([]byte("\n"))
+			if err = tmpl.Execute(tabWriter, data); err != nil {
+				return err
+			}
+			if _, err = tabWriter.Write([]byte("\n")); err != nil {
+				return err
+			}
 		}
 		tabWriter.Flush()
 		return nil
@@ -91,12 +103,20 @@
 	slice := reflect.ValueOf(data)
 	if slice.Kind() == reflect.Slice {
 		for i := 0; i < slice.Len(); i++ {
-			tmpl.Execute(writer, slice.Index(i).Interface())
-			writer.Write([]byte("\n"))
+			if err = tmpl.Execute(writer, slice.Index(i).Interface()); err != nil {
+				return err
+			}
+			if _, err = writer.Write([]byte("\n")); err != nil {
+				return err
+			}
 		}
 	} else {
-		tmpl.Execute(writer, data)
-		writer.Write([]byte("\n"))
+		if err = tmpl.Execute(writer, data); err != nil {
+			return err
+		}
+		if _, err = writer.Write([]byte("\n")); err != nil {
+			return err
+		}
 	}
 	return nil