diff --git a/Taskfile.yml b/Taskfile.yml index bfaa3b6f..5deb6536 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -15,14 +15,22 @@ tasks: default: cmds: - task: build + install_tools: + desc: "Install required Dev tools by GDG" + cmds: + - go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest format: desc: "Format code" cmds: - gofmt -w -s . lint: - desc: "Lint project" + desc: "Lint project, skipping test files." + cmds: + - golangci-lint run --skip-dirs "(^|/)test($|/)" --skip-files "_test.go" ./... + lint_tests: + desc: "Lint project, including test files." cmds: - - golangci-lint run ./... + - golangci-lint run ./... authors: desc: "Building GDG" cmds: @@ -57,10 +65,6 @@ tasks: desc: "Tidy Deps" cmds: - go mod tidy - build-alpine: - desc: "building {{ .BIN_NAME }} {{. VERSION }}" - cmds: - - go build -ldflags '{{ .LD_FLAGS }} -linkmode external -extldflags "-static"' -o bin/{{ .BIN_NAME}} pakcage: desc: "building image {{ .BIN_NAME }} {{ .VERSION }} {{ .GIT_COMMIT }}" cmds: diff --git a/cmd/backup/dashboard.go b/cmd/backup/dashboard.go index c8aed862..eec7c969 100644 --- a/cmd/backup/dashboard.go +++ b/cmd/backup/dashboard.go @@ -14,9 +14,7 @@ import ( "strings" ) -var ( - skipConfirmAction bool -) +var skipConfirmAction bool func parseDashboardGlobalFlags(command *cobra.Command) []string { folderFilter, _ := command.Flags().GetString("folder") diff --git a/cmd/context.go b/cmd/context.go index 270ca919..b6ae4992 100644 --- a/cmd/context.go +++ b/cmd/context.go @@ -50,7 +50,7 @@ func newListContextCmd() simplecobra.Commander { r.TableObj.AppendHeader(table.Row{"context", "active"}) contexts := config.Config().GetAppConfig().GetContexts() activeContext := config.Config().GetAppConfig().GetContext() - for key, _ := range contexts { + for key := range contexts { active := false if key == strings.ToLower(activeContext) { key = fmt.Sprintf("*%s", activeContext) diff --git a/cmd/support/root.go b/cmd/support/root.go index d9ea6d7c..8f09d769 100644 --- a/cmd/support/root.go +++ b/cmd/support/root.go @@ -15,17 +15,13 @@ var ( DefaultConfig string ) +// RootCommand struct wraps the root command and supporting services needed type RootCommand struct { NameP string isInit bool GrafanaSvc func() service.GrafanaService - localFlagName string - - persistentFlagNameC string - localFlagNameC string - ctx context.Context initThis *simplecobra.Commandeer initRunner *simplecobra.Commandeer @@ -37,6 +33,7 @@ type RootCommand struct { CommandEntries []simplecobra.Commander } +// RootOption used to configure the Root Command struct type RootOption func(command *RootCommand) // NewRootCmd Allows to construct a root command passing any number of arguments to set RootCommand Options @@ -50,10 +47,12 @@ func NewRootCmd(root *RootCommand, options ...RootOption) *RootCommand { return root } +// Commands returns a list of Cobra commands func (c *RootCommand) Commands() []simplecobra.Commander { return c.CommandEntries } +// PreRun executed prior to command invocation func (c *RootCommand) PreRun(this, runner *simplecobra.Commandeer) error { c.isInit = true c.initThis = this @@ -62,6 +61,7 @@ func (c *RootCommand) PreRun(this, runner *simplecobra.Commandeer) error { return nil } +// initConfiguration Loads configuration, and setups fail over case func (c *RootCommand) initConfiguration() { cmd := c.initRunner.CobraCommand configOverride, _ := cmd.Flags().GetString("config") @@ -84,10 +84,12 @@ func (c *RootCommand) initConfiguration() { } +// Name returns the cli command name func (c *RootCommand) Name() string { return c.NameP } +// Run invokes the CLI command func (c *RootCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, args []string) error { if c.failRun { return errors.New("failRun") @@ -96,6 +98,7 @@ func (c *RootCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, args return nil } +// Init invoked to Initialize the RootCommand object func (c *RootCommand) Init(cd *simplecobra.Commandeer) error { if c.failWithCobraCommand { return errors.New("failWithCobraCommand") diff --git a/cmd/support/simple.go b/cmd/support/simple.go index 810fe23c..28db95db 100644 --- a/cmd/support/simple.go +++ b/cmd/support/simple.go @@ -6,6 +6,7 @@ import ( "github.com/spf13/cobra" ) +// SimpleCommand wraps a simple command type SimpleCommand struct { use string NameP string @@ -20,18 +21,22 @@ type SimpleCommand struct { RootCmd *RootCommand } +// Commands is a list of subcommands func (c *SimpleCommand) Commands() []simplecobra.Commander { return c.CommandsList } +// SetName Function allows name to be set func (c *SimpleCommand) SetName(name string) { c.NameP = name } +// Name returns function Name func (c *SimpleCommand) Name() string { return c.NameP } +// Run executes cli command func (c *SimpleCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, args []string) error { if c.RunFunc == nil { return nil @@ -39,6 +44,7 @@ func (c *SimpleCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, arg return c.RunFunc(ctx, cd, c.RootCmd, args) } +// Init initializes the SimpleCommand func (c *SimpleCommand) Init(cd *simplecobra.Commandeer) error { c.RootCmd = cd.Root.Command.(*RootCommand) cmd := cd.CobraCommand @@ -53,6 +59,7 @@ func (c *SimpleCommand) Init(cd *simplecobra.Commandeer) error { return nil } +// PreRun executed prior to cli command execution func (c *SimpleCommand) PreRun(cd, runner *simplecobra.Commandeer) error { if c.InitCFunc != nil { return c.InitCFunc(cd, c.RootCmd) diff --git a/cmd/test_tools/support.go b/cmd/test_tools/support.go index a9ceda25..5c23ecba 100644 --- a/cmd/test_tools/support.go +++ b/cmd/test_tools/support.go @@ -2,6 +2,8 @@ package test_tools import "os" +// InterceptStdout is a test helper function that will redirect all stdout in and out to a different file stream. +// It returns the stdout, stderr, and a function to be invoked to close the streams. func InterceptStdout() (*os.File, *os.File, func()) { backupStd := os.Stdout backupErr := os.Stderr diff --git a/internal/config/config.go b/internal/config/config.go index a1fdf0d1..da874e5a 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -97,7 +97,7 @@ func (s *Configuration) DeleteContext(name string) { } delete(contexts, name) if len(contexts) != 0 { - for key, _ := range contexts { + for key := range contexts { s.GetAppConfig().ContextName = key break } diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 63d0823e..43ba49a0 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -15,12 +15,15 @@ import ( func DuplicateConfig(t *testing.T) string { dir, _ := os.Getwd() + var err error //Fix test path if strings.Contains(dir, "config") { - os.Chdir("../..") + err = os.Chdir("../..") + assert.Nil(t, err, "Failed to change to base directory ") } - os.Setenv("GDG_CONTEXT_NAME", "production") + err = os.Setenv("GDG_CONTEXT_NAME", "production") + assert.Nil(t, err, "Failed to set override GDG context name via ENV") data, err := os.ReadFile("config/testing.yml") assert.Nil(t, err, "Failed to read test configuration file") destination := os.TempDir() @@ -98,10 +101,9 @@ func validateGrafanaQA(t *testing.T, grafana *config.GrafanaConfig) { assert.Equal(t, "qa/dashboards", grafana.GetDashboardOutput()) dsSettings := grafana.DataSourceSettings request := models.AddDataSourceCommand{} - defaultSettings, _ := dsSettings.GetCredentials(request) assert.Equal(t, len(grafana.DataSourceSettings.MatchingRules), 3) //Last Entry is the default - defaultSettings = grafana.DataSourceSettings.MatchingRules[2].Auth + defaultSettings := grafana.DataSourceSettings.MatchingRules[2].Auth assert.Equal(t, "user", defaultSettings.User) assert.Equal(t, "password", defaultSettings.Password) diff --git a/internal/config/types.go b/internal/config/types.go index 8f5aa122..c2b47eeb 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -2,7 +2,6 @@ package config import ( "github.com/spf13/viper" - "regexp" ) type Configuration struct { @@ -98,7 +97,7 @@ type FilterOverrides struct { type ConnectionFilters struct { NameExclusions string `yaml:"name_exclusions"` ConnectionTypes []string `yaml:"valid_types"` - pattern *regexp.Regexp + // pattern *regexp.Regexp } // GrafanaConnection Default connection credentials diff --git a/internal/service/common.go b/internal/service/common.go index 91477533..0d897ce2 100644 --- a/internal/service/common.go +++ b/internal/service/common.go @@ -62,15 +62,6 @@ func getFolderFromResourcePath(storageEngine string, filePath string, resourceTy return "", errors.New("unable to parse resource to retrieve folder name") } -func isResourceOrgNamespaces(resourceType config.ResourceType) bool { - if resourceType == config.DashboardResource { - return true - } - - return false - -} - func buildResourceFolder(folderName string, resourceType config.ResourceType) string { if resourceType == config.DashboardResource && folderName == "" { folderName = DefaultFolderName diff --git a/internal/service/dashboards.go b/internal/service/dashboards.go index 0550198e..cf9a12be 100644 --- a/internal/service/dashboards.go +++ b/internal/service/dashboards.go @@ -240,7 +240,7 @@ func (s *DashNGoImpl) UploadDashboards(filterReq filters.Filter) { var ( rawBoard []byte - folderName string = "" + folderName string folderId int64 ) path := config.Config().GetDefaultGrafanaConfig().GetPath(config.DashboardResource) diff --git a/internal/service/libraryelements.go b/internal/service/libraryelements.go index 8e362c3e..532caa15 100644 --- a/internal/service/libraryelements.go +++ b/internal/service/libraryelements.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/esnet/gdg/internal/config" "github.com/esnet/gdg/internal/service/filters" + "github.com/esnet/gdg/internal/tools" "github.com/esnet/grafana-swagger-api-golang/goclient/client/library_elements" "github.com/esnet/grafana-swagger-api-golang/goclient/models" "github.com/gosimple/slug" @@ -23,7 +24,7 @@ type LibraryElementsApi interface { DeleteAllLibraryElements(filter filters.Filter) []string } -var ( +const ( listLibraryPanels int64 = 1 listLibraryVars int64 = 2 ) @@ -72,7 +73,7 @@ func (s *DashNGoImpl) ListLibraryElements(filter filters.Filter) []*models.Libra params := library_elements.NewGetLibraryElementsParams() params.FolderFilter = &folderList - params.Kind = &listLibraryPanels + params.Kind = tools.PtrOf(listLibraryPanels) libraryElements, err := s.client.LibraryElements.GetLibraryElements(params, s.getAuth()) if err != nil { log.WithError(err).Fatal("Unable to list Library Elements") diff --git a/internal/service/organizations.go b/internal/service/organizations.go index 703426de..c1740f99 100644 --- a/internal/service/organizations.go +++ b/internal/service/organizations.go @@ -159,9 +159,6 @@ func (s *DashNGoImpl) UploadOrganizations() []string { result []string rawFolder []byte ) - if s.grafanaConf.IsAdminEnabled() { - - } filesInDir, err := s.storage.FindAllFiles(config.Config().GetDefaultGrafanaConfig().GetPath(config.OrganizationResource), false) if err != nil { log.WithError(err).Fatal("Failed to read folders imports") diff --git a/internal/service/serviceaccounts.go b/internal/service/serviceaccounts.go index 8185144b..69e1408c 100644 --- a/internal/service/serviceaccounts.go +++ b/internal/service/serviceaccounts.go @@ -54,7 +54,6 @@ func (s *DashNGoImpl) CreateServiceAccountToken(serviceAccountId int64, name str } func (s *DashNGoImpl) ListServiceAccounts() []*api.ServiceAccountDTOWithTokens { - result := make([]*api.ServiceAccountDTOWithTokens, 0) p := service_accounts.NewSearchOrgServiceAccountsWithPagingParams() p.Disabled = tools.PtrOf(false) p.Perpage = tools.PtrOf(int64(5000)) @@ -64,7 +63,7 @@ func (s *DashNGoImpl) ListServiceAccounts() []*api.ServiceAccountDTOWithTokens { log.Fatal("unable to retrieve service accounts") } data := resp.GetPayload() - result = lo.Map(data.ServiceAccounts, func(entity *models.ServiceAccountDTO, _ int) *api.ServiceAccountDTOWithTokens { + result := lo.Map(data.ServiceAccounts, func(entity *models.ServiceAccountDTO, _ int) *api.ServiceAccountDTOWithTokens { t := api.ServiceAccountDTOWithTokens{ ServiceAccount: entity, } diff --git a/internal/service/storage_cloud.go b/internal/service/storage_cloud.go index cf2b87ff..52dab9ea 100644 --- a/internal/service/storage_cloud.go +++ b/internal/service/storage_cloud.go @@ -144,6 +144,9 @@ func NewCloudStorage(c context.Context) (Storage, error) { S3ForcePathStyle: aws.Bool(true), Region: aws.String(getMapValue(Region, "us-east-1", stringEmpty, appData)), }) + if err != nil { + errorMsg = err.Error() + } bucketObj, err = s3blob.OpenBucket(context.Background(), sess, appData["bucket_name"], nil) if err != nil { errorMsg = err.Error() diff --git a/internal/service/storage_local.go b/internal/service/storage_local.go index dbe02eca..43617b17 100644 --- a/internal/service/storage_local.go +++ b/internal/service/storage_local.go @@ -35,7 +35,7 @@ func (s *LocalStorage) getBucket(baseFolder string) (*blob.Bucket, error) { if _, err := os.Stat(baseFolder); err != nil { _ = os.Mkdir(baseFolder, 0750) } - opts := fileblob.Options { + opts := fileblob.Options{ NoTempDir: true, } return fileblob.OpenBucket(baseFolder, &opts) diff --git a/internal/service/teams.go b/internal/service/teams.go index 580fdcdf..ced5b7a8 100644 --- a/internal/service/teams.go +++ b/internal/service/teams.go @@ -38,17 +38,13 @@ func NewTeamFilter(entries ...string) filters.Filter { filterObj.AddFilter(filters.Name, teamFilter) filterObj.AddValidation(filters.Name, func(i interface{}) bool { - switch i.(type) { + switch val := i.(type) { case string: - { - val := i.(string) - if filterObj.GetFilter(filters.Name) == "" { - return true - } else if val == filterObj.GetFilter(filters.Name) { - return true - } + if filterObj.GetFilter(filters.Name) == "" { + return true + } else if val == filterObj.GetFilter(filters.Name) { + return true } - default: return false } @@ -59,7 +55,7 @@ func NewTeamFilter(entries ...string) filters.Filter { return filterObj } -// Import Teams +// DownloadTeams fetches all teams for a given Org func (s *DashNGoImpl) DownloadTeams(filter filters.Filter) map[*models.TeamDTO][]*models.TeamMemberDTO { teamListing := maps.Keys(s.ListTeams(filter)) importedTeams := make(map[*models.TeamDTO][]*models.TeamMemberDTO) @@ -201,17 +197,17 @@ func (s *DashNGoImpl) ListTeams(filter filters.Filter) map[*models.TeamDTO][]*mo // Get a specific Team // Return nil if team cannot be found -func (s *DashNGoImpl) getTeam(teamName string, filter filters.Filter) *models.TeamDTO { - teamListing := maps.Keys(s.ListTeams(filter)) - var team *models.TeamDTO - for ndx, item := range teamListing { - if item.Name == teamName { - team = teamListing[ndx] - break - } - } - return team -} +//func (s *DashNGoImpl) getTeam(teamName string, filter filters.Filter) *models.TeamDTO { +// teamListing := maps.Keys(s.ListTeams(filter)) +// var team *models.TeamDTO +// for ndx, item := range teamListing { +// if item.Name == teamName { +// team = teamListing[ndx] +// break +// } +// } +// return team +//} // DeleteTeam removes all Teams func (s *DashNGoImpl) DeleteTeam(filter filters.Filter) ([]*models.TeamDTO, error) { diff --git a/internal/tools/prompt_helpers.go b/internal/tools/prompt_helpers.go index 6c8d756f..11b5143f 100644 --- a/internal/tools/prompt_helpers.go +++ b/internal/tools/prompt_helpers.go @@ -22,7 +22,7 @@ func GetUserConfirmation(msg, error string, terminate bool) bool { error = "Goodbye" } for { - fmt.Printf(msg) + fmt.Print(msg) r := bufio.NewReader(os.Stdin) ans, _ := r.ReadString('\n') ans = strings.ToLower(ans) diff --git a/test/cloud_integration_test.go b/test/cloud_integration_test.go index fb8cef7e..a6d88dfb 100644 --- a/test/cloud_integration_test.go +++ b/test/cloud_integration_test.go @@ -15,7 +15,7 @@ func TestCloudDataSourceCRUD(t *testing.T) { } os.Setenv("GDG_CONTEXT_NAME", "testing") - apiClient, cfg := initTest(t, nil) + apiClient, _ := initTest(t, nil) //Wipe all data from grafana dsFilter := service.NewConnectionFilter("") @@ -24,7 +24,7 @@ func TestCloudDataSourceCRUD(t *testing.T) { apiClient.UploadConnections(dsFilter) dsList := apiClient.ListConnections(dsFilter) assert.True(t, len(dsList) > 0) - SetupCloudFunction(t, cfg, apiClient, []string{"s3", "testing"}) + SetupCloudFunction([]string{"s3", "testing"}) //SetupCloudFunction(apiClient, []string{"mem", "testing"}) log.Info("Importing DataSources") @@ -48,8 +48,10 @@ func TestDashboardCloudCRUD(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } - os.Setenv("GDG_CONTEXT_NAME", "testing") - apiClient, cfg := initTest(t, nil) + err := os.Setenv("GDG_CONTEXT_NAME", "testing") + assert.Nil(t, err, "Failed to set context name via env to testing") + + apiClient, _ := initTest(t, nil) //Wipe all data from grafana dashFilter := service.NewDashboardFilter("", "", "") @@ -60,7 +62,7 @@ func TestDashboardCloudCRUD(t *testing.T) { assert.True(t, len(boards) > 0) //SetupCloudFunction(apiClient, []string{"mem", "testing"}) - _, apiClient = SetupCloudFunction(t, cfg, apiClient, []string{"s3", "testing"}) + _, apiClient = SetupCloudFunction([]string{"s3", "testing"}) //At this point all operations are reading/writing from Minio log.Info("Importing Dashboards") diff --git a/test/integration_common.go b/test/integration_common.go index 56715c3f..203f4961 100644 --- a/test/integration_common.go +++ b/test/integration_common.go @@ -38,7 +38,7 @@ func initTest(t *testing.T, cfgName *string) (service.GrafanaService, *viper.Vip return client, conf } -func SetupCloudFunction(t *testing.T, cfg *viper.Viper, apiClient service.GrafanaService, params []string) (context.Context, service.GrafanaService) { +func SetupCloudFunction(params []string) (context.Context, service.GrafanaService) { _ = os.Setenv(service.InitBucket, "true") bucketName := params[1] var m = map[string]string{ @@ -58,7 +58,7 @@ func SetupCloudFunction(t *testing.T, cfg *viper.Viper, apiClient service.Grafan defaultCfg := config.Config().GetDefaultGrafanaConfig() defaultCfg.Storage = "test" cfgObj.StorageEngine["test"] = m - apiClient = service.NewApiService("dummy") + apiClient := service.NewApiService("dummy") ctx := context.Background() ctx = context.WithValue(ctx, service.StorageContext, m) diff --git a/test/organizations_integration_test.go b/test/organizations_integration_test.go index 490f76f1..cedc2eb1 100644 --- a/test/organizations_integration_test.go +++ b/test/organizations_integration_test.go @@ -53,6 +53,7 @@ func TestOrgUserMembership(t *testing.T) { } //Reset if any state exists. err := apiClient.DeleteUserFromOrg(orgUser.ID, newOrg.ID) + assert.Nil(t, err) //Start CRUD test orgUsers := apiClient.ListOrgUsers(newOrg.ID) assert.Equal(t, len(orgUsers), 1)