diff --git a/cli/backup/alerting.go b/cli/backup/alerting.go new file mode 100644 index 00000000..1f4b54fd --- /dev/null +++ b/cli/backup/alerting.go @@ -0,0 +1,34 @@ +package backup + +import ( + "context" + + "github.com/bep/simplecobra" + "github.com/esnet/gdg/cli/support" + "github.com/spf13/cobra" +) + +func newAlertingCommand() simplecobra.Commander { + description := "Manage Alerting resources" + return &support.SimpleCommand{ + NameP: "alerting", + Short: description, + Long: description, + WithCFunc: func(cmd *cobra.Command, r *support.RootCommand) { + cmd.Aliases = []string{"alert"} + // connections := cmd + // connections.PersistentFlags().StringP("connection", "", "", "filter by connection slug") + }, + CommandsList: []simplecobra.Commander{ + newAlertingContactCommand(), + // newClearConnectionsCmd(), + // newUploadConnectionsCmd(), + // newDownloadConnectionsCmd(), + // newListConnectionsCmd(), + // newConnectionsPermissionCmd(), + }, + RunFunc: func(ctx context.Context, cd *simplecobra.Commandeer, rootCmd *support.RootCommand, args []string) error { + return cd.CobraCommand.Help() + }, + } +} diff --git a/cli/backup/alerting_contacts.go b/cli/backup/alerting_contacts.go new file mode 100644 index 00000000..353daee4 --- /dev/null +++ b/cli/backup/alerting_contacts.go @@ -0,0 +1,166 @@ +package backup + +import ( + "context" + "encoding/json" + "log" + "log/slog" + + "github.com/bep/simplecobra" + "github.com/esnet/gdg/cli/support" + "github.com/esnet/gdg/internal/service" + "github.com/jedib0t/go-pretty/v6/table" + "github.com/spf13/cobra" +) + +func newAlertingContactCommand() simplecobra.Commander { + description := "Manage Alerting ContactPoints " + return &support.SimpleCommand{ + NameP: "contactpoint", + Short: description, + Long: description, + WithCFunc: func(cmd *cobra.Command, r *support.RootCommand) { + cmd.Aliases = []string{"contact", "contacts", "contactpoints"} + }, + CommandsList: []simplecobra.Commander{ + newListContactPointsCmd(), + newClearContactPointsCmd(), + newUploadContactPointsCmd(), + newDownloadContactPointsCmd(), + }, + RunFunc: func(ctx context.Context, cd *simplecobra.Commandeer, rootCmd *support.RootCommand, args []string) error { + return cd.CobraCommand.Help() + }, + } +} + +func logWarning() { + slog.Warn("GDG does not manage the 'email receiver' entity. It has a very odd behavior compared to all " + + "other entities. If you need to manage email contacts, please create a new contact. GDG will ignore the default contact.") +} + +func newListContactPointsCmd() simplecobra.Commander { + description := "List all contact points for the given Organization" + return &support.SimpleCommand{ + NameP: "list", + Short: description, + Long: description, + WithCFunc: func(cmd *cobra.Command, r *support.RootCommand) { + cmd.Aliases = []string{"l"} + }, + RunFunc: func(ctx context.Context, cd *simplecobra.Commandeer, rootCmd *support.RootCommand, args []string) error { + rootCmd.TableObj.AppendHeader(table.Row{"uid", "name", "slug", "type", "provenance", "settings"}) + contactPoints, err := rootCmd.GrafanaSvc().ListContactPoints() + slog.Info("Listing contact points for context", + slog.String("Organization", GetOrganizationName()), + slog.String("context", GetContext())) + + logWarning() + if err != nil { + log.Fatal("unable to retrieve Orgs contact points", slog.Any("err", err)) + } + if len(contactPoints) == 0 { + slog.Info("No contact points found") + } else { + for _, link := range contactPoints { + rawBytes, err := json.Marshal(link.Settings) + if err != nil { + slog.Warn("unable to marshall settings to valid JSON") + } + typeVal := "" + if link.Type != nil { + typeVal = *link.Type + } + rootCmd.TableObj.AppendRow(table.Row{link.UID, link.Name, service.GetSlug(link.Name), typeVal, link.Provenance, string(rawBytes)}) + } + rootCmd.Render(cd.CobraCommand, contactPoints) + } + return nil + }, + } +} + +func newDownloadContactPointsCmd() simplecobra.Commander { + description := "Download all contact points for the given Organization" + return &support.SimpleCommand{ + NameP: "download", + Short: description, + Long: description, + WithCFunc: func(cmd *cobra.Command, r *support.RootCommand) { + cmd.Aliases = []string{"d"} + }, + RunFunc: func(ctx context.Context, cd *simplecobra.Commandeer, rootCmd *support.RootCommand, args []string) error { + slog.Info("Download contact points for context", + slog.String("Organization", GetOrganizationName()), + slog.String("context", GetContext())) + logWarning() + file, err := rootCmd.GrafanaSvc().DownloadContactPoints() + if err != nil { + slog.Error("unable to download contact points") + } else { + slog.Info("contact points successfully downloaded", slog.Any("file", file)) + } + return nil + }, + } +} + +func newUploadContactPointsCmd() simplecobra.Commander { + description := "Upload all contact points for the given Organization" + return &support.SimpleCommand{ + NameP: "upload", + Short: description, + Long: description, + WithCFunc: func(cmd *cobra.Command, r *support.RootCommand) { + cmd.Aliases = []string{"u"} + }, + RunFunc: func(ctx context.Context, cd *simplecobra.Commandeer, rootCmd *support.RootCommand, args []string) error { + slog.Info("Upload contact points for context", + slog.String("Organization", GetOrganizationName()), + slog.String("context", GetContext())) + newItems, err := rootCmd.GrafanaSvc().UploadContactPoints() + logWarning() + if err != nil { + slog.Error("unable to upload contact points", slog.Any("err", err)) + } else { + slog.Info("contact points successfully uploaded") + rootCmd.TableObj.AppendHeader(table.Row{"name"}) + for _, item := range newItems { + rootCmd.TableObj.AppendRow(table.Row{item}) + } + + rootCmd.Render(cd.CobraCommand, newItems) + } + return nil + }, + } +} + +func newClearContactPointsCmd() simplecobra.Commander { + description := "Clear all contact points for the given Organization" + return &support.SimpleCommand{ + NameP: "clear", + Short: description, + Long: description, + WithCFunc: func(cmd *cobra.Command, r *support.RootCommand) { + cmd.Aliases = []string{"l"} + }, + RunFunc: func(ctx context.Context, cd *simplecobra.Commandeer, rootCmd *support.RootCommand, args []string) error { + slog.Info("Clear contact points for context", + slog.String("Organization", GetOrganizationName()), + slog.String("context", GetContext())) + removedItems, err := rootCmd.GrafanaSvc().ClearContactPoints() + logWarning() + if err != nil { + slog.Error("unable to clear Contact Points") + } else { + slog.Info("Contact Points successfully removed") + rootCmd.TableObj.AppendHeader(table.Row{"name"}) + for _, item := range removedItems { + rootCmd.TableObj.AppendRow(table.Row{item}) + } + } + return nil + }, + } +} diff --git a/cli/backup/backup.go b/cli/backup/backup.go index 8d1caf3d..bb5c7332 100644 --- a/cli/backup/backup.go +++ b/cli/backup/backup.go @@ -35,6 +35,7 @@ limited to clear/delete, list, download and upload. Any other functionality wil newOrganizationsCommand(), newTeamsCommand(), newUsersCommand(), + newAlertingCommand(), }, } } diff --git a/cli/commandeer.go b/cli/commandeer.go index 7f42d7b9..ac2f92a3 100644 --- a/cli/commandeer.go +++ b/cli/commandeer.go @@ -27,7 +27,9 @@ func Execute(defaultCfg string, args []string, options ...support.RootOption) er cd, err := x.Execute(context.Background(), args) if err != nil || len(args) == 0 { - _ = cd.CobraCommand.Help() + if cd != nil { + _ = cd.CobraCommand.Help() + } return err } diff --git a/cli/test/backup/alerting_contactpoints_test.go b/cli/test/backup/alerting_contactpoints_test.go new file mode 100644 index 00000000..146924e4 --- /dev/null +++ b/cli/test/backup/alerting_contactpoints_test.go @@ -0,0 +1,298 @@ +package backup + +import ( + "fmt" + "io" + "log/slog" + "strings" + "testing" + + "github.com/esnet/gdg/internal/tools/ptr" + "github.com/grafana/grafana-openapi-client-go/models" + + "github.com/esnet/gdg/cli" + "github.com/esnet/gdg/internal/service/mocks" + "github.com/esnet/gdg/pkg/test_tooling" + "github.com/esnet/gdg/pkg/test_tooling/common" + "github.com/stretchr/testify/assert" +) + +func TestUploadContactPoints(t *testing.T) { + listCmd := []string{"backup", "alerting", "contactpoint", "upload"} + testCases := []struct { + skip bool + name string + validateFn func(t *testing.T, output string) + setupMocks func(testSvc *mocks.GrafanaService) + expectErr bool + }{ + { + name: "ErrNoDataTest", + validateFn: func(t *testing.T, output string) { + assert.True(t, strings.Contains(output, "WRN GDG does not manage the 'email receiver' entity.")) + assert.True(t, strings.Contains(output, "ERR unable to upload contact points err=\"Unable to download data data\"")) + }, + setupMocks: func(testSvc *mocks.GrafanaService) { + testSvc.EXPECT().InitOrganizations().Return() + testSvc.EXPECT().UploadContactPoints().Return(nil, fmt.Errorf("Unable to download data data")) + }, + }, + { + name: "SuccessUpload", + validateFn: func(t *testing.T, output string) { + assert.True(t, strings.Contains(output, "WRN GDG does not manage the 'email receiver' entity.")) + assert.True(t, strings.Contains(output, "NAME")) + assert.True(t, strings.Contains(output, "─────"), "table structure not found") + assert.True(t, strings.Contains(output, "discord")) + assert.True(t, strings.Contains(output, "slack")) + }, + setupMocks: func(testSvc *mocks.GrafanaService) { + testSvc.EXPECT().InitOrganizations().Return() + testSvc.EXPECT().UploadContactPoints().Return([]string{"discord", "slack"}, nil) + }, + }, + } + for _, tc := range testCases { + if tc.skip { + slog.Debug("Skipping test", slog.Any("testName", tc.name)) + continue + } + slog.Info("Running test", slog.Any("testName", tc.name)) + testSvc := new(mocks.GrafanaService) + if tc.setupMocks != nil { + tc.setupMocks(testSvc) + } + optionMockSvc := getOptionMockSvc(testSvc) + r, w, cleanup := test_tooling.InterceptStdout() + defer cleanup() + + err := cli.Execute(common.DefaultTestConfig, listCmd, optionMockSvc()) + if tc.expectErr { + assert.NotNil(t, err) + } else { + assert.Nil(t, err) + } + defer cleanup() + assert.NoError(t, w.Close()) + + out, _ := io.ReadAll(r) + outStr := string(out) + assert.NotNil(t, tc.validateFn) + tc.validateFn(t, outStr) + + } +} + +func TestDownloadContactPoints(t *testing.T) { + listCmd := []string{"backup", "alerting", "contactpoint", "download"} + testCases := []struct { + skip bool + name string + validateFn func(t *testing.T, output string) + setupMocks func(testSvc *mocks.GrafanaService) + expectErr bool + }{ + { + name: "ErrNoDataTest", + validateFn: func(t *testing.T, output string) { + assert.True(t, strings.Contains(output, "WRN GDG does not manage the 'email receiver' entity.")) + assert.True(t, strings.Contains(output, "ERR unable to download contact points")) + }, + setupMocks: func(testSvc *mocks.GrafanaService) { + testSvc.EXPECT().InitOrganizations().Return() + testSvc.EXPECT().DownloadContactPoints().Return("", fmt.Errorf("Unable to download data data")) + }, + }, + { + name: "SuccessDownload", + validateFn: func(t *testing.T, output string) { + assert.True(t, strings.Contains(output, "WRN GDG does not manage the 'email receiver' entity.")) + assert.True(t, strings.Contains(output, "INF contact points successfully downloaded file=fileName")) + }, + setupMocks: func(testSvc *mocks.GrafanaService) { + testSvc.EXPECT().InitOrganizations().Return() + testSvc.EXPECT().DownloadContactPoints().Return("fileName", nil) + }, + }, + } + for _, tc := range testCases { + if tc.skip { + slog.Debug("Skipping test", slog.Any("testName", tc.name)) + continue + } + slog.Info("Running test", slog.Any("testName", tc.name)) + testSvc := new(mocks.GrafanaService) + if tc.setupMocks != nil { + tc.setupMocks(testSvc) + } + optionMockSvc := getOptionMockSvc(testSvc) + r, w, cleanup := test_tooling.InterceptStdout() + defer cleanup() + + err := cli.Execute(common.DefaultTestConfig, listCmd, optionMockSvc()) + if tc.expectErr { + assert.NotNil(t, err) + } else { + assert.Nil(t, err) + } + defer cleanup() + assert.NoError(t, w.Close()) + + out, _ := io.ReadAll(r) + outStr := string(out) + assert.NotNil(t, tc.validateFn) + tc.validateFn(t, outStr) + + } +} + +func TestListContactPoints(t *testing.T) { + listCmd := []string{"backup", "alerting", "contactpoint", "list"} + testCases := []struct { + skip bool + name string + validateFn func(t *testing.T, output string) + setupMocks func(testSvc *mocks.GrafanaService) + expectErr bool + }{ + { + name: "NoDataTest", + validateFn: func(t *testing.T, output string) { + assert.True(t, strings.Contains(output, "WRN GDG does not manage the 'email receiver' entity.")) + assert.True(t, strings.Contains(output, "No contact points found")) + }, + setupMocks: func(testSvc *mocks.GrafanaService) { + testSvc.EXPECT().InitOrganizations().Return() + testSvc.EXPECT().ListContactPoints().Return(nil, nil) + }, + }, + { + name: "ListingTest", + validateFn: func(t *testing.T, output string) { + assert.True(t, strings.Contains(output, "WRN GDG does not manage the 'email receiver' entity.")) + assert.True(t, strings.Contains(output, "PROVENANCE")) + assert.True(t, strings.Contains(output, "Discord")) + assert.True(t, strings.Contains(output, "Slack")) + // validate Type + assert.True(t, strings.Contains(output, "discordType")) + assert.True(t, strings.Contains(output, "slackType")) + }, + setupMocks: func(testSvc *mocks.GrafanaService) { + testSvc.EXPECT().InitOrganizations().Return() + resp := []*models.EmbeddedContactPoint{ + { + Name: "Discord", + Type: ptr.Of("discordType"), + Settings: map[string]any{"token": "secret", "someValue": "result"}, + }, + { + Name: "Slack", + Type: ptr.Of("slackType"), + Settings: map[string]any{"token": "secret", "slack": "rocks"}, + }, + } + + testSvc.EXPECT().ListContactPoints().Return(resp, nil) + }, + }, + } + for _, tc := range testCases { + if tc.skip { + slog.Debug("Skipping test", slog.Any("testName", tc.name)) + continue + } + slog.Info("Running test", slog.Any("testName", tc.name)) + testSvc := new(mocks.GrafanaService) + if tc.setupMocks != nil { + tc.setupMocks(testSvc) + } + optionMockSvc := getOptionMockSvc(testSvc) + r, w, cleanup := test_tooling.InterceptStdout() + defer cleanup() + + err := cli.Execute(common.DefaultTestConfig, listCmd, optionMockSvc()) + if tc.expectErr { + assert.NotNil(t, err) + } else { + assert.Nil(t, err) + } + defer cleanup() + assert.NoError(t, w.Close()) + + out, _ := io.ReadAll(r) + outStr := string(out) + assert.NotNil(t, tc.validateFn) + tc.validateFn(t, outStr) + + } +} + +func TestClearContactPoints(t *testing.T) { + clearCmd := []string{"backup", "alerting", "contactpoint", "clear"} + testCases := []struct { + skip bool + name string + validateFn func(t *testing.T, output string) + setupMocks func(testSvc *mocks.GrafanaService) + }{ + { + name: "ErrDataTest", + validateFn: func(t *testing.T, output string) { + assert.True(t, strings.Contains(output, "WRN GDG does not manage the 'email receiver' entity.")) + assert.True(t, strings.Contains(output, "ERR unable to clear Contact Points")) + }, + setupMocks: func(testSvc *mocks.GrafanaService) { + testSvc.EXPECT().InitOrganizations().Return() + testSvc.EXPECT().ClearContactPoints().Return(nil, fmt.Errorf("Errror!!!")) + }, + }, + { + name: "NoDataTest", + validateFn: func(t *testing.T, output string) { + assert.True(t, strings.Contains(output, "WRN GDG does not manage the 'email receiver' entity.")) + assert.True(t, strings.Contains(output, "Contact Points successfully removed")) + }, + setupMocks: func(testSvc *mocks.GrafanaService) { + testSvc.EXPECT().InitOrganizations().Return() + testSvc.EXPECT().ClearContactPoints().Return(nil, nil) + }, + }, + { + name: "ListingTest", + validateFn: func(t *testing.T, output string) { + assert.True(t, strings.Contains(output, "WRN GDG does not manage the 'email receiver' entity.")) + assert.True(t, strings.Contains(output, "Contact Points successfully removed")) + }, + setupMocks: func(testSvc *mocks.GrafanaService) { + testSvc.EXPECT().ClearContactPoints().Return([]string{"discord", "slack"}, nil) + testSvc.EXPECT().InitOrganizations().Return() + }, + }, + } + + for _, tc := range testCases { + if tc.skip { + slog.Debug("Skipping test", slog.Any("testName", tc.name)) + continue + } + slog.Info("Running test", slog.Any("testName", tc.name)) + testSvc := new(mocks.GrafanaService) + if tc.setupMocks != nil { + tc.setupMocks(testSvc) + } + + optionMockSvc := getOptionMockSvc(testSvc) + r, w, cleanup := test_tooling.InterceptStdout() + defer cleanup() + + err := cli.Execute(common.DefaultTestConfig, clearCmd, optionMockSvc()) + assert.Nil(t, err) + defer cleanup() + assert.NoError(t, w.Close()) + + out, _ := io.ReadAll(r) + outStr := string(out) + assert.NotNil(t, tc.validateFn) + tc.validateFn(t, outStr) + } +} diff --git a/cli/test/conections_test.go b/cli/test/backup/conections_test.go similarity index 90% rename from cli/test/conections_test.go rename to cli/test/backup/conections_test.go index b5bfb809..32641d41 100644 --- a/cli/test/conections_test.go +++ b/cli/test/backup/conections_test.go @@ -1,10 +1,12 @@ -package test +package backup import ( "io" "strings" "testing" + "github.com/esnet/gdg/pkg/test_tooling" + "github.com/esnet/gdg/cli" "github.com/esnet/gdg/cli/support" "github.com/esnet/gdg/internal/service" @@ -38,12 +40,12 @@ func TestConnectionCommand(t *testing.T) { response.GrafanaSvc = getMockSvc } } - r, w, cleanup := InterceptStdout() + r, w, cleanup := test_tooling.InterceptStdout() err := cli.Execute(common.DefaultTestConfig, []string{"backup", "connections", "list"}, optionMockSvc()) assert.Nil(t, err) defer cleanup() - w.Close() + assert.NoError(t, w.Close()) out, _ := io.ReadAll(r) outStr := string(out) diff --git a/cli/test/backup/main_test.go b/cli/test/backup/main_test.go new file mode 100644 index 00000000..dc9803f7 --- /dev/null +++ b/cli/test/backup/main_test.go @@ -0,0 +1,32 @@ +package backup + +import ( + "log" + "os" + "testing" + + "github.com/esnet/gdg/cli/support" + "github.com/esnet/gdg/internal/service" + "github.com/esnet/gdg/internal/service/mocks" + + "github.com/esnet/gdg/pkg/test_tooling/path" +) + +func TestMain(m *testing.M) { + err := path.FixTestDir("backup", "../../..") + if err != nil { + log.Fatal(err.Error()) + } + code := m.Run() + os.Exit(code) +} + +func getOptionMockSvc(testSvc *mocks.GrafanaService) func() support.RootOption { + return func() support.RootOption { + return func(response *support.RootCommand) { + response.GrafanaSvc = func() service.GrafanaService { + return testSvc + } + } + } +} diff --git a/cli/test/devel_test.go b/cli/test/tools/devel_test.go similarity index 75% rename from cli/test/devel_test.go rename to cli/test/tools/devel_test.go index aef7d0a1..82010609 100644 --- a/cli/test/devel_test.go +++ b/cli/test/tools/devel_test.go @@ -1,9 +1,11 @@ -package test +package tools import ( "strings" "testing" + "github.com/esnet/gdg/pkg/test_tooling" + "github.com/esnet/gdg/cli" "github.com/esnet/gdg/cli/support" "github.com/esnet/gdg/internal/service/mocks" @@ -21,7 +23,7 @@ func TestDevelSrvInfo(t *testing.T) { err := cli.Execute(string(data), []string{"tools", "devel", "srvinfo"}, optionMockSvc()) return err } - outStr, closeReader := setupAndExecuteMockingServices(t, execMe) + outStr, closeReader := test_tooling.SetupAndExecuteMockingServices(t, execMe) defer closeReader() assert.True(t, strings.Contains(outStr, "Version=")) @@ -37,15 +39,15 @@ func TestDevelSrvCompletion(t *testing.T) { } } - outStr, closeReader := setupAndExecuteMockingServices(t, fn([]string{"tools", "devel", "completion", "fish"})) + outStr, closeReader := test_tooling.SetupAndExecuteMockingServices(t, fn([]string{"tools", "devel", "completion", "fish"})) assert.True(t, strings.Contains(outStr, "fish")) assert.True(t, strings.Contains(outStr, "__completion_prepare_completions")) closeReader() - outStr, closeReader = setupAndExecuteMockingServices(t, fn([]string{"tools", "devel", "completion", "bash"})) + outStr, closeReader = test_tooling.SetupAndExecuteMockingServices(t, fn([]string{"tools", "devel", "completion", "bash"})) assert.True(t, strings.Contains(outStr, "bash")) assert.True(t, strings.Contains(outStr, "flag_parsing_disabled")) closeReader() - outStr, closeReader = setupAndExecuteMockingServices(t, fn([]string{"tools", "devel", "completion", "zsh"})) + outStr, closeReader = test_tooling.SetupAndExecuteMockingServices(t, fn([]string{"tools", "devel", "completion", "zsh"})) assert.True(t, strings.Contains(outStr, "shellCompDirectiveKeepOrder")) closeReader() } diff --git a/cli/test/tools/main_test.go b/cli/test/tools/main_test.go new file mode 100644 index 00000000..c5233411 --- /dev/null +++ b/cli/test/tools/main_test.go @@ -0,0 +1,18 @@ +package tools + +import ( + "log" + "os" + "testing" + + "github.com/esnet/gdg/pkg/test_tooling/path" +) + +func TestMain(m *testing.M) { + err := path.FixTestDir("tools", "../../..") + if err != nil { + log.Fatal(err.Error()) + } + code := m.Run() + os.Exit(code) +} diff --git a/cli/test/version_test.go b/cli/test/version_test.go index 44590de2..7dc076c6 100644 --- a/cli/test/version_test.go +++ b/cli/test/version_test.go @@ -1,11 +1,13 @@ package test import ( - "fmt" - "os" + "io" "strings" "testing" + "github.com/esnet/gdg/pkg/test_tooling" + "github.com/esnet/gdg/pkg/test_tooling/path" + "github.com/esnet/gdg/cli" "github.com/esnet/gdg/cli/support" "github.com/esnet/gdg/internal/service" @@ -16,11 +18,12 @@ import ( ) func TestVersionCommand(t *testing.T) { + assert.NoError(t, path.FixTestDir("test", "../..")) execMe := func(mock *mocks.GrafanaService, data []byte, optionMockSvc func() support.RootOption) error { err := cli.Execute(string(data), []string{"version"}, optionMockSvc()) return err } - outStr, closeReader := setupAndExecuteMockingServices(t, execMe) + outStr, closeReader := test_tooling.SetupAndExecuteMockingServices(t, execMe) defer closeReader() assert.True(t, strings.Contains(outStr, "Build Date:")) @@ -33,6 +36,7 @@ func TestVersionCommand(t *testing.T) { } func TestVersionErrCommand(t *testing.T) { + assert.NoError(t, path.FixTestDir("test", "../..")) testSvc := new(mocks.GrafanaService) getMockSvc := func() service.GrafanaService { return testSvc @@ -43,12 +47,14 @@ func TestVersionErrCommand(t *testing.T) { response.GrafanaSvc = getMockSvc } } - path, _ := os.Getwd() - fmt.Println(path) - data, err := os.ReadFile("../../config/" + common.DefaultTestConfig) - assert.Nil(t, err) - - err = cli.Execute(string(data), []string{"dumb", "dumb"}, optionMockSvc()) + r, w, cleanup := test_tooling.InterceptStdout() + defer cleanup() + err := cli.Execute(common.DefaultTestConfig, []string{"dumb", "dumb"}, optionMockSvc()) assert.NotNil(t, err) + assert.NoError(t, w.Close()) + assert.Equal(t, err.Error(), `command error: unknown command "dumb" for "gdg"`) + out, _ := io.ReadAll(r) + output := string(out) + assert.True(t, strings.Contains(output, "gdg [command] --help\" for more information about a command")) } diff --git a/go.mod b/go.mod index bf7e3393..b5d8a145 100644 --- a/go.mod +++ b/go.mod @@ -46,7 +46,6 @@ require ( cloud.google.com/go/monitoring v1.21.1 // indirect cloud.google.com/go/storage v1.44.0 // indirect dario.cat/mergo v1.0.1 // indirect - github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.15.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect @@ -150,7 +149,6 @@ require ( github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect - github.com/hashicorp/go-msgpack v1.1.5 // indirect github.com/hashicorp/go-msgpack/v2 v2.1.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect diff --git a/go.sum b/go.sum index 00c9b988..93569ce5 100644 --- a/go.sum +++ b/go.sum @@ -1,65 +1,52 @@ cel.dev/expr v0.16.2 h1:RwRhoH17VhAu9U5CMvMhH1PDVgf0tuz9FT+24AfMLfU= cel.dev/expr v0.16.2/go.mod h1:gXngZQMkWJoSbE8mOzehJlXQyubn/Vg0vR9/F3W7iw8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.115.1 h1:Jo0SM9cQnSkYfp44+v+NQXHpcHqlnRJk2qxh6yvxxxQ= -cloud.google.com/go v0.115.1/go.mod h1:DuujITeaufu3gL68/lOFIirVNJwQeyf5UXyi+Wbgknc= cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= -cloud.google.com/go/auth v0.9.4 h1:DxF7imbEbiFu9+zdKC6cKBko1e8XeJnipNqIbWZ+kDI= -cloud.google.com/go/auth v0.9.4/go.mod h1:SHia8n6//Ya940F1rLimhJCjjx7KE17t0ctFEci3HkA= cloud.google.com/go/auth v0.9.8 h1:+CSJ0Gw9iVeSENVCKJoLHhdUykDgXSc4Qn+gu2BRtR8= cloud.google.com/go/auth v0.9.8/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI= cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY= cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc= -cloud.google.com/go/compute v1.28.1 h1:XwPcZjgMCnU2tkwY10VleUjSAfpTj9RDn+kGrbYsi8o= -cloud.google.com/go/compute v1.28.1/go.mod h1:b72iXMY4FucVry3NR3Li4kVyyTvbMDE7x5WsqvxjsYk= -cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= -cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo= cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= -cloud.google.com/go/iam v1.2.0 h1:kZKMKVNk/IsSSc/udOb83K0hL/Yh/Gcqpz+oAkoIFN8= -cloud.google.com/go/iam v1.2.0/go.mod h1:zITGuWgsLZxd8OwAlX+eMFgZDXzBm7icj1PVTYG766Q= cloud.google.com/go/iam v1.2.1 h1:QFct02HRb7H12J/3utj0qf5tobFh9V4vR6h9eX5EBRU= cloud.google.com/go/iam v1.2.1/go.mod h1:3VUIJDPpwT6p/amXRC5GY8fCCh70lxPygguVtI0Z4/g= -cloud.google.com/go/longrunning v0.6.0 h1:mM1ZmaNsQsnb+5n1DNPeL0KwQd9jQRqSqSDEkBZr+aI= -cloud.google.com/go/longrunning v0.6.0/go.mod h1:uHzSZqW89h7/pasCWNYdUpwGz3PcVWhrWupreVPYLts= +cloud.google.com/go/logging v1.11.0 h1:v3ktVzXMV7CwHq1MBF65wcqLMA7i+z3YxbUsoK7mOKs= +cloud.google.com/go/logging v1.11.0/go.mod h1:5LDiJC/RxTt+fHc1LAt20R9TKiUTReDg6RuuFOZ67+A= cloud.google.com/go/longrunning v0.6.1 h1:lOLTFxYpr8hcRtcwWir5ITh1PAKUD/sG2lKrTSYjyMc= +cloud.google.com/go/longrunning v0.6.1/go.mod h1:nHISoOZpBcmlwbJmiVk5oDRz0qG/ZxPynEGs1iZ79s0= cloud.google.com/go/monitoring v1.21.1 h1:zWtbIoBMnU5LP9A/fz8LmWMGHpk4skdfeiaa66QdFGc= cloud.google.com/go/monitoring v1.21.1/go.mod h1:Rj++LKrlht9uBi8+Eb530dIrzG/cU/lB8mt+lbeFK1c= -cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs= -cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0= cloud.google.com/go/storage v1.44.0 h1:abBzXf4UJKMmQ04xxJf9dYM/fNl24KHoTuBjyJDX2AI= cloud.google.com/go/storage v1.44.0/go.mod h1:wpPblkIuMP5jCB/E48Pz9zIo2S/zD8g+ITmxKkPCITE= +cloud.google.com/go/trace v1.11.1 h1:UNqdP+HYYtnm6lb91aNA5JQ0X14GnxkABGlfz2PzPew= +cloud.google.com/go/trace v1.11.1/go.mod h1:IQKNQuBzH72EGaXEodKlNJrWykGZxet2zgjtS60OtjA= dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.15.0 h1:eXzkOEXbSTOa7cJ7EqeCVi/OFi/ppDrUtQuttCWy74c= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.15.0/go.mod h1:YL1xnZ6QejvQHWJrX/AvhFl4WW4rqHVoKspWNVwFk0M= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 h1:B/dfvscEQtew9dVuoxqxrUKKv8Ih2f55PydknDamU+g= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0/go.mod h1:fiPSssYvltE08HJchL04dOy+RD4hgrjph0cwGGMntdI= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0 h1:+m0M/LFxN43KvULkDNfdXOgrjtg6UYJPFBJyuEcRCAw= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0/go.mod h1:PwOyop78lveYMRs6oCxjiVyBdyCgIYH6XHIVZO9/SFQ= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0 h1:PiSrjRPpkQNjrM8H0WwKMnZUdu1RGMtd/LdGKUrOo+c= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0/go.mod h1:oDrbWx4ewMylP7xHivfgixbfGBT6APAwsSoHRKotnIc= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.0 h1:Be6KInmFEKV81c0pOAEbRYehLMwmmGI1exuFj248AMk= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.0/go.mod h1:WCPBHsOXfBVnivScjs2ypRfimjEW0qPVLGgJkZlrIOA= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.1 h1:cf+OIKbkmMHBaC3u78AXomweqM0oxQSgBXRZf3WH4yM= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.1/go.mod h1:ap1dmS6vQKJxSMNiGJcq4QuUQkOynyD93gLw6MDF7ek= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.11.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw= -github.com/Azure/go-autorest/autorest v0.11.29/go.mod h1:ZtEzC4Jy2JDrZLxvWs8LrBWEBycl1hbT1eknI8MtfAs= github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk= github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -70,8 +57,12 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.24.3 github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.24.3/go.mod h1:itPGVDKf9cC/ov4MdvJ2QZ0khw4bfoo9jzwTJlaxy2k= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.3 h1:xir5X8TS8UBVPWg2jHL+cSTf0jZgqYQSA54TscSt1/0= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.3/go.mod h1:SsdWig2J5PMnfMvfJuEb1uZa8Y+kvNyvrULFo69gTFk= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.48.3 h1:Nl7phYyHjnqofWDpD+6FYdiwtNIxebn0AHLry7Sxb0M= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.48.3/go.mod h1:pNP/L2wDlaQnQlFvkDKGSruDoYRpmAxB6drgsskfYwg= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.3 h1:2vcVkrNdSMJpoOVAWi9ApsQR5iqNeFGt5Qx8Xlt3IoI= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.3/go.mod h1:wRbFgBQUVm1YXrvWKofAEmq9HNJTDphbAaJSSX01KUI= +github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= +github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= @@ -82,15 +73,21 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= +github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/Workiva/go-datastructures v1.1.5 h1:5YfhQ4ry7bZc2Mc7R0YZyYwpf5c6t1cEFvdAhd6Mkf4= +github.com/Workiva/go-datastructures v1.1.5/go.mod h1:1yZL+zfsztete+ePzZz/Zb1/t5BnDuE2Ya2MMGhzP6A= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30 h1:t3eaIm0rUkzbrIewtiFmMK5RXHej2XnoXNhxVsAYUfg= -github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs= github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0= github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs= +github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= +github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= +github.com/alicebob/miniredis v2.5.0+incompatible h1:yBHoLpsyjupjz3NL3MhKMVkR41j82Yjf3KFv7ApYzUI= +github.com/alicebob/miniredis/v2 v2.30.4 h1:8S4/o1/KoUArAGbGwPxcwf0krlzceva2XVOSchFS7Eo= +github.com/alicebob/miniredis/v2 v2.30.4/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= @@ -103,78 +100,42 @@ github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHS github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= -github.com/aws/aws-sdk-go-v2 v1.30.5 h1:mWSRTwQAb0aLE17dSzztCVJWI9+cRMgqebndjwDyK0g= -github.com/aws/aws-sdk-go-v2 v1.30.5/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0= github.com/aws/aws-sdk-go-v2 v1.32.2 h1:AkNLZEyYMLnx/Q/mSKkcMqwNFXMAvFto9bNsHqcTduI= github.com/aws/aws-sdk-go-v2 v1.32.2/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4 h1:70PVAiL15/aBMh5LThwgXdSQorVr91L127ttckI9QQU= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4/go.mod h1:/MQxMqci8tlqDH+pjmoLu1i0tbWCUP1hhyMRuFxpQCw= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6 h1:pT3hpW0cOHRJx8Y0DfJUEQuqPild8jRGmSFmBgvydr0= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6/go.mod h1:j/I2++U0xX+cr44QjHay4Cvxj6FUbnxrgmqN3H1jTZA= -github.com/aws/aws-sdk-go-v2/config v1.27.33 h1:Nof9o/MsmH4oa0s2q9a0k7tMz5x/Yj5k06lDODWz3BU= -github.com/aws/aws-sdk-go-v2/config v1.27.33/go.mod h1:kEqdYzRb8dd8Sy2pOdEbExTTF5v7ozEXX0McgPE7xks= github.com/aws/aws-sdk-go-v2/config v1.28.0 h1:FosVYWcqEtWNxHn8gB/Vs6jOlNwSoyOCA/g/sxyySOQ= github.com/aws/aws-sdk-go-v2/config v1.28.0/go.mod h1:pYhbtvg1siOOg8h5an77rXle9tVG8T+BWLWAo7cOukc= -github.com/aws/aws-sdk-go-v2/credentials v1.17.32 h1:7Cxhp/BnT2RcGy4VisJ9miUPecY+lyE9I8JvcZofn9I= -github.com/aws/aws-sdk-go-v2/credentials v1.17.32/go.mod h1:P5/QMF3/DCHbXGEGkdbilXHsyTBX5D3HSwcrSc9p20I= github.com/aws/aws-sdk-go-v2/credentials v1.17.41 h1:7gXo+Axmp+R4Z+AK8YFQO0ZV3L0gizGINCOWxSLY9W8= github.com/aws/aws-sdk-go-v2/credentials v1.17.41/go.mod h1:u4Eb8d3394YLubphT4jLEwN1rLNq2wFOlT6OuxFwPzU= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13 h1:pfQ2sqNpMVK6xz2RbqLEL0GH87JOwSxPV2rzm8Zsb74= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13/go.mod h1:NG7RXPUlqfsCLLFfi0+IpKN4sCB9D9fw/qTaSB+xRoU= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17 h1:TMH3f/SCAWdNtXXVPPu5D6wrr4G5hI1rAxbcocKfC7Q= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17/go.mod h1:1ZRXLdTpzdJb9fwTMXiLipENRxkGMTn1sfKexGllQCw= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.18 h1:9DIp7vhmOPmueCDwpXa45bEbLHHTt1kcxChdTJWWxvI= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.18/go.mod h1:aJv/Fwz8r56ozwYFRC4bzoeL1L17GYQYemfblOBux1M= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.33 h1:X+4YY5kZRI/cOoSMVMGTqFXHAMg1bvvay7IBcqHpybQ= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.33/go.mod h1:DPynzu+cn92k5UQ6tZhX+wfTB4ah6QDU/NgdHqatmvk= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17 h1:pI7Bzt0BJtYA0N/JEC6B8fJ4RBrEMi1LBrkMdFYNSnQ= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17/go.mod h1:Dh5zzJYMtxfIjYW+/evjQ8uj2OyR/ve2KROHGHlSFqE= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 h1:UAsR3xA31QGf79WzpG/ixT9FZvQlh5HY1NRqSHBNOCk= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21/go.mod h1:JNr43NFf5L9YaG3eKTm7HQzls9J+A9YYcGI5Quh1r2Y= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17 h1:Mqr/V5gvrhA2gvgnF42Zh5iMiQNcOYthFYwCyrnuWlc= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17/go.mod h1:aLJpZlCmjE+V+KtN1q1uyZkfnUWpQGpbsn89XPKyzfU= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 h1:6jZVETqmYCadGFvrYEQfC5fAQmlo80CeL5psbno6r0s= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21/go.mod h1:1SR0GbLlnN3QUmYaflZNiH1ql+1qrSiB2vwcJ+4UM60= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.17 h1:Roo69qTpfu8OlJ2Tb7pAYVuF0CpuUMB0IYWwYP/4DZM= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.17/go.mod h1:NcWPxQzGM1USQggaTVwz6VpqMZPX1CvDJLDh6jnOCa4= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.21 h1:7edmS3VOBDhK00b/MwGtGglCm7hhwNYnjJs/PgFdMQE= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.21/go.mod h1:Q9o5h4HoIWG8XfzxqiuK/CGUbepCJ8uTlaE3bAbxytQ= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 h1:KypMCbLPPHEmf9DgMGw51jMj77VfGPAN2Kv4cfhlfgI= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4/go.mod h1:Vz1JQXliGcQktFTN/LN6uGppAIRoLBR2bMvIMP0gOjc= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 h1:TToQNkvGguu209puTojY/ozlqy2d/SFNcoLIqTFi42g= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0/go.mod h1:0jp+ltwkf+SwG2fm/PKo8t4y8pJSgOCO4D8Lz3k0aHQ= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.19 h1:FLMkfEiRjhgeDTCjjLoc3URo/TBkgeQbocA78lfkzSI= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.19/go.mod h1:Vx+GucNSsdhaxs3aZIKfSUjKVGsxN25nX2SRcdhuw08= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.2 h1:4FMHqLfk0efmTqhXVRL5xYRqlEBNBiRI7N6w4jsEdd4= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.2/go.mod h1:LWoqeWlK9OZeJxsROW2RqrSPvQHKTpp69r/iDjwsSaw= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19 h1:rfprUlsdzgl7ZL2KlXiUAoJnI/VxfHCvDFr2QDFj6u4= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19/go.mod h1:SCWkEdRq8/7EK60NcvvQ6NXKuTcchAD4ROAsC37VEZE= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2 h1:s7NA1SOw8q/5c0wr8477yOPp0z+uBaXBnLE0XYb0POA= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2/go.mod h1:fnjjWyAW/Pj5HYOxl9LJqWtEwS7W2qgcRLWP+uWbss0= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.17 h1:u+EfGmksnJc/x5tq3A+OD7LrMbSSR/5TrKLvkdy/fhY= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.17/go.mod h1:VaMx6302JHax2vHJWgRo+5n9zvbacs3bLU/23DNQrTY= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.2 h1:t7iUP9+4wdc5lt3E41huP+GvQZJD38WLsgVp4iOtAjg= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.2/go.mod h1:/niFCtmuQNxqx9v8WAPq5qh7EH25U4BF6tjoyq9bObM= -github.com/aws/aws-sdk-go-v2/service/s3 v1.61.2 h1:Kp6PWAlXwP1UvIflkIP6MFZYBNDCa4mFCGtxrpICVOg= -github.com/aws/aws-sdk-go-v2/service/s3 v1.61.2/go.mod h1:5FmD/Dqq57gP+XwaUnd5WFPipAuzrf0HmupX27Gvjvc= github.com/aws/aws-sdk-go-v2/service/s3 v1.66.0 h1:xA6XhTF7PE89BCNHJbQi8VvPzcgMtmGC5dr8S8N7lHk= github.com/aws/aws-sdk-go-v2/service/s3 v1.66.0/go.mod h1:cB6oAuus7YXRZhWCc1wIwPywwZ1XwweNp2TVAEGYeB8= -github.com/aws/aws-sdk-go-v2/service/sso v1.22.7 h1:pIaGg+08llrP7Q5aiz9ICWbY8cqhTkyy+0SHvfzQpTc= -github.com/aws/aws-sdk-go-v2/service/sso v1.22.7/go.mod h1:eEygMHnTKH/3kNp9Jr1n3PdejuSNcgwLe1dWgQtO0VQ= github.com/aws/aws-sdk-go-v2/service/sso v1.24.2 h1:bSYXVyUzoTHoKalBmwaZxs97HU9DWWI3ehHSAMa7xOk= github.com/aws/aws-sdk-go-v2/service/sso v1.24.2/go.mod h1:skMqY7JElusiOUjMJMOv1jJsP7YUg7DrhgqZZWuzu1U= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.7 h1:/Cfdu0XV3mONYKaOt1Gr0k1KvQzkzPyiKUdlWJqy+J4= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.7/go.mod h1:bCbAxKDqNvkHxRaIMnyVPXPo+OaPRwvmgzMxbz1VKSA= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2 h1:AhmO1fHINP9vFYUE0LHzCWg/LfUWUF+zFPEcY9QXb7o= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2/go.mod h1:o8aQygT2+MVP0NaV6kbdE1YnnIM8RRVQzoeUH45GOdI= -github.com/aws/aws-sdk-go-v2/service/sts v1.30.7 h1:NKTa1eqZYw8tiHSRGpP0VtTdub/8KNk8sDkNPFaOKDE= -github.com/aws/aws-sdk-go-v2/service/sts v1.30.7/go.mod h1:NXi1dIAGteSaRLqYgarlhP/Ij0cFT+qmCwiJqWh/U5o= github.com/aws/aws-sdk-go-v2/service/sts v1.32.2 h1:CiS7i0+FUe+/YY1GvIBLLrR/XNGZ4CtM1Ll0XavNuVo= github.com/aws/aws-sdk-go-v2/service/sts v1.32.2/go.mod h1:HtaiBI8CjYoNVde8arShXb94UbQQi9L4EMr6D+xGBwo= -github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4= -github.com/aws/smithy-go v1.20.4/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM= github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3 h1:6df1vn4bBlDDo4tARvBm7l6KA9iVMnE3NWizDeWSrps= @@ -212,12 +173,8 @@ github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpS github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= -github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU= -github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E= -github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -234,8 +191,6 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/docker v27.2.1+incompatible h1:fQdiLfW7VLscyoeYEBz7/J8soYFDZV1u6VW6gJEjNMI= -github.com/docker/docker v27.2.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI= github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= @@ -374,8 +329,6 @@ github.com/gosimple/slug v1.14.0 h1:RtTL/71mJNDfpUbCOmnf/XFkzKRtD6wL6Uy+3akm4Es= github.com/gosimple/slug v1.14.0/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ= github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o= github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc= -github.com/grafana/dashboard-linter v0.0.0-20240808111517-eb2bc3ba25e3 h1:/tTPH3D/NBDnRf250HEzaWtaTl1Mv7XJop0Yozj2GmU= -github.com/grafana/dashboard-linter v0.0.0-20240808111517-eb2bc3ba25e3/go.mod h1:oqkuR/13iWWt/23IXYqq6qTj448D1eiuLr1U1RD7D8o= github.com/grafana/dashboard-linter v0.0.0-20241017155901-a9d6c25b7bd3 h1:dyVY3v5AVrfyeTKuZR4o8LSeIZQLnCeon6WFi8LeH0w= github.com/grafana/dashboard-linter v0.0.0-20241017155901-a9d6c25b7bd3/go.mod h1:CHmLeAJSUdGwo0AM8LWs0aDqoOXxt2zBuhSMoL17oO8= github.com/grafana/dskit v0.0.0-20241015200741-21f60cf427aa h1:qn6vlh4ZPBgyMTGUoSS6LewOmZk4JJDeLIfU3o6mYHo= @@ -397,9 +350,12 @@ github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGh github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= -github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= github.com/hashicorp/consul/api v1.29.5 h1:IT+NKziYjZwPGyx3lwC19R/4qdlrKhJkZuGcaC4gCjk= github.com/hashicorp/consul/api v1.29.5/go.mod h1:82/r0JLVRIiY0gIU+F7aKFhyThOdvhII0hqJmjdrTEg= +github.com/hashicorp/consul/proto-public v0.6.3 h1:iDA+fHtcqIc3kMMWkND6CD9W98jfKER0EC9GI7jOUvg= +github.com/hashicorp/consul/proto-public v0.6.3/go.mod h1:a1pOtKbQ2+iRnMlEA2bywlEZ0nbCQ2pS7GDQN6pqLwU= +github.com/hashicorp/consul/sdk v0.16.1 h1:V8TxTnImoPD5cj0U9Spl0TUxcytjcbbJeADFF07KdHg= +github.com/hashicorp/consul/sdk v0.16.1/go.mod h1:fSXvwxB2hmh1FMZCNl6PwX0Q/1wdWtHJcZ7Ea5tns0s= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -429,6 +385,10 @@ github.com/hashicorp/go-sockaddr v1.0.7/go.mod h1:FZQbEYa1pxkQ7WLpyXJ6cbjpT8q0Yg github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= +github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= @@ -447,8 +407,6 @@ github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jedib0t/go-pretty/v6 v6.5.9 h1:ACteMBRrrmm1gMsXe9PSTOClQ63IXDUt03H5U+UV8OU= -github.com/jedib0t/go-pretty/v6 v6.5.9/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E= github.com/jedib0t/go-pretty/v6 v6.6.0 h1:wmZVuAcEkZRT+Aq1xXpE8IGat4vE5WXOMmBpbQqERXw= github.com/jedib0t/go-pretty/v6 v6.6.0/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= @@ -468,10 +426,10 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs= +github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -561,8 +519,14 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/gomega v1.24.0 h1:+0glovB9Jd6z3VR+ScSwQqXVTIfJcGA9UBM8yzQxhqg= +github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= @@ -575,9 +539,12 @@ github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFSt github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= +github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pires/go-proxyproto v0.8.0 h1:5unRmEAPbHXHuLjDg01CxJWf91cw3lKHc/0xzKpXEe0= github.com/pires/go-proxyproto v0.8.0/go.mod h1:iknsfgnH8EkjrMeMyvfKByp9TiBZCKZM0jx2xmKqnVY= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= @@ -598,8 +565,6 @@ github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:Om github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0qELP/7u83l4= -github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -610,8 +575,6 @@ github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.59.1 h1:LXb1quJHWm1P6wq/U824uxYi4Sg0oGvNeUm1z5dJoX0= -github.com/prometheus/common v0.59.1/go.mod h1:GpWM7dewqmVYcd7SmRaiWVe9SSqjf0UrwnYnpEZNuT0= github.com/prometheus/common v0.60.0 h1:+V9PAREWNvJMAuJ1x1BaWl9dewMW4YrHZQbx0sJNllA= github.com/prometheus/common v0.60.0/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= github.com/prometheus/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4= @@ -625,6 +588,8 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/prometheus/prometheus v0.54.1 h1:vKuwQNjnYN2/mDoWfHXDhAsz/68q/dQDb+YbcEqU7MQ= github.com/prometheus/prometheus v0.54.1/go.mod h1:xlLByHhk2g3ycakQGrMaU8K7OySZx98BzeCR99991NY= +github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4= +github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= @@ -661,6 +626,8 @@ github.com/sony/gobreaker v1.0.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJ github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= @@ -693,8 +660,6 @@ github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8 github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/testcontainers/testcontainers-go v0.33.0 h1:zJS9PfXYT5O0ZFXM2xxXfk4J5UMw/kRiISng037Gxdw= github.com/testcontainers/testcontainers-go v0.33.0/go.mod h1:W80YpTa8D5C3Yy16icheD01UTDu+LmXIA2Keo+jWtT8= -github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94= -github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= @@ -704,8 +669,6 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU= github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY= -github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY= -github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE= github.com/tklauser/numcpus v0.9.0 h1:lmyCHtANi8aRUgkckBgoDk1nHCux3n2cgkJLXdQGPDo= github.com/tklauser/numcpus v0.9.0/go.mod h1:SN6Nq1O3VychhC1npsWostA+oW+VOQTxZrS604NSRyI= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= @@ -723,10 +686,10 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yuin/gopher-lua v1.1.0 h1:BojcDhfyDWgU2f2TOzYK/g5p2gxMrku8oupLDqlnSqE= +github.com/yuin/gopher-lua v1.1.0/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -github.com/zeitlinger/conflate v0.0.0-20230622100834-279724abda8c h1:PtECnCzGLw8MuQ0tmPRaN5c95ZfNTFZOobvgC6A83zk= -github.com/zeitlinger/conflate v0.0.0-20230622100834-279724abda8c/go.mod h1:KsJBt1tGR0Q7u+3T7CLN+zITAI06GiXVi/cgP9Xrpb8= github.com/zeitlinger/conflate v0.0.0-20240927101413-c06be92f798f h1:LDoXLndy4Q/r9T8FGSCFI9Gid7CpX51A1hrKeEHfgac= github.com/zeitlinger/conflate v0.0.0-20240927101413-c06be92f798f/go.mod h1:LsXDjizLSJDbT5phvDbF3yZRPZQmZ5Tfv5BMrLnSVg4= go.etcd.io/etcd/api/v3 v3.5.16 h1:WvmyJVbjWqK4R1E+B12RRHz3bRGy9XVfh++MgbN+6n0= @@ -735,8 +698,6 @@ go.etcd.io/etcd/client/pkg/v3 v3.5.16 h1:ZgY48uH6UvB+/7R9Yf4x574uCO3jIx0TRDyetSf go.etcd.io/etcd/client/pkg/v3 v3.5.16/go.mod h1:V8acl8pcEK0Y2g19YlOV9m9ssUe6MgiDSobSoaBAM0E= go.etcd.io/etcd/client/v3 v3.5.16 h1:sSmVYOAHeC9doqi0gv7v86oY/BTld0SEFGaxsU9eRhE= go.etcd.io/etcd/client/v3 v3.5.16/go.mod h1:X+rExSGkyqxvu276cr2OwPLBaeqFu1cIl4vmRjAD/50= -go.mongodb.org/mongo-driver v1.16.1 h1:rIVLL3q0IHM39dvE+z2ulZLp9ENZKThVfuvN/IiN4l8= -go.mongodb.org/mongo-driver v1.16.1/go.mod h1:oB6AhJQvFQL4LEHyXi6aJzQJtBiTQHiAd83l0GdFaiw= go.mongodb.org/mongo-driver v1.17.1 h1:Wic5cJIwJgSpBhe3lx3+/RybR5PiYRMpVFgO7cOHyIM= go.mongodb.org/mongo-driver v1.17.1/go.mod h1:wwWm/+BuOddhcq3n68LKRmgk2wXzmF6s0SFOa0GINL4= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= @@ -745,34 +706,22 @@ go.opentelemetry.io/collector/pdata v1.17.0 h1:z8cjjT2FThAehWu5fbF48OnZyK5q8xd1U go.opentelemetry.io/collector/pdata v1.17.0/go.mod h1:yZaQ9KZAm/qie96LTygRKxOXMq0/54h8OW7330ycuvQ= go.opentelemetry.io/contrib/detectors/gcp v1.31.0 h1:G1JQOreVrfhRkner+l4mrGxmfqYCAuy76asTDAo0xsA= go.opentelemetry.io/contrib/detectors/gcp v1.31.0/go.mod h1:tzQL6E1l+iV44YFTkcAeNQqzXUiekSYP9jjJjXwEd00= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.56.0 h1:yMkBS9yViCc7U7yeLzJPM2XizlfdVvBRSmsQDWu6qc0= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.56.0/go.mod h1:n8MR6/liuGB5EmTETUBeU5ZgqMOlqKRxUaqPQBOANZ8= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM= -go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts= -go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0 h1:j9+03ymgYhPKmeXGk5Zu+cIZOlVzd9Zv7QIiyItjFBU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0/go.mod h1:Y5+XiUG4Emn1hTfciPzGPJaSI+RpDts6BnCIir0SLqk= -go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w= -go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ= go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= -go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= -go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk= go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc= go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= -go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc= -go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o= go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= @@ -787,8 +736,6 @@ go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= -gocloud.dev v0.39.0 h1:EYABYGhAalPUaMrbSKOr5lejxoxvXj99nE8XFtsDgds= -gocloud.dev v0.39.0/go.mod h1:drz+VyYNBvrMTW0KZiBAYEdl8lbNZx+OQ7oQvdrFmSQ= gocloud.dev v0.40.0 h1:f8LgP+4WDqOG/RXoUcyLpeIAGOcAbZrZbDQCUee10ng= gocloud.dev v0.40.0/go.mod h1:drz+VyYNBvrMTW0KZiBAYEdl8lbNZx+OQ7oQvdrFmSQ= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -799,13 +746,9 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= -golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY= golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -838,8 +781,6 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -894,8 +835,6 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -904,8 +843,6 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= -golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -918,19 +855,14 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= -golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190424220101-1e8e1cfdf96b/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -948,8 +880,6 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= -google.golang.org/api v0.197.0 h1:x6CwqQLsFiA5JKAiGyGBjc2bNtHtLddhJCE2IKuhhcQ= -google.golang.org/api v0.197.0/go.mod h1:AuOuo20GoQ331nq7DquGHlU6d+2wN2fZ8O0ta60nRNw= google.golang.org/api v0.201.0 h1:+7AD9JNM3tREtawRMu8sOjSbb8VYcYXJG/2eEOmfDu0= google.golang.org/api v0.201.0/go.mod h1:HVY0FCHVs89xIW9fzf/pBvOEm+OolHa86G/txFezyq4= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -958,16 +888,10 @@ google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoA google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 h1:BulPr26Jqjnd4eYDVe+YvyR7Yc2vJGkO5/0UxD0/jZU= -google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:hL97c3SYopEHblzpxRL4lSs523++l8DYxGM1FQiYmb4= google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53 h1:Df6WuGvthPzc+JiQ/G+m+sNX24kc0aTBqoDN/0yyykE= google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53/go.mod h1:fheguH3Am2dGp1LfXkrvwqC/KlFq8F0nLq3LryOMrrE= -google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc= -google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 h1:fVoAXEKA4+yufmbdVYv+SE73+cPZbbbe8paLsHfkK+U= google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53/go.mod h1:riSXTwQ4+nqmPGtobMFyW5FqVAmIs0St6VPp4Ug7CE4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE= google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= @@ -976,8 +900,6 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo= -google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/grpc/stats/opentelemetry v0.0.0-20241017163036-56df169480cd h1:02ssfqxi4Gh7gq74zPkpugKBpSew71uIxoc+lBwF+KI= @@ -991,8 +913,6 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= @@ -1002,6 +922,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1012,6 +934,7 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/config/resource_type.go b/internal/config/resource_type.go index 371f17a5..34b86214 100644 --- a/internal/config/resource_type.go +++ b/internal/config/resource_type.go @@ -23,6 +23,7 @@ const ( UserResource ResourceType = "users" TemplatesResource ResourceType = "templates" SecureSecretsResource ResourceType = "secure" + AlertingResource ResourceType = "alerting" ) var orgNamespacedResource = map[ResourceType]bool{ @@ -34,6 +35,7 @@ var orgNamespacedResource = map[ResourceType]bool{ FolderResource: true, LibraryElementResource: true, TeamResource: true, + AlertingResource: true, } // isNamespaced returns true if the resource type is namespaced diff --git a/internal/service/alerting.go b/internal/service/alerting.go new file mode 100644 index 00000000..a75a79c4 --- /dev/null +++ b/internal/service/alerting.go @@ -0,0 +1,160 @@ +package service + +import ( + "encoding/json" + "fmt" + "log" + "log/slog" + + "github.com/samber/lo" + + "github.com/esnet/gdg/internal/tools/ptr" + + "github.com/esnet/gdg/internal/config" + "github.com/grafana/grafana-openapi-client-go/client/provisioning" + "github.com/grafana/grafana-openapi-client-go/models" +) + +const ( + emailReceiver = "email receiver" +) + +func (s *DashNGoImpl) ListContactPoints() ([]*models.EmbeddedContactPoint, error) { + p := provisioning.NewGetContactpointsParams() + result, err := s.GetClient().Provisioning.GetContactpoints(p) + if err != nil { + return nil, err + } + data := lo.Filter(result.GetPayload(), func(item *models.EmbeddedContactPoint, index int) bool { + return item.UID != "" + }) + + return data, nil +} + +func (s *DashNGoImpl) DownloadContactPoints() (string, error) { + var ( + dsPacked []byte + err error + ) + p := provisioning.NewGetContactpointsExportParams() + p.Download = ptr.Of(true) + p.Decrypt = ptr.Of(true) + p.Format = ptr.Of("json") + data, err := s.GetClient().Provisioning.GetContactpointsExport(p) + if err != nil { + log.Fatalf("unable to retrieve Contact Points, err: %s", err.Error()) + } + // filter default contactPoints + payload := data.GetPayload() + payload.ContactPoints = lo.Filter(payload.ContactPoints, func(item *models.ContactPointExport, index int) bool { + return item.Name != emailReceiver + }) + + dsPath := buildResourcePath("contacts", config.AlertingResource) + if dsPacked, err = json.MarshalIndent(payload.ContactPoints, "", " "); err != nil { + return "", fmt.Errorf("unable to serialize data to JSON. %w", err) + } + if err = s.storage.WriteFile(dsPath, dsPacked); err != nil { + return "", fmt.Errorf("unable to write file. %w", err) + } + + return dsPath, nil +} + +func (s *DashNGoImpl) UploadContactPoints() ([]string, error) { + var ( + err error + rawDS []byte + result []string + ) + var data []models.ContactPointExport + currentContacts, err := s.ListContactPoints() + if err != nil { + return nil, err + } + m := make(map[string]*models.EmbeddedContactPoint) + for ndx, i := range currentContacts { + m[i.UID] = currentContacts[ndx] + } + + fileLocation := buildResourcePath("contacts", config.AlertingResource) + if rawDS, err = s.storage.ReadFile(fileLocation); err != nil { + return nil, fmt.Errorf("failed to read file. file: %s, err: %w", fileLocation, err) + } + if err = json.Unmarshal(rawDS, &data); err != nil { + return nil, fmt.Errorf("failed to unmarshall file, file:%s, err: %w", fileLocation, err) + } + for _, i := range data { + for _, r := range i.Receivers { + if r.UID == "" { + slog.Info("No valid UID found for record, skipping", slog.Any("type", r.Type)) + continue + } + if _, ok := m[r.UID]; ok { + // do update + p := provisioning.NewPutContactpointParams() + p.UID = r.UID + p.Body = &models.EmbeddedContactPoint{ + DisableResolveMessage: false, + Name: i.Name, + Provenance: "", + Settings: r.Settings, + Type: ptr.Of(r.Type), + UID: r.UID, + } + _, err := s.GetClient().Provisioning.PutContactpoint(p) + if err != nil { + slog.Error("failed to update contact point", slog.Any("uid", r.UID)) + continue + } + result = append(result, i.Name) + + } else { + p := provisioning.NewPostContactpointsParams() + p.Body = &models.EmbeddedContactPoint{ + DisableResolveMessage: false, + Name: i.Name, + UID: r.UID, + Provenance: "", + Settings: r.Settings, + Type: ptr.Of(r.Type), + } + _, err = s.GetClient().Provisioning.PostContactpoints(p) + if err != nil { + slog.Error("failed to create contact point", slog.Any("uid", r.UID)) + continue + } + + result = append(result, i.Name) + } + } + } + + return result, nil +} + +func (s *DashNGoImpl) ClearContactPoints() ([]string, error) { + var ( + err error + results []string + ) + contacts, err := s.ListContactPoints() + if err != nil { + return nil, err + } + + for _, contact := range contacts { + _, err = s.GetClient().Provisioning.DeleteContactpoints(contact.UID) + if err != nil { + slog.Error("unable to delete contact point", + slog.Any("name", contact.Name), + slog.Any("uid", contact.UID), + ) + continue + } + results = append(results, contact.Name) + } + + return results, nil +} diff --git a/internal/service/contracts.go b/internal/service/contracts.go index 11fdbb8f..9959378a 100644 --- a/internal/service/contracts.go +++ b/internal/service/contracts.go @@ -21,6 +21,7 @@ type GrafanaService interface { FoldersApi LibraryElementsApi TeamsApi + AlertingApi AuthenticationApi // MetaData @@ -58,6 +59,13 @@ type DashboardsApi interface { LintDashboards(req types.LintRequest) []string } +type AlertingApi interface { + ListContactPoints() ([]*models.EmbeddedContactPoint, error) + DownloadContactPoints() (string, error) + ClearContactPoints() ([]string, error) + UploadContactPoints() ([]string, error) +} + type DashboardPermissionsApi interface { ListDashboardPermissions(filterReq filters.Filter) ([]gdgType.DashboardAndPermissions, error) DownloadDashboardPermissions(filterReq filters.Filter) ([]string, error) diff --git a/internal/service/dashboards.go b/internal/service/dashboards.go index b8f2258e..b0108b70 100644 --- a/internal/service/dashboards.go +++ b/internal/service/dashboards.go @@ -12,6 +12,8 @@ import ( "sort" "strings" + "github.com/esnet/gdg/internal/tools/ptr" + "github.com/esnet/gdg/internal/config" "github.com/esnet/gdg/internal/service/filters" "github.com/esnet/gdg/internal/service/types" @@ -279,9 +281,9 @@ func (s *DashNGoImpl) ListDashboards(filterReq filters.Filter) []*models.Hit { if tag != "" { searchParams.Tag = []string{tag} } - searchParams.Limit = tools.PtrOf(limit) - searchParams.Page = tools.PtrOf(page) - searchParams.Type = tools.PtrOf(searchTypeDashboard) + searchParams.Limit = ptr.Of(limit) + searchParams.Page = ptr.Of(page) + searchParams.Type = ptr.Of(searchTypeDashboard) pageBoardLinks, err := s.GetClient().Search.Search(searchParams) if err != nil { diff --git a/internal/service/libraryelements.go b/internal/service/libraryelements.go index 3d21821a..279dc356 100644 --- a/internal/service/libraryelements.go +++ b/internal/service/libraryelements.go @@ -8,9 +8,10 @@ import ( "log/slog" "strings" + "github.com/esnet/gdg/internal/tools/ptr" + "github.com/esnet/gdg/internal/config" "github.com/esnet/gdg/internal/service/filters" - "github.com/esnet/gdg/internal/tools" "github.com/gosimple/slug" "github.com/grafana/grafana-openapi-client-go/client/library_elements" "github.com/grafana/grafana-openapi-client-go/models" @@ -66,7 +67,7 @@ func (s *DashNGoImpl) ListLibraryElements(filter filters.Filter) []*models.Libra params := library_elements.NewGetLibraryElementsParams() params.FolderFilter = &folderList - params.Kind = tools.PtrOf(listLibraryPanels) + params.Kind = ptr.Of(listLibraryPanels) libraryElements, err := s.GetClient().LibraryElements.GetLibraryElements(params) if err != nil { log.Fatalf("Unable to list Library Elements %v", err) diff --git a/internal/service/mocks/AlertingApi.go b/internal/service/mocks/AlertingApi.go new file mode 100644 index 00000000..03fcf134 --- /dev/null +++ b/internal/service/mocks/AlertingApi.go @@ -0,0 +1,261 @@ +// Code generated by mockery v2.44.1. DO NOT EDIT. + +package mocks + +import ( + models "github.com/grafana/grafana-openapi-client-go/models" + mock "github.com/stretchr/testify/mock" +) + +// AlertingApi is an autogenerated mock type for the AlertingApi type +type AlertingApi struct { + mock.Mock +} + +type AlertingApi_Expecter struct { + mock *mock.Mock +} + +func (_m *AlertingApi) EXPECT() *AlertingApi_Expecter { + return &AlertingApi_Expecter{mock: &_m.Mock} +} + +// ClearContactPoints provides a mock function with given fields: +func (_m *AlertingApi) ClearContactPoints() ([]string, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for ClearContactPoints") + } + + var r0 []string + var r1 error + if rf, ok := ret.Get(0).(func() ([]string, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() []string); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AlertingApi_ClearContactPoints_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ClearContactPoints' +type AlertingApi_ClearContactPoints_Call struct { + *mock.Call +} + +// ClearContactPoints is a helper method to define mock.On call +func (_e *AlertingApi_Expecter) ClearContactPoints() *AlertingApi_ClearContactPoints_Call { + return &AlertingApi_ClearContactPoints_Call{Call: _e.mock.On("ClearContactPoints")} +} + +func (_c *AlertingApi_ClearContactPoints_Call) Run(run func()) *AlertingApi_ClearContactPoints_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *AlertingApi_ClearContactPoints_Call) Return(_a0 []string, _a1 error) *AlertingApi_ClearContactPoints_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AlertingApi_ClearContactPoints_Call) RunAndReturn(run func() ([]string, error)) *AlertingApi_ClearContactPoints_Call { + _c.Call.Return(run) + return _c +} + +// DownloadContactPoints provides a mock function with given fields: +func (_m *AlertingApi) DownloadContactPoints() (string, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for DownloadContactPoints") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func() (string, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AlertingApi_DownloadContactPoints_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DownloadContactPoints' +type AlertingApi_DownloadContactPoints_Call struct { + *mock.Call +} + +// DownloadContactPoints is a helper method to define mock.On call +func (_e *AlertingApi_Expecter) DownloadContactPoints() *AlertingApi_DownloadContactPoints_Call { + return &AlertingApi_DownloadContactPoints_Call{Call: _e.mock.On("DownloadContactPoints")} +} + +func (_c *AlertingApi_DownloadContactPoints_Call) Run(run func()) *AlertingApi_DownloadContactPoints_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *AlertingApi_DownloadContactPoints_Call) Return(_a0 string, _a1 error) *AlertingApi_DownloadContactPoints_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AlertingApi_DownloadContactPoints_Call) RunAndReturn(run func() (string, error)) *AlertingApi_DownloadContactPoints_Call { + _c.Call.Return(run) + return _c +} + +// ListContactPoints provides a mock function with given fields: +func (_m *AlertingApi) ListContactPoints() ([]*models.EmbeddedContactPoint, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for ListContactPoints") + } + + var r0 []*models.EmbeddedContactPoint + var r1 error + if rf, ok := ret.Get(0).(func() ([]*models.EmbeddedContactPoint, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() []*models.EmbeddedContactPoint); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*models.EmbeddedContactPoint) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AlertingApi_ListContactPoints_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListContactPoints' +type AlertingApi_ListContactPoints_Call struct { + *mock.Call +} + +// ListContactPoints is a helper method to define mock.On call +func (_e *AlertingApi_Expecter) ListContactPoints() *AlertingApi_ListContactPoints_Call { + return &AlertingApi_ListContactPoints_Call{Call: _e.mock.On("ListContactPoints")} +} + +func (_c *AlertingApi_ListContactPoints_Call) Run(run func()) *AlertingApi_ListContactPoints_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *AlertingApi_ListContactPoints_Call) Return(_a0 []*models.EmbeddedContactPoint, _a1 error) *AlertingApi_ListContactPoints_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AlertingApi_ListContactPoints_Call) RunAndReturn(run func() ([]*models.EmbeddedContactPoint, error)) *AlertingApi_ListContactPoints_Call { + _c.Call.Return(run) + return _c +} + +// UploadContactPoints provides a mock function with given fields: +func (_m *AlertingApi) UploadContactPoints() ([]string, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for UploadContactPoints") + } + + var r0 []string + var r1 error + if rf, ok := ret.Get(0).(func() ([]string, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() []string); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AlertingApi_UploadContactPoints_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UploadContactPoints' +type AlertingApi_UploadContactPoints_Call struct { + *mock.Call +} + +// UploadContactPoints is a helper method to define mock.On call +func (_e *AlertingApi_Expecter) UploadContactPoints() *AlertingApi_UploadContactPoints_Call { + return &AlertingApi_UploadContactPoints_Call{Call: _e.mock.On("UploadContactPoints")} +} + +func (_c *AlertingApi_UploadContactPoints_Call) Run(run func()) *AlertingApi_UploadContactPoints_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *AlertingApi_UploadContactPoints_Call) Return(_a0 []string, _a1 error) *AlertingApi_UploadContactPoints_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AlertingApi_UploadContactPoints_Call) RunAndReturn(run func() ([]string, error)) *AlertingApi_UploadContactPoints_Call { + _c.Call.Return(run) + return _c +} + +// NewAlertingApi creates a new instance of AlertingApi. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewAlertingApi(t interface { + mock.TestingT + Cleanup(func()) +}) *AlertingApi { + mock := &AlertingApi{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/service/mocks/AuthenticationApi.go b/internal/service/mocks/AuthenticationApi.go index 236566ac..8f44c16c 100644 --- a/internal/service/mocks/AuthenticationApi.go +++ b/internal/service/mocks/AuthenticationApi.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.0. DO NOT EDIT. +// Code generated by mockery v2.44.1. DO NOT EDIT. package mocks diff --git a/internal/service/mocks/ConnectionPermissions.go b/internal/service/mocks/ConnectionPermissions.go index 4bde69a3..42eda9f1 100644 --- a/internal/service/mocks/ConnectionPermissions.go +++ b/internal/service/mocks/ConnectionPermissions.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.0. DO NOT EDIT. +// Code generated by mockery v2.44.1. DO NOT EDIT. package mocks diff --git a/internal/service/mocks/ConnectionsApi.go b/internal/service/mocks/ConnectionsApi.go index 3e47bf88..902da856 100644 --- a/internal/service/mocks/ConnectionsApi.go +++ b/internal/service/mocks/ConnectionsApi.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.0. DO NOT EDIT. +// Code generated by mockery v2.44.1. DO NOT EDIT. package mocks diff --git a/internal/service/mocks/DashboardPermissionsApi.go b/internal/service/mocks/DashboardPermissionsApi.go index 00f850ed..35394628 100644 --- a/internal/service/mocks/DashboardPermissionsApi.go +++ b/internal/service/mocks/DashboardPermissionsApi.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.0. DO NOT EDIT. +// Code generated by mockery v2.44.1. DO NOT EDIT. package mocks diff --git a/internal/service/mocks/DashboardsApi.go b/internal/service/mocks/DashboardsApi.go index cf378b21..56aba452 100644 --- a/internal/service/mocks/DashboardsApi.go +++ b/internal/service/mocks/DashboardsApi.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.0. DO NOT EDIT. +// Code generated by mockery v2.44.1. DO NOT EDIT. package mocks diff --git a/internal/service/mocks/FoldersApi.go b/internal/service/mocks/FoldersApi.go index ce209436..5c68ab09 100644 --- a/internal/service/mocks/FoldersApi.go +++ b/internal/service/mocks/FoldersApi.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.0. DO NOT EDIT. +// Code generated by mockery v2.44.1. DO NOT EDIT. package mocks diff --git a/internal/service/mocks/GrafanaService.go b/internal/service/mocks/GrafanaService.go index c1faf0f7..c2145961 100644 --- a/internal/service/mocks/GrafanaService.go +++ b/internal/service/mocks/GrafanaService.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.0. DO NOT EDIT. +// Code generated by mockery v2.44.1. DO NOT EDIT. package mocks @@ -74,6 +74,63 @@ func (_c *GrafanaService_AddUserToOrg_Call) RunAndReturn(run func(string, string return _c } +// ClearContactPoints provides a mock function with given fields: +func (_m *GrafanaService) ClearContactPoints() ([]string, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for ClearContactPoints") + } + + var r0 []string + var r1 error + if rf, ok := ret.Get(0).(func() ([]string, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() []string); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GrafanaService_ClearContactPoints_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ClearContactPoints' +type GrafanaService_ClearContactPoints_Call struct { + *mock.Call +} + +// ClearContactPoints is a helper method to define mock.On call +func (_e *GrafanaService_Expecter) ClearContactPoints() *GrafanaService_ClearContactPoints_Call { + return &GrafanaService_ClearContactPoints_Call{Call: _e.mock.On("ClearContactPoints")} +} + +func (_c *GrafanaService_ClearContactPoints_Call) Run(run func()) *GrafanaService_ClearContactPoints_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *GrafanaService_ClearContactPoints_Call) Return(_a0 []string, _a1 error) *GrafanaService_ClearContactPoints_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *GrafanaService_ClearContactPoints_Call) RunAndReturn(run func() ([]string, error)) *GrafanaService_ClearContactPoints_Call { + _c.Call.Return(run) + return _c +} + // ClearDashboardPermissions provides a mock function with given fields: filterReq func (_m *GrafanaService) ClearDashboardPermissions(filterReq filters.Filter) error { ret := _m.Called(filterReq) @@ -931,6 +988,61 @@ func (_c *GrafanaService_DownloadConnections_Call) RunAndReturn(run func(filters return _c } +// DownloadContactPoints provides a mock function with given fields: +func (_m *GrafanaService) DownloadContactPoints() (string, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for DownloadContactPoints") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func() (string, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GrafanaService_DownloadContactPoints_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DownloadContactPoints' +type GrafanaService_DownloadContactPoints_Call struct { + *mock.Call +} + +// DownloadContactPoints is a helper method to define mock.On call +func (_e *GrafanaService_Expecter) DownloadContactPoints() *GrafanaService_DownloadContactPoints_Call { + return &GrafanaService_DownloadContactPoints_Call{Call: _e.mock.On("DownloadContactPoints")} +} + +func (_c *GrafanaService_DownloadContactPoints_Call) Run(run func()) *GrafanaService_DownloadContactPoints_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *GrafanaService_DownloadContactPoints_Call) Return(_a0 string, _a1 error) *GrafanaService_DownloadContactPoints_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *GrafanaService_DownloadContactPoints_Call) RunAndReturn(run func() (string, error)) *GrafanaService_DownloadContactPoints_Call { + _c.Call.Return(run) + return _c +} + // DownloadDashboardPermissions provides a mock function with given fields: filterReq func (_m *GrafanaService) DownloadDashboardPermissions(filterReq filters.Filter) ([]string, error) { ret := _m.Called(filterReq) @@ -1849,6 +1961,63 @@ func (_c *GrafanaService_ListConnections_Call) RunAndReturn(run func(filters.Fil return _c } +// ListContactPoints provides a mock function with given fields: +func (_m *GrafanaService) ListContactPoints() ([]*models.EmbeddedContactPoint, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for ListContactPoints") + } + + var r0 []*models.EmbeddedContactPoint + var r1 error + if rf, ok := ret.Get(0).(func() ([]*models.EmbeddedContactPoint, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() []*models.EmbeddedContactPoint); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*models.EmbeddedContactPoint) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GrafanaService_ListContactPoints_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListContactPoints' +type GrafanaService_ListContactPoints_Call struct { + *mock.Call +} + +// ListContactPoints is a helper method to define mock.On call +func (_e *GrafanaService_Expecter) ListContactPoints() *GrafanaService_ListContactPoints_Call { + return &GrafanaService_ListContactPoints_Call{Call: _e.mock.On("ListContactPoints")} +} + +func (_c *GrafanaService_ListContactPoints_Call) Run(run func()) *GrafanaService_ListContactPoints_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *GrafanaService_ListContactPoints_Call) Return(_a0 []*models.EmbeddedContactPoint, _a1 error) *GrafanaService_ListContactPoints_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *GrafanaService_ListContactPoints_Call) RunAndReturn(run func() ([]*models.EmbeddedContactPoint, error)) *GrafanaService_ListContactPoints_Call { + _c.Call.Return(run) + return _c +} + // ListDashboardPermissions provides a mock function with given fields: filterReq func (_m *GrafanaService) ListDashboardPermissions(filterReq filters.Filter) ([]internaltypes.DashboardAndPermissions, error) { ret := _m.Called(filterReq) @@ -2828,6 +2997,63 @@ func (_c *GrafanaService_UploadConnections_Call) RunAndReturn(run func(filters.F return _c } +// UploadContactPoints provides a mock function with given fields: +func (_m *GrafanaService) UploadContactPoints() ([]string, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for UploadContactPoints") + } + + var r0 []string + var r1 error + if rf, ok := ret.Get(0).(func() ([]string, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() []string); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GrafanaService_UploadContactPoints_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UploadContactPoints' +type GrafanaService_UploadContactPoints_Call struct { + *mock.Call +} + +// UploadContactPoints is a helper method to define mock.On call +func (_e *GrafanaService_Expecter) UploadContactPoints() *GrafanaService_UploadContactPoints_Call { + return &GrafanaService_UploadContactPoints_Call{Call: _e.mock.On("UploadContactPoints")} +} + +func (_c *GrafanaService_UploadContactPoints_Call) Run(run func()) *GrafanaService_UploadContactPoints_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *GrafanaService_UploadContactPoints_Call) Return(_a0 []string, _a1 error) *GrafanaService_UploadContactPoints_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *GrafanaService_UploadContactPoints_Call) RunAndReturn(run func() ([]string, error)) *GrafanaService_UploadContactPoints_Call { + _c.Call.Return(run) + return _c +} + // UploadDashboardPermissions provides a mock function with given fields: filterReq func (_m *GrafanaService) UploadDashboardPermissions(filterReq filters.Filter) ([]string, error) { ret := _m.Called(filterReq) diff --git a/internal/service/mocks/LibraryElementsApi.go b/internal/service/mocks/LibraryElementsApi.go index 30caac58..24f6a1f4 100644 --- a/internal/service/mocks/LibraryElementsApi.go +++ b/internal/service/mocks/LibraryElementsApi.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.0. DO NOT EDIT. +// Code generated by mockery v2.44.1. DO NOT EDIT. package mocks diff --git a/internal/service/mocks/LicenseApi.go b/internal/service/mocks/LicenseApi.go index d68af936..15c75abf 100644 --- a/internal/service/mocks/LicenseApi.go +++ b/internal/service/mocks/LicenseApi.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.0. DO NOT EDIT. +// Code generated by mockery v2.44.1. DO NOT EDIT. package mocks diff --git a/internal/service/mocks/NewClientOpts.go b/internal/service/mocks/NewClientOpts.go index 1fe8ae07..1ad7b91d 100644 --- a/internal/service/mocks/NewClientOpts.go +++ b/internal/service/mocks/NewClientOpts.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.0. DO NOT EDIT. +// Code generated by mockery v2.44.1. DO NOT EDIT. package mocks diff --git a/internal/service/mocks/OrgPreferencesApi.go b/internal/service/mocks/OrgPreferencesApi.go index f5360ad1..042108ac 100644 --- a/internal/service/mocks/OrgPreferencesApi.go +++ b/internal/service/mocks/OrgPreferencesApi.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.0. DO NOT EDIT. +// Code generated by mockery v2.44.1. DO NOT EDIT. package mocks diff --git a/internal/service/mocks/OrganizationsApi.go b/internal/service/mocks/OrganizationsApi.go index 2186437b..a2043311 100644 --- a/internal/service/mocks/OrganizationsApi.go +++ b/internal/service/mocks/OrganizationsApi.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.0. DO NOT EDIT. +// Code generated by mockery v2.44.1. DO NOT EDIT. package mocks diff --git a/internal/service/mocks/ServerInfoApi.go b/internal/service/mocks/ServerInfoApi.go index b4e0ffde..18ea0952 100644 --- a/internal/service/mocks/ServerInfoApi.go +++ b/internal/service/mocks/ServerInfoApi.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.0. DO NOT EDIT. +// Code generated by mockery v2.44.1. DO NOT EDIT. package mocks diff --git a/internal/service/mocks/ServiceAccountApi.go b/internal/service/mocks/ServiceAccountApi.go index f7621575..733e9e2c 100644 --- a/internal/service/mocks/ServiceAccountApi.go +++ b/internal/service/mocks/ServiceAccountApi.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.0. DO NOT EDIT. +// Code generated by mockery v2.44.1. DO NOT EDIT. package mocks diff --git a/internal/service/mocks/Storage.go b/internal/service/mocks/Storage.go index ee524f0b..e4d23ac7 100644 --- a/internal/service/mocks/Storage.go +++ b/internal/service/mocks/Storage.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.0. DO NOT EDIT. +// Code generated by mockery v2.44.1. DO NOT EDIT. package mocks diff --git a/internal/service/mocks/TeamsApi.go b/internal/service/mocks/TeamsApi.go index 7b309d76..858c737e 100644 --- a/internal/service/mocks/TeamsApi.go +++ b/internal/service/mocks/TeamsApi.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.0. DO NOT EDIT. +// Code generated by mockery v2.44.1. DO NOT EDIT. package mocks diff --git a/internal/service/mocks/TokenApi.go b/internal/service/mocks/TokenApi.go index aa424f85..880a21b1 100644 --- a/internal/service/mocks/TokenApi.go +++ b/internal/service/mocks/TokenApi.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.0. DO NOT EDIT. +// Code generated by mockery v2.44.1. DO NOT EDIT. package mocks diff --git a/internal/service/mocks/UsersApi.go b/internal/service/mocks/UsersApi.go index 7eb583b7..66500b84 100644 --- a/internal/service/mocks/UsersApi.go +++ b/internal/service/mocks/UsersApi.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.0. DO NOT EDIT. +// Code generated by mockery v2.44.1. DO NOT EDIT. package mocks diff --git a/internal/service/mocks/organizationCrudApi.go b/internal/service/mocks/organizationCrudApi.go index ba3cbf9e..c7a3f25f 100644 --- a/internal/service/mocks/organizationCrudApi.go +++ b/internal/service/mocks/organizationCrudApi.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.0. DO NOT EDIT. +// Code generated by mockery v2.44.1. DO NOT EDIT. package mocks diff --git a/internal/service/mocks/organizationToolsApi.go b/internal/service/mocks/organizationToolsApi.go index 1c926192..81404acf 100644 --- a/internal/service/mocks/organizationToolsApi.go +++ b/internal/service/mocks/organizationToolsApi.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.0. DO NOT EDIT. +// Code generated by mockery v2.44.1. DO NOT EDIT. package mocks diff --git a/internal/service/mocks/organizationUserCrudApi.go b/internal/service/mocks/organizationUserCrudApi.go index dd9e78c6..ea92eaff 100644 --- a/internal/service/mocks/organizationUserCrudApi.go +++ b/internal/service/mocks/organizationUserCrudApi.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.0. DO NOT EDIT. +// Code generated by mockery v2.44.1. DO NOT EDIT. package mocks diff --git a/internal/service/serviceaccounts.go b/internal/service/serviceaccounts.go index 43a95e9f..b83c30fb 100644 --- a/internal/service/serviceaccounts.go +++ b/internal/service/serviceaccounts.go @@ -5,9 +5,10 @@ import ( "log" "log/slog" + "github.com/esnet/gdg/internal/tools/ptr" + "github.com/esnet/gdg/internal/types" - "github.com/esnet/gdg/internal/tools" "github.com/grafana/grafana-openapi-client-go/client/service_accounts" "github.com/grafana/grafana-openapi-client-go/models" "github.com/samber/lo" @@ -44,8 +45,8 @@ func (s *DashNGoImpl) CreateServiceAccountToken(serviceAccountId int64, name str func (s *DashNGoImpl) ListServiceAccounts() []*types.ServiceAccountDTOWithTokens { p := service_accounts.NewSearchOrgServiceAccountsWithPagingParams() - p.Disabled = tools.PtrOf(false) - p.Perpage = tools.PtrOf(int64(5000)) + p.Disabled = ptr.Of(false) + p.Perpage = ptr.Of(int64(5000)) resp, err := s.GetClient().ServiceAccounts.SearchOrgServiceAccountsWithPaging(p) if err != nil { diff --git a/internal/service/teams.go b/internal/service/teams.go index 0b4aea06..6b6afe6d 100644 --- a/internal/service/teams.go +++ b/internal/service/teams.go @@ -183,20 +183,6 @@ func (s *DashNGoImpl) ListTeams(filter filters.Filter) map[*models.TeamDTO][]*mo return result } -// 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 -//} - // DeleteTeam removes all Teams func (s *DashNGoImpl) DeleteTeam(filter filters.Filter) ([]*models.TeamDTO, error) { teamListing := maps.Keys(s.ListTeams(filter)) diff --git a/internal/service/user.go b/internal/service/user.go index f90ddfdc..1b7e1e6c 100644 --- a/internal/service/user.go +++ b/internal/service/user.go @@ -10,9 +10,10 @@ import ( "sort" "strings" + "github.com/esnet/gdg/internal/tools/ptr" + "github.com/esnet/gdg/internal/config" "github.com/esnet/gdg/internal/service/filters" - "github.com/esnet/gdg/internal/tools" "github.com/esnet/gdg/internal/types" "github.com/gosimple/slug" "github.com/grafana/grafana-openapi-client-go/client/admin_users" @@ -164,8 +165,8 @@ func (s *DashNGoImpl) ListUsers(filter filters.Filter) []*models.UserSearchHitDT } var filteredUsers []*models.UserSearchHitDTO params := users.NewSearchUsersParams() - params.Page = tools.PtrOf(int64(1)) - params.Perpage = tools.PtrOf(int64(5000)) + params.Page = ptr.Of(int64(1)) + params.Perpage = ptr.Of(int64(5000)) usersList, err := s.GetClient().Users.SearchUsers(params) if err != nil { log.Fatal(err.Error()) diff --git a/internal/tools/generics_tooling.go b/internal/tools/generics_tooling.go index 4db316db..2d259867 100644 --- a/internal/tools/generics_tooling.go +++ b/internal/tools/generics_tooling.go @@ -6,10 +6,6 @@ import ( "os" ) -func PtrOf[T any](value T) *T { - return &value -} - func DeepCopy[T any](value T) (*T, error) { origJSON, err := json.Marshal(value) if err != nil { diff --git a/internal/tools/ptr/ptr.go b/internal/tools/ptr/ptr.go new file mode 100644 index 00000000..c36b2a2d --- /dev/null +++ b/internal/tools/ptr/ptr.go @@ -0,0 +1,5 @@ +package ptr + +func Of[T any](value T) *T { + return &value +} diff --git a/cli/test/support.go b/pkg/test_tooling/support.go similarity index 80% rename from cli/test/support.go rename to pkg/test_tooling/support.go index 7498bec9..e318fedf 100644 --- a/cli/test/support.go +++ b/pkg/test_tooling/support.go @@ -1,6 +1,7 @@ -package test +package test_tooling import ( + "context" "io" "log/slog" "os" @@ -16,9 +17,9 @@ import ( "github.com/stretchr/testify/assert" ) -// setupAndExecuteMockingServices will create a mock for varous required entities allowing to test the CLI flag parsing +// SetupAndExecuteMockingServices will create a mock for varous required entities allowing to test the CLI flag parsing // process: function that setups mocks and invokes the Execute command -func setupAndExecuteMockingServices(t *testing.T, process func(mock *mocks.GrafanaService, data []byte, optionMockSvc func() support.RootOption) error) (string, func()) { +func SetupAndExecuteMockingServices(t *testing.T, process func(mock *mocks.GrafanaService, data []byte, optionMockSvc func() support.RootOption) error) (string, func()) { testSvc := new(mocks.GrafanaService) getMockSvc := func() service.GrafanaService { return testSvc @@ -31,7 +32,7 @@ func setupAndExecuteMockingServices(t *testing.T, process func(mock *mocks.Grafa } r, w, cleanup := InterceptStdout() - data, err := os.ReadFile("../../config/" + common.DefaultTestConfig) + data, err := os.ReadFile("config/" + common.DefaultTestConfig) assert.Nil(t, err) err = process(testSvc, data, optionMockSvc) @@ -51,13 +52,15 @@ func setupAndExecuteMockingServices(t *testing.T, process func(mock *mocks.Grafa // 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()) { +func InterceptStdout() (*os.File, *os.File, context.CancelFunc) { backupStd := os.Stdout backupErr := os.Stderr - r, w, _ := os.Pipe() + r, w, e := os.Pipe() + if e != nil { + panic(e) + } // Restore streams config.InitGdgConfig("testing", "") - applog.InitializeAppLogger(w, w, false) cleanup := func() { os.Stdout = backupStd os.Stderr = backupErr @@ -65,6 +68,7 @@ func InterceptStdout() (*os.File, *os.File, func()) { } os.Stdout = w os.Stderr = w + applog.InitializeAppLogger(os.Stdout, os.Stderr, true) return r, w, cleanup } diff --git a/test/alerting_contacts_test.go b/test/alerting_contacts_test.go new file mode 100644 index 00000000..12df3fed --- /dev/null +++ b/test/alerting_contacts_test.go @@ -0,0 +1,42 @@ +package test + +import ( + "bytes" + "log/slog" + "os" + "slices" + "testing" + + "github.com/esnet/gdg/pkg/test_tooling" + "github.com/stretchr/testify/assert" +) + +func TestContactsCrud(t *testing.T) { + apiClient, _, _, cleanup := test_tooling.InitTest(t, nil, nil) + defer func() { + err := cleanup() + if err != nil { + slog.Warn("Unable to clean up after alerting contacts crud tests") + } + }() + contactPoints, err := apiClient.ListContactPoints() + assert.NoError(t, err) + assert.Equal(t, len(contactPoints), 0, "Validate initial contact list is empty") + contacts, err := apiClient.UploadContactPoints() + assert.NoError(t, err) + assert.Equal(t, len(contacts), 1) + assert.True(t, slices.Contains(contacts, "discord")) + contactPoints, err = apiClient.ListContactPoints() + assert.NoError(t, err) + assert.Equal(t, len(contactPoints), 1) + data, err := apiClient.DownloadContactPoints() + assert.NoError(t, err) + assert.Equal(t, "test/data/org_main-org/alerting/contacts.json", data) + rawData, err := os.ReadFile(data) + assert.NoError(t, err) + assert.True(t, bytes.Contains(rawData, []byte("discord"))) + assert.False(t, bytes.Contains(rawData, []byte("email receiver"))) + contacts, err = apiClient.ClearContactPoints() + assert.NoError(t, err) + assert.Equal(t, len(contacts), 1) +} diff --git a/test/dashboard_integration_test.go b/test/dashboard_integration_test.go index 9a828f0e..2b7ec8eb 100644 --- a/test/dashboard_integration_test.go +++ b/test/dashboard_integration_test.go @@ -8,7 +8,8 @@ import ( "strings" "testing" - "github.com/esnet/gdg/internal/tools" + "github.com/esnet/gdg/internal/tools/ptr" + "github.com/esnet/gdg/internal/types" "github.com/esnet/gdg/pkg/test_tooling/containers" "github.com/samber/lo" @@ -266,7 +267,7 @@ func TestDashboardPermissionsCrud(t *testing.T) { // Get current Permissions currentPerms, err := apiClient.ListDashboardPermissions(nil) assert.Equal(t, len(currentPerms), 16) - entry := tools.PtrOf(lo.FirstOrEmpty(lo.Filter(currentPerms, func(item types.DashboardAndPermissions, index int) bool { + entry := ptr.Of(lo.FirstOrEmpty(lo.Filter(currentPerms, func(item types.DashboardAndPermissions, index int) bool { return item.Dashboard.Title == "Bandwidth Dashboard" }))) assert.NotNil(t, entry) @@ -282,7 +283,7 @@ func TestDashboardPermissionsCrud(t *testing.T) { assert.Equal(t, len(addPerms), 16) currentPerms, err = apiClient.ListDashboardPermissions(nil) entry = nil - entry = tools.PtrOf(lo.FirstOrEmpty(lo.Filter(currentPerms, func(item types.DashboardAndPermissions, index int) bool { + entry = ptr.Of(lo.FirstOrEmpty(lo.Filter(currentPerms, func(item types.DashboardAndPermissions, index int) bool { return item.Dashboard.Title == "Bandwidth Dashboard" }))) assert.NotNil(t, entry) diff --git a/test/data/org_main-org/alerting/contacts.json b/test/data/org_main-org/alerting/contacts.json new file mode 100644 index 00000000..2bc299a4 --- /dev/null +++ b/test/data/org_main-org/alerting/contacts.json @@ -0,0 +1,16 @@ +[ + { + "name": "discord", + "orgId": 1, + "receivers": [ + { + "settings": { + "url": "https://www.discord.com?q=woot", + "use_discord_username": false + }, + "type": "discord", + "uid": "fdxmqkyb5gl4xb" + } + ] + } +] \ No newline at end of file