From 91097856b59ff5134475b2046565cb99bdb882d8 Mon Sep 17 00:00:00 2001 From: shreyas-goenka <88374338+shreyas-goenka@users.noreply.github.com> Date: Fri, 2 Jun 2023 12:28:35 +0200 Subject: [PATCH 1/9] Add check for path is a directory in filer.ReadDir (#426) ## Tests Integration tests --- internal/filer_test.go | 22 +++++++++++++++++++++- libs/filer/dbfs_client.go | 4 ++++ libs/filer/filer.go | 12 ++++++++++++ libs/filer/workspace_files_client.go | 5 +++++ 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/internal/filer_test.go b/internal/filer_test.go index 0dda1d1bf..5037f7840 100644 --- a/internal/filer_test.go +++ b/internal/filer_test.go @@ -159,6 +159,26 @@ func runFilerReadDirTest(t *testing.T, ctx context.Context, f filer.Filer) { assert.Len(t, entries, 1) assert.Equal(t, "c", entries[0].Name()) assert.True(t, entries[0].IsDir()) + + // Expect an error trying to call ReadDir on a file + _, err = f.ReadDir(ctx, "/hello.txt") + assert.ErrorIs(t, err, fs.ErrInvalid) + + // Expect 0 entries for an empty directory + err = f.Mkdir(ctx, "empty-dir") + require.NoError(t, err) + entries, err = f.ReadDir(ctx, "empty-dir") + assert.NoError(t, err) + assert.Len(t, entries, 0) + + // Expect one entry for a directory with a file in it + err = f.Write(ctx, "dir-with-one-file/my-file.txt", strings.NewReader("abc"), filer.CreateParentDirectories) + require.NoError(t, err) + entries, err = f.ReadDir(ctx, "dir-with-one-file") + assert.NoError(t, err) + assert.Len(t, entries, 1) + assert.Equal(t, entries[0].Name(), "my-file.txt") + assert.False(t, entries[0].IsDir()) } func temporaryWorkspaceDir(t *testing.T, w *databricks.WorkspaceClient) string { @@ -166,7 +186,7 @@ func temporaryWorkspaceDir(t *testing.T, w *databricks.WorkspaceClient) string { me, err := w.CurrentUser.Me(ctx) require.NoError(t, err) - path := fmt.Sprintf("/Users/%s/%s", me.UserName, RandomName("integration-test-filer-wsfs-")) + path := fmt.Sprintf("/Users/%s/%s", me.UserName, RandomName("integration-test-wsfs-")) // Ensure directory exists, but doesn't exist YET! // Otherwise we could inadvertently remove a directory that already exists on cleanup. diff --git a/libs/filer/dbfs_client.go b/libs/filer/dbfs_client.go index c86a80b1e..67878136b 100644 --- a/libs/filer/dbfs_client.go +++ b/libs/filer/dbfs_client.go @@ -222,6 +222,10 @@ func (w *DbfsClient) ReadDir(ctx context.Context, name string) ([]fs.DirEntry, e return nil, err } + if len(res.Files) == 1 && res.Files[0].Path == absPath { + return nil, NotADirectory{absPath} + } + info := make([]fs.DirEntry, len(res.Files)) for i, v := range res.Files { info[i] = dbfsDirEntry{dbfsFileInfo: dbfsFileInfo{fi: v}} diff --git a/libs/filer/filer.go b/libs/filer/filer.go index ff01ea798..58273fff3 100644 --- a/libs/filer/filer.go +++ b/libs/filer/filer.go @@ -50,6 +50,18 @@ func (err NoSuchDirectoryError) Is(other error) bool { return other == fs.ErrNotExist } +type NotADirectory struct { + path string +} + +func (err NotADirectory) Error() string { + return fmt.Sprintf("not a directory: %s", err.path) +} + +func (err NotADirectory) Is(other error) bool { + return other == fs.ErrInvalid +} + // Filer is used to access files in a workspace. // It has implementations for accessing files in WSFS and in DBFS. type Filer interface { diff --git a/libs/filer/workspace_files_client.go b/libs/filer/workspace_files_client.go index 967f9a1de..b06a25146 100644 --- a/libs/filer/workspace_files_client.go +++ b/libs/filer/workspace_files_client.go @@ -222,6 +222,11 @@ func (w *WorkspaceFilesClient) ReadDir(ctx context.Context, name string) ([]fs.D objects, err := w.workspaceClient.Workspace.ListAll(ctx, workspace.ListWorkspaceRequest{ Path: absPath, }) + + if len(objects) == 1 && objects[0].Path == absPath { + return nil, NotADirectory{absPath} + } + if err != nil { // If we got an API error we deal with it below. var aerr *apierr.APIError From a6c9533c1ce6256e02e5f2f5e19bd7712ae19edd Mon Sep 17 00:00:00 2001 From: Serge Smertin <259697+nfx@users.noreply.github.com> Date: Fri, 2 Jun 2023 13:49:39 +0200 Subject: [PATCH 2/9] Add profile on `databricks auth login` (#423) ## Changes - added saving profile to `~/.databrickscfg` whenever we do `databricks auth login`. - we either match profile by account id / canonical host or introduce the new one from deployment name. - fail on multiple profiles with matching accounts or workspace hosts. - overriding `~/.databrickscfg` keeps the (valid) comments, but reformats the file. ## Tests - `make test` - `go run main.go auth login --account-id XXX --host https://accounts.cloud.databricks.com/` - `go run main.go auth token --account-id XXX --host https://accounts.cloud.databricks.com/` - `go run main.go auth login --host https://XXX.cloud.databricks.com/` --- libs/auth/oauth.go | 19 ++- libs/databrickscfg/loader.go | 88 ++++++---- libs/databrickscfg/loader_test.go | 2 +- libs/databrickscfg/ops.go | 122 ++++++++++++++ libs/databrickscfg/ops_test.go | 192 ++++++++++++++++++++++ libs/databrickscfg/testdata/databrickscfg | 4 + 6 files changed, 391 insertions(+), 36 deletions(-) create mode 100644 libs/databrickscfg/ops.go create mode 100644 libs/databrickscfg/ops_test.go diff --git a/libs/auth/oauth.go b/libs/auth/oauth.go index af4b5e096..1171103cb 100644 --- a/libs/auth/oauth.go +++ b/libs/auth/oauth.go @@ -16,6 +16,8 @@ import ( "time" "github.com/databricks/cli/libs/auth/cache" + "github.com/databricks/cli/libs/databrickscfg" + "github.com/databricks/databricks-sdk-go/config" "github.com/databricks/databricks-sdk-go/retries" "github.com/pkg/browser" "golang.org/x/oauth2" @@ -95,6 +97,16 @@ func (a *PersistentAuth) Load(ctx context.Context) (*oauth2.Token, error) { return refreshed, nil } +func (a *PersistentAuth) profileName() string { + // TODO: get profile name from interactive input + if a.AccountID != "" { + return fmt.Sprintf("ACCOUNT-%s", a.AccountID) + } + host := strings.TrimPrefix(a.Host, "https://") + split := strings.Split(host, ".") + return split[0] +} + func (a *PersistentAuth) Challenge(ctx context.Context) error { err := a.init(ctx) if err != nil { @@ -120,7 +132,12 @@ func (a *PersistentAuth) Challenge(ctx context.Context) error { if err != nil { return fmt.Errorf("store: %w", err) } - return nil + return databrickscfg.SaveToProfile(ctx, &config.Config{ + Host: a.Host, + AccountID: a.AccountID, + AuthType: "databricks-cli", + Profile: a.profileName(), + }) } func (a *PersistentAuth) init(ctx context.Context) error { diff --git a/libs/databrickscfg/loader.go b/libs/databrickscfg/loader.go index 087703ff8..8179703a3 100644 --- a/libs/databrickscfg/loader.go +++ b/libs/databrickscfg/loader.go @@ -2,6 +2,7 @@ package databrickscfg import ( "context" + "errors" "fmt" "os" "strings" @@ -13,6 +14,43 @@ import ( var ResolveProfileFromHost = profileFromHostLoader{} +var errNoMatchingProfiles = errors.New("no matching config profiles found") + +type errMultipleProfiles []string + +func (e errMultipleProfiles) Error() string { + return fmt.Sprintf("multiple profiles matched: %s", strings.Join(e, ", ")) +} + +func findMatchingProfile(configFile *config.File, matcher func(*ini.Section) bool) (*ini.Section, error) { + // Look for sections in the configuration file that match the configured host. + var matching []*ini.Section + for _, section := range configFile.Sections() { + if !matcher(section) { + continue + } + matching = append(matching, section) + } + + // If there are no matching sections, we don't do anything. + if len(matching) == 0 { + return nil, errNoMatchingProfiles + } + + // If there are multiple matching sections, let the user know it is impossible + // to unambiguously select a profile to use. + if len(matching) > 1 { + var names errMultipleProfiles + for _, section := range matching { + names = append(names, section.Name()) + } + + return nil, names + } + + return matching[0], nil +} + type profileFromHostLoader struct{} func (l profileFromHostLoader) Name() string { @@ -27,6 +65,7 @@ func (l profileFromHostLoader) Configure(cfg *config.Config) error { return nil } + ctx := context.Background() configFile, err := config.LoadFile(cfg.ConfigFile) if err != nil { if os.IsNotExist(err) { @@ -34,56 +73,37 @@ func (l profileFromHostLoader) Configure(cfg *config.Config) error { } return fmt.Errorf("cannot parse config file: %w", err) } - // Normalized version of the configured host. host := normalizeHost(cfg.Host) - - // Look for sections in the configuration file that match the configured host. - var matching []*ini.Section - for _, section := range configFile.Sections() { - key, err := section.GetKey("host") + match, err := findMatchingProfile(configFile, func(s *ini.Section) bool { + key, err := s.GetKey("host") if err != nil { - log.Tracef(context.Background(), "section %s: %s", section.Name(), err) - continue + log.Tracef(ctx, "section %s: %s", s.Name(), err) + return false } - // Ignore this section if the normalized host doesn't match. - if normalizeHost(key.Value()) != host { - continue - } - - matching = append(matching, section) - } - - // If there are no matching sections, we don't do anything. - if len(matching) == 0 { + // Check if this section matches the normalized host + return normalizeHost(key.Value()) == host + }) + if err == errNoMatchingProfiles { return nil } - - // If there are multiple matching sections, let the user know it is impossible - // to unambiguously select a profile to use. - if len(matching) > 1 { - var names []string - for _, section := range matching { - names = append(names, section.Name()) - } - + if err, ok := err.(errMultipleProfiles); ok { return fmt.Errorf( - "multiple profiles for host %s (%s): please set DATABRICKS_CONFIG_PROFILE to specify one", - host, - strings.Join(names, ", "), - ) + "%s: %w: please set DATABRICKS_CONFIG_PROFILE to specify one", + host, err) + } + if err != nil { + return err } - match := matching[0] - log.Debugf(context.Background(), "Loading profile %s because of host match", match.Name()) + log.Debugf(ctx, "Loading profile %s because of host match", match.Name()) err = config.ConfigAttributes.ResolveFromStringMap(cfg, match.KeysHash()) if err != nil { return fmt.Errorf("%s %s profile: %w", configFile.Path(), match.Name(), err) } return nil - } func (l profileFromHostLoader) isAnyAuthConfigured(cfg *config.Config) bool { diff --git a/libs/databrickscfg/loader_test.go b/libs/databrickscfg/loader_test.go index 59610858c..5fa7f7dd2 100644 --- a/libs/databrickscfg/loader_test.go +++ b/libs/databrickscfg/loader_test.go @@ -126,5 +126,5 @@ func TestLoaderErrorsOnMultipleMatches(t *testing.T) { err := cfg.EnsureResolved() assert.Error(t, err) - assert.ErrorContains(t, err, "multiple profiles for host https://foo (foo1, foo2): ") + assert.ErrorContains(t, err, "https://foo: multiple profiles matched: foo1, foo2") } diff --git a/libs/databrickscfg/ops.go b/libs/databrickscfg/ops.go new file mode 100644 index 000000000..8b4e1a5f3 --- /dev/null +++ b/libs/databrickscfg/ops.go @@ -0,0 +1,122 @@ +package databrickscfg + +import ( + "context" + "fmt" + "os" + "strings" + + "github.com/databricks/cli/libs/log" + "github.com/databricks/databricks-sdk-go/config" + "gopkg.in/ini.v1" +) + +const fileMode = 0o600 + +func loadOrCreateConfigFile(filename string) (*config.File, error) { + if filename == "" { + filename = "~/.databrickscfg" + } + // Expand ~ to home directory, as we need a deterministic name for os.OpenFile + // to work in the cases when ~/.databrickscfg does not exist yet + if strings.HasPrefix(filename, "~") { + homedir, err := os.UserHomeDir() + if err != nil { + return nil, fmt.Errorf("cannot find homedir: %w", err) + } + filename = fmt.Sprintf("%s%s", homedir, filename[1:]) + } + configFile, err := config.LoadFile(filename) + if err != nil && os.IsNotExist(err) { + file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, fileMode) + if err != nil { + return nil, fmt.Errorf("create %s: %w", filename, err) + } + defer file.Close() + configFile, err = config.LoadFile(filename) + if err != nil { + return nil, fmt.Errorf("load created %s: %w", filename, err) + } + } else if err != nil { + return nil, fmt.Errorf("parse %s: %w", filename, err) + } + return configFile, nil +} + +func matchOrCreateSection(ctx context.Context, configFile *config.File, cfg *config.Config) (*ini.Section, error) { + section, err := findMatchingProfile(configFile, func(s *ini.Section) bool { + if cfg.Profile == s.Name() { + return true + } + raw := s.KeysHash() + if cfg.AccountID != "" { + // here we rely on map zerovals for matching with accounts: + // if profile has no account id, the raw["account_id"] will be empty + return cfg.AccountID == raw["account_id"] + } + if cfg.Host == "" { + return false + } + host, ok := raw["host"] + if !ok { + log.Tracef(ctx, "section %s: no host", s.Name()) + return false + } + // Check if this section matches the normalized host + return normalizeHost(host) == normalizeHost(cfg.Host) + }) + if err == errNoMatchingProfiles { + section, err = configFile.NewSection(cfg.Profile) + if err != nil { + return nil, fmt.Errorf("cannot create new profile: %w", err) + } + } else if err != nil { + return nil, err + } + return section, nil +} + +func SaveToProfile(ctx context.Context, cfg *config.Config) error { + configFile, err := loadOrCreateConfigFile(cfg.ConfigFile) + if err != nil { + return err + } + + section, err := matchOrCreateSection(ctx, configFile, cfg) + if err != nil { + return err + } + + // zeroval profile name before adding it to a section + cfg.Profile = "" + cfg.ConfigFile = "" + + // clear old keys in case we're overriding the section + for _, oldKey := range section.KeyStrings() { + section.DeleteKey(oldKey) + } + + for _, attr := range config.ConfigAttributes { + if attr.IsZero(cfg) { + continue + } + key := section.Key(attr.Name) + key.SetValue(attr.GetString(cfg)) + } + + orig, backupErr := os.ReadFile(configFile.Path()) + if len(orig) > 0 && backupErr == nil { + log.Infof(ctx, "Backing up in %s.bak", configFile.Path()) + err = os.WriteFile(configFile.Path()+".bak", orig, fileMode) + if err != nil { + return fmt.Errorf("backup: %w", err) + } + log.Infof(ctx, "Overwriting %s", configFile.Path()) + } else if backupErr != nil { + log.Warnf(ctx, "Failed to backup %s: %v. Proceeding to save", + configFile.Path(), backupErr) + } else { + log.Infof(ctx, "Saving %s", configFile.Path()) + } + return configFile.SaveTo(configFile.Path()) +} diff --git a/libs/databrickscfg/ops_test.go b/libs/databrickscfg/ops_test.go new file mode 100644 index 000000000..64b4fbadf --- /dev/null +++ b/libs/databrickscfg/ops_test.go @@ -0,0 +1,192 @@ +package databrickscfg + +import ( + "context" + "path/filepath" + "testing" + + "github.com/databricks/databricks-sdk-go/config" + "github.com/stretchr/testify/assert" +) + +func TestLoadOrCreate(t *testing.T) { + dir := t.TempDir() + + path := filepath.Join(dir, "databrickscfg") + file, err := loadOrCreateConfigFile(path) + assert.NoError(t, err) + assert.NotNil(t, file) + assert.FileExists(t, path) +} + +func TestLoadOrCreate_NotAllowed(t *testing.T) { + path := "/dev/databrickscfg" + file, err := loadOrCreateConfigFile(path) + assert.Error(t, err) + assert.Nil(t, file) + assert.NoFileExists(t, path) +} + +func TestLoadOrCreate_Bad(t *testing.T) { + path := "testdata/badcfg" + file, err := loadOrCreateConfigFile(path) + assert.Error(t, err) + assert.Nil(t, file) +} + +func TestMatchOrCreateSection_Direct(t *testing.T) { + cfg := &config.Config{ + Profile: "query", + } + file, err := loadOrCreateConfigFile("testdata/databrickscfg") + assert.NoError(t, err) + + ctx := context.Background() + section, err := matchOrCreateSection(ctx, file, cfg) + assert.NoError(t, err) + assert.NotNil(t, section) + assert.Equal(t, "query", section.Name()) +} + +func TestMatchOrCreateSection_AccountID(t *testing.T) { + cfg := &config.Config{ + AccountID: "abc", + } + file, err := loadOrCreateConfigFile("testdata/databrickscfg") + assert.NoError(t, err) + + ctx := context.Background() + section, err := matchOrCreateSection(ctx, file, cfg) + assert.NoError(t, err) + assert.NotNil(t, section) + assert.Equal(t, "acc", section.Name()) +} + +func TestMatchOrCreateSection_NormalizeHost(t *testing.T) { + cfg := &config.Config{ + Host: "https://query/?o=abracadabra", + } + file, err := loadOrCreateConfigFile("testdata/databrickscfg") + assert.NoError(t, err) + + ctx := context.Background() + section, err := matchOrCreateSection(ctx, file, cfg) + assert.NoError(t, err) + assert.NotNil(t, section) + assert.Equal(t, "query", section.Name()) +} + +func TestMatchOrCreateSection_NoProfileOrHost(t *testing.T) { + cfg := &config.Config{} + file, err := loadOrCreateConfigFile("testdata/databrickscfg") + assert.NoError(t, err) + + ctx := context.Background() + _, err = matchOrCreateSection(ctx, file, cfg) + assert.EqualError(t, err, "cannot create new profile: empty section name") +} + +func TestMatchOrCreateSection_MultipleProfiles(t *testing.T) { + cfg := &config.Config{ + Host: "https://foo", + } + file, err := loadOrCreateConfigFile("testdata/databrickscfg") + assert.NoError(t, err) + + ctx := context.Background() + _, err = matchOrCreateSection(ctx, file, cfg) + assert.EqualError(t, err, "multiple profiles matched: foo1, foo2") +} + +func TestMatchOrCreateSection_NewProfile(t *testing.T) { + cfg := &config.Config{ + Host: "https://bar", + Profile: "delirium", + } + file, err := loadOrCreateConfigFile("testdata/databrickscfg") + assert.NoError(t, err) + + ctx := context.Background() + section, err := matchOrCreateSection(ctx, file, cfg) + assert.NoError(t, err) + assert.NotNil(t, section) + assert.Equal(t, "delirium", section.Name()) +} + +func TestSaveToProfile_ErrorOnLoad(t *testing.T) { + ctx := context.Background() + err := SaveToProfile(ctx, &config.Config{ + ConfigFile: "testdata/badcfg", + }) + assert.Error(t, err) +} + +func TestSaveToProfile_ErrorOnMatch(t *testing.T) { + ctx := context.Background() + err := SaveToProfile(ctx, &config.Config{ + Host: "https://foo", + }) + assert.Error(t, err) +} + +func TestSaveToProfile_NewFile(t *testing.T) { + ctx := context.Background() + path := filepath.Join(t.TempDir(), "databrickscfg") + + err := SaveToProfile(ctx, &config.Config{ + ConfigFile: path, + Profile: "abc", + Host: "https://foo", + Token: "xyz", + }) + assert.NoError(t, err) + assert.NoFileExists(t, path+".bak") +} + +func TestSaveToProfile_ClearingPreviousProfile(t *testing.T) { + ctx := context.Background() + path := filepath.Join(t.TempDir(), "databrickscfg") + + err := SaveToProfile(ctx, &config.Config{ + ConfigFile: path, + Profile: "abc", + Host: "https://foo", + Token: "xyz", + }) + assert.NoError(t, err) + + err = SaveToProfile(ctx, &config.Config{ + ConfigFile: path, + Profile: "bcd", + Host: "https://bar", + Token: "zyx", + }) + assert.NoError(t, err) + assert.FileExists(t, path+".bak") + + err = SaveToProfile(ctx, &config.Config{ + ConfigFile: path, + Host: "https://foo", + AuthType: "databricks-cli", + }) + assert.NoError(t, err) + + file, err := loadOrCreateConfigFile(path) + assert.NoError(t, err) + + assert.Len(t, file.Sections(), 3) + assert.True(t, file.HasSection("DEFAULT")) + assert.True(t, file.HasSection("bcd")) + assert.True(t, file.HasSection("bcd")) + + dlft, err := file.GetSection("DEFAULT") + assert.NoError(t, err) + assert.Len(t, dlft.KeysHash(), 0) + + abc, err := file.GetSection("abc") + assert.NoError(t, err) + raw := abc.KeysHash() + assert.Len(t, raw, 2) + assert.Equal(t, "https://foo", raw["host"]) + assert.Equal(t, "databricks-cli", raw["auth_type"]) +} diff --git a/libs/databrickscfg/testdata/databrickscfg b/libs/databrickscfg/testdata/databrickscfg index ad81933e4..ba045c6c2 100644 --- a/libs/databrickscfg/testdata/databrickscfg +++ b/libs/databrickscfg/testdata/databrickscfg @@ -14,6 +14,10 @@ token = query host = https://foo token = foo1 +[acc] +host = https://accounts.cloud.databricks.com +account_id = abc + # Duplicate entry for https://foo [foo2] host = https://foo From f8255f356b152367deb21d557f51401ddc2c19b8 Mon Sep 17 00:00:00 2001 From: Andrew Nester Date: Fri, 2 Jun 2023 14:13:18 +0200 Subject: [PATCH 3/9] Added spinner when loading command prompts (#420) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Changes Added spinner when loading command prompts ## Tests ``` andrew.nester@HFW9Y94129 multiples-tasks % cli jobs get-run ⡿ No RUN_ID argument specified. Loading names for Jobs drop-down.``` --- .codegen/service.go.tmpl | 3 ++ cmd/account/budgets/budgets.go | 6 ++++ cmd/account/credentials/credentials.go | 6 ++++ cmd/account/groups/groups.go | 12 +++++++ .../ip-access-lists/ip-access-lists.go | 6 ++++ cmd/account/log-delivery/log-delivery.go | 3 ++ cmd/account/networks/networks.go | 9 +++++ cmd/account/private-access/private-access.go | 6 ++++ .../service-principals/service-principals.go | 12 +++++++ cmd/account/storage/storage.go | 6 ++++ cmd/account/users/users.go | 12 +++++++ cmd/account/vpc-endpoints/vpc-endpoints.go | 9 +++++ cmd/account/workspaces/workspaces.go | 12 +++++++ cmd/workspace/alerts/alerts.go | 6 ++++ .../cluster-policies/cluster-policies.go | 9 +++++ cmd/workspace/clusters/clusters.go | 30 ++++++++++++++++ cmd/workspace/dashboards/dashboards.go | 9 +++++ .../git-credentials/git-credentials.go | 12 +++++++ .../global-init-scripts.go | 6 ++++ cmd/workspace/groups/groups.go | 12 +++++++ .../instance-pools/instance-pools.go | 6 ++++ .../ip-access-lists/ip-access-lists.go | 6 ++++ cmd/workspace/jobs/jobs.go | 34 +++++++++++++++++++ cmd/workspace/metastores/metastores.go | 12 +++++++ .../model-registry/model-registry.go | 4 +-- cmd/workspace/pipelines/pipelines.go | 24 +++++++++++++ cmd/workspace/providers/providers.go | 12 +++++++ cmd/workspace/queries/queries.go | 12 +++++++ cmd/workspace/recipients/recipients.go | 12 +++++++ cmd/workspace/repos/repos.go | 9 +++++ cmd/workspace/schemas/schemas.go | 9 +++++ .../service-principals/service-principals.go | 12 +++++++ cmd/workspace/tables/tables.go | 9 +++++ .../token-management/token-management.go | 6 ++++ cmd/workspace/tokens/tokens.go | 3 ++ cmd/workspace/users/users.go | 12 +++++++ cmd/workspace/volumes/volumes.go | 9 +++++ cmd/workspace/warehouses/warehouses.go | 15 ++++++++ cmd/workspace/workspace/workspace.go | 15 ++++++++ 39 files changed, 405 insertions(+), 2 deletions(-) diff --git a/.codegen/service.go.tmpl b/.codegen/service.go.tmpl index 3cc1943fc..72aea3705 100644 --- a/.codegen/service.go.tmpl +++ b/.codegen/service.go.tmpl @@ -96,7 +96,10 @@ var {{.CamelName}}Cmd = &cobra.Command{ } else { {{- if $hasIdPrompt}} if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No{{range .Request.RequiredFields}} {{.ConstantName}}{{end}} argument specified. Loading names for {{.Service.TitleName}} drop-down." names, err := {{if .Service.IsAccounts}}a{{else}}w{{end}}.{{(.Service.TrimPrefix "account").PascalName}}.{{.Service.List.NamedIdMap.PascalName}}(ctx{{if .Service.List.Request}}, {{.Service.Package.Name}}.{{.Service.List.Request.PascalName}}{}{{end}}) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/account/budgets/budgets.go b/cmd/account/budgets/budgets.go index dedcdd802..8edbe0a6d 100755 --- a/cmd/account/budgets/budgets.go +++ b/cmd/account/budgets/budgets.go @@ -94,7 +94,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No BUDGET_ID argument specified. Loading names for Budgets drop-down." names, err := a.Budgets.BudgetWithStatusNameToBudgetIdMap(ctx) + close(promptSpinner) if err != nil { return err } @@ -150,7 +153,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No BUDGET_ID argument specified. Loading names for Budgets drop-down." names, err := a.Budgets.BudgetWithStatusNameToBudgetIdMap(ctx) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/account/credentials/credentials.go b/cmd/account/credentials/credentials.go index 1f3f52614..81f587709 100755 --- a/cmd/account/credentials/credentials.go +++ b/cmd/account/credentials/credentials.go @@ -113,7 +113,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No CREDENTIALS_ID argument specified. Loading names for Credentials drop-down." names, err := a.Credentials.CredentialCredentialsNameToCredentialsIdMap(ctx) + close(promptSpinner) if err != nil { return err } @@ -169,7 +172,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No CREDENTIALS_ID argument specified. Loading names for Credentials drop-down." names, err := a.Credentials.CredentialCredentialsNameToCredentialsIdMap(ctx) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/account/groups/groups.go b/cmd/account/groups/groups.go index f76711d00..143bbf92c 100755 --- a/cmd/account/groups/groups.go +++ b/cmd/account/groups/groups.go @@ -111,7 +111,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Account Groups drop-down." names, err := a.Groups.GroupDisplayNameToIdMap(ctx, iam.ListAccountGroupsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -166,7 +169,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Account Groups drop-down." names, err := a.Groups.GroupDisplayNameToIdMap(ctx, iam.ListAccountGroupsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -278,7 +284,10 @@ var patchCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Account Groups drop-down." names, err := a.Groups.GroupDisplayNameToIdMap(ctx, iam.ListAccountGroupsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -341,7 +350,10 @@ var updateCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Account Groups drop-down." names, err := a.Groups.GroupDisplayNameToIdMap(ctx, iam.ListAccountGroupsRequest{}) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/account/ip-access-lists/ip-access-lists.go b/cmd/account/ip-access-lists/ip-access-lists.go index e525c57ea..d52917afe 100755 --- a/cmd/account/ip-access-lists/ip-access-lists.go +++ b/cmd/account/ip-access-lists/ip-access-lists.go @@ -132,7 +132,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No IP_ACCESS_LIST_ID argument specified. Loading names for Account Ip Access Lists drop-down." names, err := a.IpAccessLists.IpAccessListInfoLabelToListIdMap(ctx) + close(promptSpinner) if err != nil { return err } @@ -187,7 +190,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No IP_ACCESS_LIST_ID argument specified. Loading names for Account Ip Access Lists drop-down." names, err := a.IpAccessLists.IpAccessListInfoLabelToListIdMap(ctx) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/account/log-delivery/log-delivery.go b/cmd/account/log-delivery/log-delivery.go index a38a661ad..a20972ce7 100755 --- a/cmd/account/log-delivery/log-delivery.go +++ b/cmd/account/log-delivery/log-delivery.go @@ -183,7 +183,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No LOG_DELIVERY_CONFIGURATION_ID argument specified. Loading names for Log Delivery drop-down." names, err := a.LogDelivery.LogDeliveryConfigurationConfigNameToConfigIdMap(ctx, billing.ListLogDeliveryRequest{}) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/account/networks/networks.go b/cmd/account/networks/networks.go index 04355e5a3..9a0b77391 100755 --- a/cmd/account/networks/networks.go +++ b/cmd/account/networks/networks.go @@ -58,7 +58,10 @@ var createCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No NETWORK_NAME argument specified. Loading names for Networks drop-down." names, err := a.Networks.NetworkNetworkNameToNetworkIdMap(ctx) + close(promptSpinner) if err != nil { return err } @@ -118,7 +121,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No NETWORK_ID argument specified. Loading names for Networks drop-down." names, err := a.Networks.NetworkNetworkNameToNetworkIdMap(ctx) + close(promptSpinner) if err != nil { return err } @@ -174,7 +180,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No NETWORK_ID argument specified. Loading names for Networks drop-down." names, err := a.Networks.NetworkNetworkNameToNetworkIdMap(ctx) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/account/private-access/private-access.go b/cmd/account/private-access/private-access.go index e7235f37c..0a6f06e50 100755 --- a/cmd/account/private-access/private-access.go +++ b/cmd/account/private-access/private-access.go @@ -123,7 +123,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No PRIVATE_ACCESS_SETTINGS_ID argument specified. Loading names for Private Access drop-down." names, err := a.PrivateAccess.PrivateAccessSettingsPrivateAccessSettingsNameToPrivateAccessSettingsIdMap(ctx) + close(promptSpinner) if err != nil { return err } @@ -185,7 +188,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No PRIVATE_ACCESS_SETTINGS_ID argument specified. Loading names for Private Access drop-down." names, err := a.PrivateAccess.PrivateAccessSettingsPrivateAccessSettingsNameToPrivateAccessSettingsIdMap(ctx) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/account/service-principals/service-principals.go b/cmd/account/service-principals/service-principals.go index 6432ed2d5..f2bce37ab 100755 --- a/cmd/account/service-principals/service-principals.go +++ b/cmd/account/service-principals/service-principals.go @@ -110,7 +110,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Account Service Principals drop-down." names, err := a.ServicePrincipals.ServicePrincipalDisplayNameToIdMap(ctx, iam.ListAccountServicePrincipalsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -166,7 +169,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Account Service Principals drop-down." names, err := a.ServicePrincipals.ServicePrincipalDisplayNameToIdMap(ctx, iam.ListAccountServicePrincipalsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -279,7 +285,10 @@ var patchCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Account Service Principals drop-down." names, err := a.ServicePrincipals.ServicePrincipalDisplayNameToIdMap(ctx, iam.ListAccountServicePrincipalsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -345,7 +354,10 @@ var updateCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Account Service Principals drop-down." names, err := a.ServicePrincipals.ServicePrincipalDisplayNameToIdMap(ctx, iam.ListAccountServicePrincipalsRequest{}) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/account/storage/storage.go b/cmd/account/storage/storage.go index a8512ffa3..023d5894a 100755 --- a/cmd/account/storage/storage.go +++ b/cmd/account/storage/storage.go @@ -109,7 +109,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No STORAGE_CONFIGURATION_ID argument specified. Loading names for Storage drop-down." names, err := a.Storage.StorageConfigurationStorageConfigurationNameToStorageConfigurationIdMap(ctx) + close(promptSpinner) if err != nil { return err } @@ -164,7 +167,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No STORAGE_CONFIGURATION_ID argument specified. Loading names for Storage drop-down." names, err := a.Storage.StorageConfigurationStorageConfigurationNameToStorageConfigurationIdMap(ctx) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/account/users/users.go b/cmd/account/users/users.go index 6ccb39f53..faf240d8e 100755 --- a/cmd/account/users/users.go +++ b/cmd/account/users/users.go @@ -119,7 +119,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Account Users drop-down." names, err := a.Users.UserUserNameToIdMap(ctx, iam.ListAccountUsersRequest{}) + close(promptSpinner) if err != nil { return err } @@ -174,7 +177,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Account Users drop-down." names, err := a.Users.UserUserNameToIdMap(ctx, iam.ListAccountUsersRequest{}) + close(promptSpinner) if err != nil { return err } @@ -287,7 +293,10 @@ var patchCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Account Users drop-down." names, err := a.Users.UserUserNameToIdMap(ctx, iam.ListAccountUsersRequest{}) + close(promptSpinner) if err != nil { return err } @@ -353,7 +362,10 @@ var updateCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Account Users drop-down." names, err := a.Users.UserUserNameToIdMap(ctx, iam.ListAccountUsersRequest{}) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/account/vpc-endpoints/vpc-endpoints.go b/cmd/account/vpc-endpoints/vpc-endpoints.go index 0572c44c3..295d7621f 100755 --- a/cmd/account/vpc-endpoints/vpc-endpoints.go +++ b/cmd/account/vpc-endpoints/vpc-endpoints.go @@ -65,7 +65,10 @@ var createCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No VPC_ENDPOINT_NAME argument specified. Loading names for Vpc Endpoints drop-down." names, err := a.VpcEndpoints.VpcEndpointVpcEndpointNameToVpcEndpointIdMap(ctx) + close(promptSpinner) if err != nil { return err } @@ -128,7 +131,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No VPC_ENDPOINT_ID argument specified. Loading names for Vpc Endpoints drop-down." names, err := a.VpcEndpoints.VpcEndpointVpcEndpointNameToVpcEndpointIdMap(ctx) + close(promptSpinner) if err != nil { return err } @@ -187,7 +193,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No VPC_ENDPOINT_ID argument specified. Loading names for Vpc Endpoints drop-down." names, err := a.VpcEndpoints.VpcEndpointVpcEndpointNameToVpcEndpointIdMap(ctx) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/account/workspaces/workspaces.go b/cmd/account/workspaces/workspaces.go index f611fa8d2..4dbfe24e4 100755 --- a/cmd/account/workspaces/workspaces.go +++ b/cmd/account/workspaces/workspaces.go @@ -84,7 +84,10 @@ var createCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No WORKSPACE_NAME argument specified. Loading names for Workspaces drop-down." names, err := a.Workspaces.WorkspaceWorkspaceNameToWorkspaceIdMap(ctx) + close(promptSpinner) if err != nil { return err } @@ -163,7 +166,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No WORKSPACE_ID argument specified. Loading names for Workspaces drop-down." names, err := a.Workspaces.WorkspaceWorkspaceNameToWorkspaceIdMap(ctx) + close(promptSpinner) if err != nil { return err } @@ -234,7 +240,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No WORKSPACE_ID argument specified. Loading names for Workspaces drop-down." names, err := a.Workspaces.WorkspaceWorkspaceNameToWorkspaceIdMap(ctx) + close(promptSpinner) if err != nil { return err } @@ -445,7 +454,10 @@ var updateCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No WORKSPACE_ID argument specified. Loading names for Workspaces drop-down." names, err := a.Workspaces.WorkspaceWorkspaceNameToWorkspaceIdMap(ctx) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/workspace/alerts/alerts.go b/cmd/workspace/alerts/alerts.go index cd52408f1..e1485d31a 100755 --- a/cmd/workspace/alerts/alerts.go +++ b/cmd/workspace/alerts/alerts.go @@ -106,7 +106,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ALERT_ID argument specified. Loading names for Alerts drop-down." names, err := w.Alerts.AlertNameToIdMap(ctx) + close(promptSpinner) if err != nil { return err } @@ -161,7 +164,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ALERT_ID argument specified. Loading names for Alerts drop-down." names, err := w.Alerts.AlertNameToIdMap(ctx) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/workspace/cluster-policies/cluster-policies.go b/cmd/workspace/cluster-policies/cluster-policies.go index 7fbdce9bb..dce0a604f 100755 --- a/cmd/workspace/cluster-policies/cluster-policies.go +++ b/cmd/workspace/cluster-policies/cluster-policies.go @@ -78,7 +78,10 @@ var createCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No NAME argument specified. Loading names for Cluster Policies drop-down." names, err := w.ClusterPolicies.PolicyNameToPolicyIdMap(ctx, compute.ListClusterPoliciesRequest{}) + close(promptSpinner) if err != nil { return err } @@ -134,7 +137,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No POLICY_ID argument specified. Loading names for Cluster Policies drop-down." names, err := w.ClusterPolicies.PolicyNameToPolicyIdMap(ctx, compute.ListClusterPoliciesRequest{}) + close(promptSpinner) if err != nil { return err } @@ -245,7 +251,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No POLICY_ID argument specified. Loading names for Cluster Policies drop-down." names, err := w.ClusterPolicies.PolicyNameToPolicyIdMap(ctx, compute.ListClusterPoliciesRequest{}) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/workspace/clusters/clusters.go b/cmd/workspace/clusters/clusters.go index d609f573a..10155161c 100755 --- a/cmd/workspace/clusters/clusters.go +++ b/cmd/workspace/clusters/clusters.go @@ -169,7 +169,10 @@ var createCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No SPARK_VERSION argument specified. Loading names for Clusters drop-down." names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{}) + close(promptSpinner) if err != nil { return err } @@ -249,7 +252,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No CLUSTER_ID argument specified. Loading names for Clusters drop-down." names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{}) + close(promptSpinner) if err != nil { return err } @@ -437,7 +443,10 @@ var eventsCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No CLUSTER_ID argument specified. Loading names for Clusters drop-down." names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{}) + close(promptSpinner) if err != nil { return err } @@ -498,7 +507,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No CLUSTER_ID argument specified. Loading names for Clusters drop-down." names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{}) + close(promptSpinner) if err != nil { return err } @@ -671,7 +683,10 @@ var permanentDeleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No CLUSTER_ID argument specified. Loading names for Clusters drop-down." names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{}) + close(promptSpinner) if err != nil { return err } @@ -728,7 +743,10 @@ var pinCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No CLUSTER_ID argument specified. Loading names for Clusters drop-down." names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{}) + close(promptSpinner) if err != nil { return err } @@ -792,7 +810,10 @@ var resizeCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No CLUSTER_ID argument specified. Loading names for Clusters drop-down." names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{}) + close(promptSpinner) if err != nil { return err } @@ -872,7 +893,10 @@ var restartCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No CLUSTER_ID argument specified. Loading names for Clusters drop-down." names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{}) + close(promptSpinner) if err != nil { return err } @@ -984,7 +1008,10 @@ var startCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No CLUSTER_ID argument specified. Loading names for Clusters drop-down." names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{}) + close(promptSpinner) if err != nil { return err } @@ -1058,7 +1085,10 @@ var unpinCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No CLUSTER_ID argument specified. Loading names for Clusters drop-down." names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{}) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/workspace/dashboards/dashboards.go b/cmd/workspace/dashboards/dashboards.go index b2f21d574..b7b1fa1c8 100755 --- a/cmd/workspace/dashboards/dashboards.go +++ b/cmd/workspace/dashboards/dashboards.go @@ -105,7 +105,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No DASHBOARD_ID argument specified. Loading names for Dashboards drop-down." names, err := w.Dashboards.DashboardNameToIdMap(ctx, sql.ListDashboardsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -161,7 +164,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No DASHBOARD_ID argument specified. Loading names for Dashboards drop-down." names, err := w.Dashboards.DashboardNameToIdMap(ctx, sql.ListDashboardsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -268,7 +274,10 @@ var restoreCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No DASHBOARD_ID argument specified. Loading names for Dashboards drop-down." names, err := w.Dashboards.DashboardNameToIdMap(ctx, sql.ListDashboardsRequest{}) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/workspace/git-credentials/git-credentials.go b/cmd/workspace/git-credentials/git-credentials.go index 3cad28471..ea7242da9 100755 --- a/cmd/workspace/git-credentials/git-credentials.go +++ b/cmd/workspace/git-credentials/git-credentials.go @@ -60,7 +60,10 @@ var createCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No GIT_PROVIDER argument specified. Loading names for Git Credentials drop-down." names, err := w.GitCredentials.CredentialInfoGitProviderToCredentialIdMap(ctx) + close(promptSpinner) if err != nil { return err } @@ -115,7 +118,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No CREDENTIAL_ID argument specified. Loading names for Git Credentials drop-down." names, err := w.GitCredentials.CredentialInfoGitProviderToCredentialIdMap(ctx) + close(promptSpinner) if err != nil { return err } @@ -173,7 +179,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No CREDENTIAL_ID argument specified. Loading names for Git Credentials drop-down." names, err := w.GitCredentials.CredentialInfoGitProviderToCredentialIdMap(ctx) + close(promptSpinner) if err != nil { return err } @@ -263,7 +272,10 @@ var updateCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No CREDENTIAL_ID argument specified. Loading names for Git Credentials drop-down." names, err := w.GitCredentials.CredentialInfoGitProviderToCredentialIdMap(ctx) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/workspace/global-init-scripts/global-init-scripts.go b/cmd/workspace/global-init-scripts/global-init-scripts.go index 9df0596a0..090a2b352 100755 --- a/cmd/workspace/global-init-scripts/global-init-scripts.go +++ b/cmd/workspace/global-init-scripts/global-init-scripts.go @@ -109,7 +109,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No SCRIPT_ID argument specified. Loading names for Global Init Scripts drop-down." names, err := w.GlobalInitScripts.GlobalInitScriptDetailsNameToScriptIdMap(ctx) + close(promptSpinner) if err != nil { return err } @@ -164,7 +167,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No SCRIPT_ID argument specified. Loading names for Global Init Scripts drop-down." names, err := w.GlobalInitScripts.GlobalInitScriptDetailsNameToScriptIdMap(ctx) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/workspace/groups/groups.go b/cmd/workspace/groups/groups.go index 3bfc83dba..9f85cdf33 100755 --- a/cmd/workspace/groups/groups.go +++ b/cmd/workspace/groups/groups.go @@ -111,7 +111,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Groups drop-down." names, err := w.Groups.GroupDisplayNameToIdMap(ctx, iam.ListGroupsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -166,7 +169,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Groups drop-down." names, err := w.Groups.GroupDisplayNameToIdMap(ctx, iam.ListGroupsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -278,7 +284,10 @@ var patchCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Groups drop-down." names, err := w.Groups.GroupDisplayNameToIdMap(ctx, iam.ListGroupsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -341,7 +350,10 @@ var updateCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Groups drop-down." names, err := w.Groups.GroupDisplayNameToIdMap(ctx, iam.ListGroupsRequest{}) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/workspace/instance-pools/instance-pools.go b/cmd/workspace/instance-pools/instance-pools.go index 7d39cfd80..d78ae9396 100755 --- a/cmd/workspace/instance-pools/instance-pools.go +++ b/cmd/workspace/instance-pools/instance-pools.go @@ -128,7 +128,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No INSTANCE_POOL_ID argument specified. Loading names for Instance Pools drop-down." names, err := w.InstancePools.InstancePoolAndStatsInstancePoolNameToInstancePoolIdMap(ctx) + close(promptSpinner) if err != nil { return err } @@ -245,7 +248,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No INSTANCE_POOL_ID argument specified. Loading names for Instance Pools drop-down." names, err := w.InstancePools.InstancePoolAndStatsInstancePoolNameToInstancePoolIdMap(ctx) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/workspace/ip-access-lists/ip-access-lists.go b/cmd/workspace/ip-access-lists/ip-access-lists.go index 6e46c47bd..e29339747 100755 --- a/cmd/workspace/ip-access-lists/ip-access-lists.go +++ b/cmd/workspace/ip-access-lists/ip-access-lists.go @@ -133,7 +133,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No IP_ACCESS_LIST_ID argument specified. Loading names for Ip Access Lists drop-down." names, err := w.IpAccessLists.IpAccessListInfoLabelToListIdMap(ctx) + close(promptSpinner) if err != nil { return err } @@ -188,7 +191,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No IP_ACCESS_LIST_ID argument specified. Loading names for Ip Access Lists drop-down." names, err := w.IpAccessLists.IpAccessListInfoLabelToListIdMap(ctx) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/workspace/jobs/jobs.go b/cmd/workspace/jobs/jobs.go index 2d8dbd0de..601293eea 100755 --- a/cmd/workspace/jobs/jobs.go +++ b/cmd/workspace/jobs/jobs.go @@ -69,7 +69,10 @@ var cancelAllRunsCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No JOB_ID argument specified. Loading names for Jobs drop-down." names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -133,7 +136,10 @@ var cancelRunCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No RUN_ID argument specified. Loading names for Jobs drop-down." names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -203,6 +209,7 @@ func init() { createCmd.Flags().IntVar(&createReq.MaxConcurrentRuns, "max-concurrent-runs", createReq.MaxConcurrentRuns, `An optional maximum allowed number of concurrent runs of the job.`) createCmd.Flags().StringVar(&createReq.Name, "name", createReq.Name, `An optional name for the job.`) // TODO: complex arg: notification_settings + // TODO: complex arg: run_as // TODO: complex arg: schedule // TODO: map via StringToStringVar: tags // TODO: array: tasks @@ -278,7 +285,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No JOB_ID argument specified. Loading names for Jobs drop-down." names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -336,7 +346,10 @@ var deleteRunCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No RUN_ID argument specified. Loading names for Jobs drop-down." names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -396,7 +409,10 @@ var exportRunCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No RUN_ID argument specified. Loading names for Jobs drop-down." names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -454,7 +470,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No JOB_ID argument specified. Loading names for Jobs drop-down." names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -519,7 +538,10 @@ var getRunCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No RUN_ID argument specified. Loading names for Jobs drop-down." names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -586,7 +608,10 @@ var getRunOutputCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No RUN_ID argument specified. Loading names for Jobs drop-down." names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -772,7 +797,10 @@ var repairRunCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No RUN_ID argument specified. Loading names for Jobs drop-down." names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -918,7 +946,10 @@ var runNowCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No JOB_ID argument specified. Loading names for Jobs drop-down." names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -1092,7 +1123,10 @@ var updateCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No JOB_ID argument specified. Loading names for Jobs drop-down." names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{}) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/workspace/metastores/metastores.go b/cmd/workspace/metastores/metastores.go index f1cc68e6d..589140a06 100755 --- a/cmd/workspace/metastores/metastores.go +++ b/cmd/workspace/metastores/metastores.go @@ -196,7 +196,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Metastores drop-down." names, err := w.Metastores.MetastoreInfoNameToMetastoreIdMap(ctx) + close(promptSpinner) if err != nil { return err } @@ -252,7 +255,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Metastores drop-down." names, err := w.Metastores.MetastoreInfoNameToMetastoreIdMap(ctx) + close(promptSpinner) if err != nil { return err } @@ -477,7 +483,10 @@ var updateCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Metastores drop-down." names, err := w.Metastores.MetastoreInfoNameToMetastoreIdMap(ctx) + close(promptSpinner) if err != nil { return err } @@ -538,7 +547,10 @@ var updateAssignmentCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No WORKSPACE_ID argument specified. Loading names for Metastores drop-down." names, err := w.Metastores.MetastoreInfoNameToMetastoreIdMap(ctx) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/workspace/model-registry/model-registry.go b/cmd/workspace/model-registry/model-registry.go index 3bda9e6f0..1bfff481a 100755 --- a/cmd/workspace/model-registry/model-registry.go +++ b/cmd/workspace/model-registry/model-registry.go @@ -605,8 +605,8 @@ func init() { var deleteTransitionRequestCmd = &cobra.Command{ Use: "delete-transition-request NAME VERSION STAGE CREATOR", - Short: `Delete a ransition request.`, - Long: `Delete a ransition request. + Short: `Delete a transition request.`, + Long: `Delete a transition request. Cancels a model version stage transition request.`, diff --git a/cmd/workspace/pipelines/pipelines.go b/cmd/workspace/pipelines/pipelines.go index b65af4d74..1d2871749 100755 --- a/cmd/workspace/pipelines/pipelines.go +++ b/cmd/workspace/pipelines/pipelines.go @@ -131,7 +131,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No PIPELINE_ID argument specified. Loading names for Pipelines drop-down." names, err := w.Pipelines.PipelineStateInfoNameToPipelineIdMap(ctx, pipelines.ListPipelinesRequest{}) + close(promptSpinner) if err != nil { return err } @@ -189,7 +192,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No PIPELINE_ID argument specified. Loading names for Pipelines drop-down." names, err := w.Pipelines.PipelineStateInfoNameToPipelineIdMap(ctx, pipelines.ListPipelinesRequest{}) + close(promptSpinner) if err != nil { return err } @@ -298,7 +304,10 @@ var listPipelineEventsCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No PIPELINE_ID argument specified. Loading names for Pipelines drop-down." names, err := w.Pipelines.PipelineStateInfoNameToPipelineIdMap(ctx, pipelines.ListPipelinesRequest{}) + close(promptSpinner) if err != nil { return err } @@ -409,7 +418,10 @@ var listUpdatesCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No PIPELINE_ID argument specified. Loading names for Pipelines drop-down." names, err := w.Pipelines.PipelineStateInfoNameToPipelineIdMap(ctx, pipelines.ListPipelinesRequest{}) + close(promptSpinner) if err != nil { return err } @@ -469,7 +481,10 @@ var resetCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No PIPELINE_ID argument specified. Loading names for Pipelines drop-down." names, err := w.Pipelines.PipelineStateInfoNameToPipelineIdMap(ctx, pipelines.ListPipelinesRequest{}) + close(promptSpinner) if err != nil { return err } @@ -546,7 +561,10 @@ var startUpdateCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No PIPELINE_ID argument specified. Loading names for Pipelines drop-down." names, err := w.Pipelines.PipelineStateInfoNameToPipelineIdMap(ctx, pipelines.ListPipelinesRequest{}) + close(promptSpinner) if err != nil { return err } @@ -606,7 +624,10 @@ var stopCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No PIPELINE_ID argument specified. Loading names for Pipelines drop-down." names, err := w.Pipelines.PipelineStateInfoNameToPipelineIdMap(ctx, pipelines.ListPipelinesRequest{}) + close(promptSpinner) if err != nil { return err } @@ -698,7 +719,10 @@ var updateCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No PIPELINE_ID argument specified. Loading names for Pipelines drop-down." names, err := w.Pipelines.PipelineStateInfoNameToPipelineIdMap(ctx, pipelines.ListPipelinesRequest{}) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/workspace/providers/providers.go b/cmd/workspace/providers/providers.go index 21a85ff13..c9dd3cd0a 100755 --- a/cmd/workspace/providers/providers.go +++ b/cmd/workspace/providers/providers.go @@ -106,7 +106,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No NAME argument specified. Loading names for Providers drop-down." names, err := w.Providers.ProviderInfoNameToMetastoreIdMap(ctx, sharing.ListProvidersRequest{}) + close(promptSpinner) if err != nil { return err } @@ -163,7 +166,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No NAME argument specified. Loading names for Providers drop-down." names, err := w.Providers.ProviderInfoNameToMetastoreIdMap(ctx, sharing.ListProvidersRequest{}) + close(promptSpinner) if err != nil { return err } @@ -272,7 +278,10 @@ var listSharesCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No NAME argument specified. Loading names for Providers drop-down." names, err := w.Providers.ProviderInfoNameToMetastoreIdMap(ctx, sharing.ListProvidersRequest{}) + close(promptSpinner) if err != nil { return err } @@ -335,7 +344,10 @@ var updateCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No NAME argument specified. Loading names for Providers drop-down." names, err := w.Providers.ProviderInfoNameToMetastoreIdMap(ctx, sharing.ListProvidersRequest{}) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/workspace/queries/queries.go b/cmd/workspace/queries/queries.go index 1c81c704c..fa83408aa 100755 --- a/cmd/workspace/queries/queries.go +++ b/cmd/workspace/queries/queries.go @@ -116,7 +116,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No QUERY_ID argument specified. Loading names for Queries drop-down." names, err := w.Queries.QueryNameToIdMap(ctx, sql.ListQueriesRequest{}) + close(promptSpinner) if err != nil { return err } @@ -172,7 +175,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No QUERY_ID argument specified. Loading names for Queries drop-down." names, err := w.Queries.QueryNameToIdMap(ctx, sql.ListQueriesRequest{}) + close(promptSpinner) if err != nil { return err } @@ -281,7 +287,10 @@ var restoreCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No QUERY_ID argument specified. Loading names for Queries drop-down." names, err := w.Queries.QueryNameToIdMap(ctx, sql.ListQueriesRequest{}) + close(promptSpinner) if err != nil { return err } @@ -344,7 +353,10 @@ var updateCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No QUERY_ID argument specified. Loading names for Queries drop-down." names, err := w.Queries.QueryNameToIdMap(ctx, sql.ListQueriesRequest{}) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/workspace/recipients/recipients.go b/cmd/workspace/recipients/recipients.go index 6ccbece9d..2f907a6d8 100755 --- a/cmd/workspace/recipients/recipients.go +++ b/cmd/workspace/recipients/recipients.go @@ -111,7 +111,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No NAME argument specified. Loading names for Recipients drop-down." names, err := w.Recipients.RecipientInfoNameToMetastoreIdMap(ctx, sharing.ListRecipientsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -168,7 +171,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No NAME argument specified. Loading names for Recipients drop-down." names, err := w.Recipients.RecipientInfoNameToMetastoreIdMap(ctx, sharing.ListRecipientsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -329,7 +335,10 @@ var sharePermissionsCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No NAME argument specified. Loading names for Recipients drop-down." names, err := w.Recipients.RecipientInfoNameToMetastoreIdMap(ctx, sharing.ListRecipientsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -392,7 +401,10 @@ var updateCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No NAME argument specified. Loading names for Recipients drop-down." names, err := w.Recipients.RecipientInfoNameToMetastoreIdMap(ctx, sharing.ListRecipientsRequest{}) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/workspace/repos/repos.go b/cmd/workspace/repos/repos.go index 403c8a957..d3e95fc78 100755 --- a/cmd/workspace/repos/repos.go +++ b/cmd/workspace/repos/repos.go @@ -112,7 +112,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No REPO_ID argument specified. Loading names for Repos drop-down." names, err := w.Repos.RepoInfoPathToIdMap(ctx, workspace.ListReposRequest{}) + close(promptSpinner) if err != nil { return err } @@ -170,7 +173,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No REPO_ID argument specified. Loading names for Repos drop-down." names, err := w.Repos.RepoInfoPathToIdMap(ctx, workspace.ListReposRequest{}) + close(promptSpinner) if err != nil { return err } @@ -284,7 +290,10 @@ var updateCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No REPO_ID argument specified. Loading names for Repos drop-down." names, err := w.Repos.RepoInfoPathToIdMap(ctx, workspace.ListReposRequest{}) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/workspace/schemas/schemas.go b/cmd/workspace/schemas/schemas.go index 16e0387a9..c4bce9dd5 100755 --- a/cmd/workspace/schemas/schemas.go +++ b/cmd/workspace/schemas/schemas.go @@ -109,7 +109,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No FULL_NAME argument specified. Loading names for Schemas drop-down." names, err := w.Schemas.SchemaInfoNameToFullNameMap(ctx, catalog.ListSchemasRequest{}) + close(promptSpinner) if err != nil { return err } @@ -166,7 +169,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No FULL_NAME argument specified. Loading names for Schemas drop-down." names, err := w.Schemas.SchemaInfoNameToFullNameMap(ctx, catalog.ListSchemasRequest{}) + close(promptSpinner) if err != nil { return err } @@ -282,7 +288,10 @@ var updateCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No FULL_NAME argument specified. Loading names for Schemas drop-down." names, err := w.Schemas.SchemaInfoNameToFullNameMap(ctx, catalog.ListSchemasRequest{}) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/workspace/service-principals/service-principals.go b/cmd/workspace/service-principals/service-principals.go index 675ce8991..ea52d52a4 100755 --- a/cmd/workspace/service-principals/service-principals.go +++ b/cmd/workspace/service-principals/service-principals.go @@ -110,7 +110,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Service Principals drop-down." names, err := w.ServicePrincipals.ServicePrincipalDisplayNameToIdMap(ctx, iam.ListServicePrincipalsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -166,7 +169,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Service Principals drop-down." names, err := w.ServicePrincipals.ServicePrincipalDisplayNameToIdMap(ctx, iam.ListServicePrincipalsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -279,7 +285,10 @@ var patchCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Service Principals drop-down." names, err := w.ServicePrincipals.ServicePrincipalDisplayNameToIdMap(ctx, iam.ListServicePrincipalsRequest{}) + close(promptSpinner) if err != nil { return err } @@ -345,7 +354,10 @@ var updateCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Service Principals drop-down." names, err := w.ServicePrincipals.ServicePrincipalDisplayNameToIdMap(ctx, iam.ListServicePrincipalsRequest{}) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/workspace/tables/tables.go b/cmd/workspace/tables/tables.go index 622cbe8a9..c4f0dd80f 100755 --- a/cmd/workspace/tables/tables.go +++ b/cmd/workspace/tables/tables.go @@ -61,7 +61,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No FULL_NAME argument specified. Loading names for Tables drop-down." names, err := w.Tables.TableInfoNameToTableIdMap(ctx, catalog.ListTablesRequest{}) + close(promptSpinner) if err != nil { return err } @@ -122,7 +125,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No FULL_NAME argument specified. Loading names for Tables drop-down." names, err := w.Tables.TableInfoNameToTableIdMap(ctx, catalog.ListTablesRequest{}) + close(promptSpinner) if err != nil { return err } @@ -250,7 +256,10 @@ var listSummariesCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No CATALOG_NAME argument specified. Loading names for Tables drop-down." names, err := w.Tables.TableInfoNameToTableIdMap(ctx, catalog.ListTablesRequest{}) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/workspace/token-management/token-management.go b/cmd/workspace/token-management/token-management.go index 9e7f56143..03c32b595 100755 --- a/cmd/workspace/token-management/token-management.go +++ b/cmd/workspace/token-management/token-management.go @@ -105,7 +105,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No TOKEN_ID argument specified. Loading names for Token Management drop-down." names, err := w.TokenManagement.TokenInfoCommentToTokenIdMap(ctx, settings.ListTokenManagementRequest{}) + close(promptSpinner) if err != nil { return err } @@ -160,7 +163,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No TOKEN_ID argument specified. Loading names for Token Management drop-down." names, err := w.TokenManagement.TokenInfoCommentToTokenIdMap(ctx, settings.ListTokenManagementRequest{}) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/workspace/tokens/tokens.go b/cmd/workspace/tokens/tokens.go index ad829a6a6..359f1afd8 100755 --- a/cmd/workspace/tokens/tokens.go +++ b/cmd/workspace/tokens/tokens.go @@ -106,7 +106,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No TOKEN_ID argument specified. Loading names for Tokens drop-down." names, err := w.Tokens.TokenInfoCommentToTokenIdMap(ctx) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/workspace/users/users.go b/cmd/workspace/users/users.go index fcafde2da..fec18927a 100755 --- a/cmd/workspace/users/users.go +++ b/cmd/workspace/users/users.go @@ -119,7 +119,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Users drop-down." names, err := w.Users.UserUserNameToIdMap(ctx, iam.ListUsersRequest{}) + close(promptSpinner) if err != nil { return err } @@ -174,7 +177,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Users drop-down." names, err := w.Users.UserUserNameToIdMap(ctx, iam.ListUsersRequest{}) + close(promptSpinner) if err != nil { return err } @@ -287,7 +293,10 @@ var patchCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Users drop-down." names, err := w.Users.UserUserNameToIdMap(ctx, iam.ListUsersRequest{}) + close(promptSpinner) if err != nil { return err } @@ -353,7 +362,10 @@ var updateCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Users drop-down." names, err := w.Users.UserUserNameToIdMap(ctx, iam.ListUsersRequest{}) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/workspace/volumes/volumes.go b/cmd/workspace/volumes/volumes.go index 3484e227d..8364850d4 100755 --- a/cmd/workspace/volumes/volumes.go +++ b/cmd/workspace/volumes/volumes.go @@ -134,7 +134,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No FULL_NAME_ARG argument specified. Loading names for Volumes drop-down." names, err := w.Volumes.VolumeInfoNameToVolumeIdMap(ctx, catalog.ListVolumesRequest{}) + close(promptSpinner) if err != nil { return err } @@ -253,7 +256,10 @@ var readCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No FULL_NAME_ARG argument specified. Loading names for Volumes drop-down." names, err := w.Volumes.VolumeInfoNameToVolumeIdMap(ctx, catalog.ListVolumesRequest{}) + close(promptSpinner) if err != nil { return err } @@ -319,7 +325,10 @@ var updateCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No FULL_NAME_ARG argument specified. Loading names for Volumes drop-down." names, err := w.Volumes.VolumeInfoNameToVolumeIdMap(ctx, catalog.ListVolumesRequest{}) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/workspace/warehouses/warehouses.go b/cmd/workspace/warehouses/warehouses.go index bc8621013..ad8ef1c7a 100755 --- a/cmd/workspace/warehouses/warehouses.go +++ b/cmd/workspace/warehouses/warehouses.go @@ -148,7 +148,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Warehouses drop-down." names, err := w.Warehouses.EndpointInfoNameToIdMap(ctx, sql.ListWarehousesRequest{}) + close(promptSpinner) if err != nil { return err } @@ -246,7 +249,10 @@ var editCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Warehouses drop-down." names, err := w.Warehouses.EndpointInfoNameToIdMap(ctx, sql.ListWarehousesRequest{}) + close(promptSpinner) if err != nil { return err } @@ -330,7 +336,10 @@ var getCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Warehouses drop-down." names, err := w.Warehouses.EndpointInfoNameToIdMap(ctx, sql.ListWarehousesRequest{}) + close(promptSpinner) if err != nil { return err } @@ -525,7 +534,10 @@ var startCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Warehouses drop-down." names, err := w.Warehouses.EndpointInfoNameToIdMap(ctx, sql.ListWarehousesRequest{}) + close(promptSpinner) if err != nil { return err } @@ -609,7 +621,10 @@ var stopCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No ID argument specified. Loading names for Warehouses drop-down." names, err := w.Warehouses.EndpointInfoNameToIdMap(ctx, sql.ListWarehousesRequest{}) + close(promptSpinner) if err != nil { return err } diff --git a/cmd/workspace/workspace/workspace.go b/cmd/workspace/workspace/workspace.go index 046234245..03598c5ff 100755 --- a/cmd/workspace/workspace/workspace.go +++ b/cmd/workspace/workspace/workspace.go @@ -62,7 +62,10 @@ var deleteCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No PATH argument specified. Loading names for Workspace drop-down." names, err := w.Workspace.ObjectInfoPathToObjectIdMap(ctx, workspace.ListWorkspaceRequest{}) + close(promptSpinner) if err != nil { return err } @@ -127,7 +130,10 @@ var exportCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No PATH argument specified. Loading names for Workspace drop-down." names, err := w.Workspace.ObjectInfoPathToObjectIdMap(ctx, workspace.ListWorkspaceRequest{}) + close(promptSpinner) if err != nil { return err } @@ -183,7 +189,10 @@ var getStatusCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No PATH argument specified. Loading names for Workspace drop-down." names, err := w.Workspace.ObjectInfoPathToObjectIdMap(ctx, workspace.ListWorkspaceRequest{}) + close(promptSpinner) if err != nil { return err } @@ -246,7 +255,10 @@ var importCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No PATH argument specified. Loading names for Workspace drop-down." names, err := w.Workspace.ObjectInfoPathToObjectIdMap(ctx, workspace.ListWorkspaceRequest{}) + close(promptSpinner) if err != nil { return err } @@ -358,7 +370,10 @@ var mkdirsCmd = &cobra.Command{ } } else { if len(args) == 0 { + promptSpinner := cmdio.Spinner(ctx) + promptSpinner <- "No PATH argument specified. Loading names for Workspace drop-down." names, err := w.Workspace.ObjectInfoPathToObjectIdMap(ctx, workspace.ListWorkspaceRequest{}) + close(promptSpinner) if err != nil { return err } From 1c0d67f66c24306ca3a9162b600aa4cbbad2e6c3 Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Fri, 2 Jun 2023 14:49:59 +0200 Subject: [PATCH 4/9] Add fs.FS adapter for the filer interface (#422) ## Changes This enables the use of `io/fs` functions `fs.Glob` and `fs.WalkDir` with filers. We can't use `fs.FS` as the standard interface instead of `filer.Filer` because: 1. It was made for reading from filesystems only, not writing 2. It doesn't take a context for the core functions Therefore a wrapper will do. ## Tests * Added unit tests to cover the adapter through a fake filer. * Manually ran `fs.WalkDir` against both WSFS and DBFS filers. --- libs/filer/fs.go | 151 ++++++++++++++++++++++ libs/filer/fs_test.go | 288 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 439 insertions(+) create mode 100644 libs/filer/fs.go create mode 100644 libs/filer/fs_test.go diff --git a/libs/filer/fs.go b/libs/filer/fs.go new file mode 100644 index 000000000..c6dd21de5 --- /dev/null +++ b/libs/filer/fs.go @@ -0,0 +1,151 @@ +package filer + +import ( + "bytes" + "context" + "io" + "io/fs" +) + +// filerFS implements the fs.FS interface for a filer. +type filerFS struct { + ctx context.Context + filer Filer +} + +// NewFS returns an fs.FS backed by a filer. +func NewFS(ctx context.Context, filer Filer) fs.FS { + return &filerFS{ctx: ctx, filer: filer} +} + +func (fs *filerFS) Open(name string) (fs.File, error) { + stat, err := fs.filer.Stat(fs.ctx, name) + if err != nil { + return nil, err + } + + if stat.IsDir() { + return &fsDir{fs: fs, name: name, stat: stat}, nil + } + + return &fsFile{fs: fs, name: name, stat: stat}, nil +} + +func (fs *filerFS) ReadDir(name string) ([]fs.DirEntry, error) { + return fs.filer.ReadDir(fs.ctx, name) +} + +func (fs *filerFS) ReadFile(name string) ([]byte, error) { + reader, err := fs.filer.Read(fs.ctx, name) + if err != nil { + return nil, err + } + + var buf bytes.Buffer + _, err = io.Copy(&buf, reader) + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (fs *filerFS) Stat(name string) (fs.FileInfo, error) { + return fs.filer.Stat(fs.ctx, name) +} + +// Type that implements fs.File for a filer-backed fs.FS. +type fsFile struct { + fs *filerFS + name string + stat fs.FileInfo + + reader io.Reader +} + +func (f *fsFile) Stat() (fs.FileInfo, error) { + return f.stat, nil +} + +func (f *fsFile) Read(buf []byte) (int, error) { + if f.reader == nil { + reader, err := f.fs.filer.Read(f.fs.ctx, f.name) + if err != nil { + return 0, err + } + f.reader = reader + } + + return f.reader.Read(buf) +} + +func (f *fsFile) Close() error { + if f.reader == nil { + return fs.ErrClosed + } + f.reader = nil + return nil +} + +// Type that implements fs.ReadDirFile for a filer-backed fs.FS. +type fsDir struct { + fs *filerFS + name string + stat fs.FileInfo + + open bool + entries []fs.DirEntry +} + +func (f *fsDir) Stat() (fs.FileInfo, error) { + return f.stat, nil +} + +func (f *fsDir) Read(buf []byte) (int, error) { + return 0, fs.ErrInvalid +} + +func (f *fsDir) ReadDir(n int) ([]fs.DirEntry, error) { + // Load all directory entries if not already loaded. + if !f.open { + entries, err := f.fs.ReadDir(f.name) + if err != nil { + return nil, err + } + f.open = true + f.entries = entries + } + + // Return all entries if n <= 0. + if n <= 0 { + entries := f.entries + f.entries = nil + return entries, nil + } + + // If there are no more entries, return io.EOF. + if len(f.entries) == 0 { + return nil, io.EOF + } + + // If there are less than n entries, return all entries. + if len(f.entries) < n { + entries := f.entries + f.entries = nil + return entries, nil + } + + // Return n entries. + entries := f.entries[:n] + f.entries = f.entries[n:] + return entries, nil +} + +func (f *fsDir) Close() error { + if !f.open { + return fs.ErrClosed + } + f.open = false + f.entries = nil + return nil +} diff --git a/libs/filer/fs_test.go b/libs/filer/fs_test.go new file mode 100644 index 000000000..b8c8892e7 --- /dev/null +++ b/libs/filer/fs_test.go @@ -0,0 +1,288 @@ +package filer + +import ( + "context" + "fmt" + "io" + "io/fs" + "path" + "sort" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type fakeDirEntry struct { + fakeFileInfo +} + +func (entry fakeDirEntry) Type() fs.FileMode { + typ := fs.ModePerm + if entry.dir { + typ |= fs.ModeDir + } + return typ +} + +func (entry fakeDirEntry) Info() (fs.FileInfo, error) { + return entry.fakeFileInfo, nil +} + +type fakeFileInfo struct { + name string + size int64 + dir bool + mode fs.FileMode +} + +func (info fakeFileInfo) Name() string { + return info.name +} + +func (info fakeFileInfo) Size() int64 { + return info.size +} + +func (info fakeFileInfo) Mode() fs.FileMode { + return info.mode +} + +func (info fakeFileInfo) ModTime() time.Time { + return time.Now() +} + +func (info fakeFileInfo) IsDir() bool { + return info.dir +} + +func (info fakeFileInfo) Sys() any { + return nil +} + +type fakeFiler struct { + entries map[string]fakeFileInfo +} + +func (f *fakeFiler) Write(ctx context.Context, p string, reader io.Reader, mode ...WriteMode) error { + return fmt.Errorf("not implemented") +} + +func (f *fakeFiler) Read(ctx context.Context, p string) (io.Reader, error) { + _, ok := f.entries[p] + if !ok { + return nil, fs.ErrNotExist + } + + return strings.NewReader("foo"), nil +} + +func (f *fakeFiler) Delete(ctx context.Context, p string) error { + return fmt.Errorf("not implemented") +} + +func (f *fakeFiler) ReadDir(ctx context.Context, p string) ([]fs.DirEntry, error) { + entry, ok := f.entries[p] + if !ok { + return nil, fs.ErrNotExist + } + + if !entry.dir { + return nil, fs.ErrInvalid + } + + // Find all entries contained in the specified directory `p`. + var out []fs.DirEntry + for k, v := range f.entries { + if k == p || path.Dir(k) != p { + continue + } + + out = append(out, fakeDirEntry{v}) + } + + sort.Slice(out, func(i, j int) bool { return out[i].Name() < out[j].Name() }) + return out, nil +} + +func (f *fakeFiler) Mkdir(ctx context.Context, path string) error { + return fmt.Errorf("not implemented") +} + +func (f *fakeFiler) Stat(ctx context.Context, path string) (fs.FileInfo, error) { + entry, ok := f.entries[path] + if !ok { + return nil, fs.ErrNotExist + } + + return entry, nil +} + +func TestFsImplementsFS(t *testing.T) { + var _ fs.FS = &filerFS{} +} + +func TestFsImplementsReadDirFS(t *testing.T) { + var _ fs.ReadDirFS = &filerFS{} +} + +func TestFsImplementsReadFileFS(t *testing.T) { + var _ fs.ReadDirFS = &filerFS{} +} + +func TestFsImplementsStatFS(t *testing.T) { + var _ fs.StatFS = &filerFS{} +} + +func TestFsFileImplementsFsFile(t *testing.T) { + var _ fs.File = &fsFile{} +} + +func TestFsDirImplementsFsReadDirFile(t *testing.T) { + var _ fs.ReadDirFile = &fsDir{} +} + +func fakeFS() fs.FS { + fakeFiler := &fakeFiler{ + entries: map[string]fakeFileInfo{ + ".": {name: "root", dir: true}, + "dirA": {dir: true}, + "dirB": {dir: true}, + "fileA": {size: 3}, + }, + } + + for k, v := range fakeFiler.entries { + if v.name != "" { + continue + } + v.name = path.Base(k) + fakeFiler.entries[k] = v + } + + return NewFS(context.Background(), fakeFiler) +} + +func TestFsGlob(t *testing.T) { + fakeFS := fakeFS() + matches, err := fs.Glob(fakeFS, "*") + require.NoError(t, err) + assert.Equal(t, []string{"dirA", "dirB", "fileA"}, matches) +} + +func TestFsOpenFile(t *testing.T) { + fakeFS := fakeFS() + fakeFile, err := fakeFS.Open("fileA") + require.NoError(t, err) + + info, err := fakeFile.Stat() + require.NoError(t, err) + assert.Equal(t, "fileA", info.Name()) + assert.Equal(t, int64(3), info.Size()) + assert.Equal(t, fs.FileMode(0), info.Mode()) + assert.Equal(t, false, info.IsDir()) + + // Read until closed. + b := make([]byte, 3) + n, err := fakeFile.Read(b) + require.NoError(t, err) + assert.Equal(t, 3, n) + assert.Equal(t, []byte{'f', 'o', 'o'}, b) + _, err = fakeFile.Read(b) + assert.ErrorIs(t, err, io.EOF) + + // Close. + err = fakeFile.Close() + assert.NoError(t, err) + + // Close again. + err = fakeFile.Close() + assert.ErrorIs(t, err, fs.ErrClosed) +} + +func TestFsOpenDir(t *testing.T) { + fakeFS := fakeFS() + fakeFile, err := fakeFS.Open(".") + require.NoError(t, err) + + info, err := fakeFile.Stat() + require.NoError(t, err) + assert.Equal(t, "root", info.Name()) + assert.Equal(t, true, info.IsDir()) + + de, ok := fakeFile.(fs.ReadDirFile) + require.True(t, ok) + + // Read all entries in one shot. + reference, err := de.ReadDir(-1) + require.NoError(t, err) + + // Read entries one at a time. + { + var tmp, entries []fs.DirEntry + var err error + + de.Close() + + for i := 0; i < 3; i++ { + tmp, err = de.ReadDir(1) + require.NoError(t, err) + entries = append(entries, tmp...) + } + + _, err = de.ReadDir(1) + require.ErrorIs(t, err, io.EOF, err) + + // Compare to reference. + assert.Equal(t, reference, entries) + } + + // Read entries and overshoot at the end. + { + var tmp, entries []fs.DirEntry + var err error + + de.Close() + + tmp, err = de.ReadDir(1) + require.NoError(t, err) + entries = append(entries, tmp...) + + tmp, err = de.ReadDir(20) + require.NoError(t, err) + entries = append(entries, tmp...) + + _, err = de.ReadDir(1) + require.ErrorIs(t, err, io.EOF, err) + + // Compare to reference. + assert.Equal(t, reference, entries) + } +} + +func TestFsReadDir(t *testing.T) { + fakeFS := fakeFS().(fs.ReadDirFS) + entries, err := fakeFS.ReadDir(".") + require.NoError(t, err) + assert.Len(t, entries, 3) + assert.Equal(t, "dirA", entries[0].Name()) + assert.Equal(t, "dirB", entries[1].Name()) + assert.Equal(t, "fileA", entries[2].Name()) +} + +func TestFsReadFile(t *testing.T) { + fakeFS := fakeFS().(fs.ReadFileFS) + buf, err := fakeFS.ReadFile("fileA") + require.NoError(t, err) + assert.Equal(t, []byte("foo"), buf) +} + +func TestFsStat(t *testing.T) { + fakeFS := fakeFS().(fs.StatFS) + info, err := fakeFS.Stat("fileA") + require.NoError(t, err) + assert.Equal(t, "fileA", info.Name()) + assert.Equal(t, int64(3), info.Size()) +} From 28d36577a26348394234861bd638a3aa349f917f Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Fri, 2 Jun 2023 16:02:18 +0200 Subject: [PATCH 5/9] Speed up sync integration tests (#428) ## Changes This change implements: * Channels for line-by-line output from stdout/stderr * A function to wait for a sync step to complete (using above) * Ensure all tests are prefixed `TestAccSync` * Use temporary paths in WSFS instead of cloning a repo ## Tests The same integration tests now pass in ~90 seconds (was ~250s). --- internal/helpers.go | 53 ++++++++- internal/sync_test.go | 267 +++++++++++++++++------------------------- 2 files changed, 157 insertions(+), 163 deletions(-) diff --git a/internal/helpers.go b/internal/helpers.go index b51d005b2..1f7568719 100644 --- a/internal/helpers.go +++ b/internal/helpers.go @@ -5,10 +5,12 @@ import ( "bytes" "context" "fmt" + "io" "math/rand" "os" "path/filepath" "strings" + "sync" "testing" "time" @@ -54,18 +56,54 @@ type cobraTestRunner struct { stdout bytes.Buffer stderr bytes.Buffer + // Line-by-line output. + // Background goroutines populate these channels by reading from stdout/stderr pipes. + stdoutLines <-chan string + stderrLines <-chan string + errch <-chan error } +func consumeLines(ctx context.Context, wg *sync.WaitGroup, r io.Reader) <-chan string { + ch := make(chan string, 1000) + wg.Add(1) + go func() { + defer close(ch) + defer wg.Done() + scanner := bufio.NewScanner(r) + for scanner.Scan() { + select { + case <-ctx.Done(): + return + case ch <- scanner.Text(): + } + } + }() + return ch +} + func (t *cobraTestRunner) RunBackground() { + var stdoutR, stderrR io.Reader + var stdoutW, stderrW io.WriteCloser + stdoutR, stdoutW = io.Pipe() + stderrR, stderrW = io.Pipe() root := root.RootCmd - root.SetOut(&t.stdout) - root.SetErr(&t.stderr) + root.SetOut(stdoutW) + root.SetErr(stderrW) root.SetArgs(t.args) errch := make(chan error) ctx, cancel := context.WithCancel(context.Background()) + // Tee stdout/stderr to buffers. + stdoutR = io.TeeReader(stdoutR, &t.stdout) + stderrR = io.TeeReader(stderrR, &t.stderr) + + // Consume stdout/stderr line-by-line. + var wg sync.WaitGroup + t.stdoutLines = consumeLines(ctx, &wg, stdoutR) + t.stderrLines = consumeLines(ctx, &wg, stderrR) + // Run command in background. go func() { cmd, err := root.ExecuteContextC(ctx) @@ -73,6 +111,14 @@ func (t *cobraTestRunner) RunBackground() { t.Logf("Error running command: %s", err) } + // Close pipes to signal EOF. + stdoutW.Close() + stderrW.Close() + + // Wait for the [consumeLines] routines to finish now that + // the pipes they're reading from have closed. + wg.Wait() + if t.stdout.Len() > 0 { // Make a copy of the buffer such that it remains "unread". scanner := bufio.NewScanner(bytes.NewBuffer(t.stdout.Bytes())) @@ -127,6 +173,9 @@ func (c *cobraTestRunner) Eventually(condition func() bool, waitFor time.Duratio ticker := time.NewTicker(tick) defer ticker.Stop() + // Kick off condition check immediately. + go func() { ch <- condition() }() + for tick := ticker.C; ; { select { case err := <-c.errch: diff --git a/internal/sync_test.go b/internal/sync_test.go index bcff7b22a..89b318a97 100644 --- a/internal/sync_test.go +++ b/internal/sync_test.go @@ -26,7 +26,7 @@ import ( var ( repoUrl = "https://github.com/databricks/databricks-empty-ide-project.git" - repoFiles = []string{"README-IDE.md"} + repoFiles = []string{} ) // This test needs auth env vars to run. @@ -59,7 +59,7 @@ func setupRepo(t *testing.T, wsc *databricks.WorkspaceClient, ctx context.Contex return localRoot, remoteRoot } -type assertSync struct { +type syncTest struct { t *testing.T c *cobraTestRunner w *databricks.WorkspaceClient @@ -67,7 +67,54 @@ type assertSync struct { remoteRoot string } -func (a *assertSync) remoteDirContent(ctx context.Context, relativeDir string, expectedFiles []string) { +func setupSyncTest(t *testing.T, args ...string) *syncTest { + t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV")) + + w := databricks.Must(databricks.NewWorkspaceClient()) + localRoot := t.TempDir() + remoteRoot := temporaryWorkspaceDir(t, w) + + // Prepend common arguments. + args = append([]string{ + "sync", + localRoot, + remoteRoot, + "--output", + "json", + }, args...) + + c := NewCobraTestRunner(t, args...) + c.RunBackground() + + return &syncTest{ + t: t, + c: c, + w: w, + localRoot: localRoot, + remoteRoot: remoteRoot, + } +} + +func (s *syncTest) waitForCompletionMarker() { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + for { + select { + case <-ctx.Done(): + s.t.Fatal("timed out waiting for sync to complete") + case line := <-s.c.stdoutLines: + var event sync.EventBase + err := json.Unmarshal([]byte(line), &event) + require.NoError(s.t, err) + if event.Type == sync.EventTypeComplete { + return + } + } + } +} + +func (a *syncTest) remoteDirContent(ctx context.Context, relativeDir string, expectedFiles []string) { remoteDir := path.Join(a.remoteRoot, relativeDir) a.c.Eventually(func() bool { objects, err := a.w.Workspace.ListAll(ctx, workspace.ListWorkspaceRequest{ @@ -92,7 +139,7 @@ func (a *assertSync) remoteDirContent(ctx context.Context, relativeDir string, e } } -func (a *assertSync) remoteFileContent(ctx context.Context, relativePath string, expectedContent string) { +func (a *syncTest) remoteFileContent(ctx context.Context, relativePath string, expectedContent string) { filePath := path.Join(a.remoteRoot, relativePath) // Remove leading "/" so we can use it in the URL. @@ -113,7 +160,7 @@ func (a *assertSync) remoteFileContent(ctx context.Context, relativePath string, }, 30*time.Second, 5*time.Second) } -func (a *assertSync) objectType(ctx context.Context, relativePath string, expected string) { +func (a *syncTest) objectType(ctx context.Context, relativePath string, expected string) { path := path.Join(a.remoteRoot, relativePath) a.c.Eventually(func() bool { @@ -125,7 +172,7 @@ func (a *assertSync) objectType(ctx context.Context, relativePath string, expect }, 30*time.Second, 5*time.Second) } -func (a *assertSync) language(ctx context.Context, relativePath string, expected string) { +func (a *syncTest) language(ctx context.Context, relativePath string, expected string) { path := path.Join(a.remoteRoot, relativePath) a.c.Eventually(func() bool { @@ -137,7 +184,7 @@ func (a *assertSync) language(ctx context.Context, relativePath string, expected }, 30*time.Second, 5*time.Second) } -func (a *assertSync) snapshotContains(files []string) { +func (a *syncTest) snapshotContains(files []string) { snapshotPath := filepath.Join(a.localRoot, ".databricks/sync-snapshots", sync.GetFileName(a.w.Config.Host, a.remoteRoot)) assert.FileExists(a.t, snapshotPath) @@ -160,123 +207,87 @@ func (a *assertSync) snapshotContains(files []string) { assert.Equal(a.t, len(files), len(s.LastUpdatedTimes)) } -func TestAccFullFileSync(t *testing.T) { - t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV")) - - wsc := databricks.Must(databricks.NewWorkspaceClient()) +func TestAccSyncFullFileSync(t *testing.T) { ctx := context.Background() - - localRepoPath, remoteRepoPath := setupRepo(t, wsc, ctx) - - // Run `databricks sync` in the background. - c := NewCobraTestRunner(t, "sync", localRepoPath, remoteRepoPath, "--full", "--watch") - c.RunBackground() - - assertSync := assertSync{ - t: t, - c: c, - w: wsc, - localRoot: localRepoPath, - remoteRoot: remoteRepoPath, - } + assertSync := setupSyncTest(t, "--full", "--watch") // .gitignore is created by the sync process to enforce .databricks is not synced + assertSync.waitForCompletionMarker() assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore")) // New file - localFilePath := filepath.Join(localRepoPath, "foo.txt") + localFilePath := filepath.Join(assertSync.localRoot, "foo.txt") f := testfile.CreateFile(t, localFilePath) defer f.Close(t) + assertSync.waitForCompletionMarker() assertSync.remoteDirContent(ctx, "", append(repoFiles, "foo.txt", ".gitignore")) assertSync.remoteFileContent(ctx, "foo.txt", "") // Write to file f.Overwrite(t, `{"statement": "Mi Gente"}`) + assertSync.waitForCompletionMarker() assertSync.remoteFileContent(ctx, "foo.txt", `{"statement": "Mi Gente"}`) // Write again f.Overwrite(t, `{"statement": "Young Dumb & Broke"}`) + assertSync.waitForCompletionMarker() assertSync.remoteFileContent(ctx, "foo.txt", `{"statement": "Young Dumb & Broke"}`) // delete f.Remove(t) + assertSync.waitForCompletionMarker() assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore")) } -func TestAccIncrementalFileSync(t *testing.T) { - t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV")) - - wsc := databricks.Must(databricks.NewWorkspaceClient()) +func TestAccSyncIncrementalFileSync(t *testing.T) { ctx := context.Background() - - localRepoPath, remoteRepoPath := setupRepo(t, wsc, ctx) - - // Run `databricks sync` in the background. - c := NewCobraTestRunner(t, "sync", localRepoPath, remoteRepoPath, "--watch") - c.RunBackground() - - assertSync := assertSync{ - t: t, - c: c, - w: wsc, - localRoot: localRepoPath, - remoteRoot: remoteRepoPath, - } + assertSync := setupSyncTest(t, "--watch") // .gitignore is created by the sync process to enforce .databricks is not synced + assertSync.waitForCompletionMarker() assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore")) // New file - localFilePath := filepath.Join(localRepoPath, "foo.txt") + localFilePath := filepath.Join(assertSync.localRoot, "foo.txt") f := testfile.CreateFile(t, localFilePath) defer f.Close(t) + assertSync.waitForCompletionMarker() assertSync.remoteDirContent(ctx, "", append(repoFiles, "foo.txt", ".gitignore")) assertSync.remoteFileContent(ctx, "foo.txt", "") assertSync.snapshotContains(append(repoFiles, "foo.txt", ".gitignore")) // Write to file f.Overwrite(t, `{"statement": "Mi Gente"}`) + assertSync.waitForCompletionMarker() assertSync.remoteFileContent(ctx, "foo.txt", `{"statement": "Mi Gente"}`) // Write again f.Overwrite(t, `{"statement": "Young Dumb & Broke"}`) + assertSync.waitForCompletionMarker() assertSync.remoteFileContent(ctx, "foo.txt", `{"statement": "Young Dumb & Broke"}`) // delete f.Remove(t) + assertSync.waitForCompletionMarker() assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore")) assertSync.snapshotContains(append(repoFiles, ".gitignore")) } -func TestAccNestedFolderSync(t *testing.T) { - t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV")) - - wsc := databricks.Must(databricks.NewWorkspaceClient()) +func TestAccSyncNestedFolderSync(t *testing.T) { ctx := context.Background() - - localRepoPath, remoteRepoPath := setupRepo(t, wsc, ctx) - - // Run `databricks sync` in the background. - c := NewCobraTestRunner(t, "sync", localRepoPath, remoteRepoPath, "--watch") - c.RunBackground() - - assertSync := assertSync{ - t: t, - c: c, - w: wsc, - localRoot: localRepoPath, - remoteRoot: remoteRepoPath, - } + assertSync := setupSyncTest(t, "--watch") // .gitignore is created by the sync process to enforce .databricks is not synced + assertSync.waitForCompletionMarker() assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore")) // New file - localFilePath := filepath.Join(localRepoPath, "dir1/dir2/dir3/foo.txt") + localFilePath := filepath.Join(assertSync.localRoot, "dir1/dir2/dir3/foo.txt") err := os.MkdirAll(filepath.Dir(localFilePath), 0o755) assert.NoError(t, err) f := testfile.CreateFile(t, localFilePath) defer f.Close(t) + assertSync.waitForCompletionMarker() assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "dir1")) assertSync.remoteDirContent(ctx, "dir1", []string{"dir2"}) assertSync.remoteDirContent(ctx, "dir1/dir2", []string{"dir3"}) @@ -285,40 +296,27 @@ func TestAccNestedFolderSync(t *testing.T) { // delete f.Remove(t) + assertSync.waitForCompletionMarker() // directories are not cleaned up right now. This is not ideal assertSync.remoteDirContent(ctx, "dir1/dir2/dir3", []string{}) assertSync.snapshotContains(append(repoFiles, ".gitignore")) } -func TestAccNestedSpacePlusAndHashAreEscapedSync(t *testing.T) { - t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV")) - - wsc := databricks.Must(databricks.NewWorkspaceClient()) +func TestAccSyncNestedSpacePlusAndHashAreEscapedSync(t *testing.T) { ctx := context.Background() - - localRepoPath, remoteRepoPath := setupRepo(t, wsc, ctx) - - // Run `databricks sync` in the background. - c := NewCobraTestRunner(t, "sync", localRepoPath, remoteRepoPath, "--watch") - c.RunBackground() - - assertSync := assertSync{ - t: t, - c: c, - w: wsc, - localRoot: localRepoPath, - remoteRoot: remoteRepoPath, - } + assertSync := setupSyncTest(t, "--watch") // .gitignore is created by the sync process to enforce .databricks is not synced + assertSync.waitForCompletionMarker() assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore")) // New file - localFilePath := filepath.Join(localRepoPath, "dir1/a b+c/c+d e/e+f g#i.txt") + localFilePath := filepath.Join(assertSync.localRoot, "dir1/a b+c/c+d e/e+f g#i.txt") err := os.MkdirAll(filepath.Dir(localFilePath), 0o755) assert.NoError(t, err) f := testfile.CreateFile(t, localFilePath) defer f.Close(t) + assertSync.waitForCompletionMarker() assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "dir1")) assertSync.remoteDirContent(ctx, "dir1", []string{"a b+c"}) assertSync.remoteDirContent(ctx, "dir1/a b+c", []string{"c+d e"}) @@ -327,6 +325,7 @@ func TestAccNestedSpacePlusAndHashAreEscapedSync(t *testing.T) { // delete f.Remove(t) + assertSync.waitForCompletionMarker() // directories are not cleaned up right now. This is not ideal assertSync.remoteDirContent(ctx, "dir1/a b+c/c+d e", []string{}) assertSync.snapshotContains(append(repoFiles, ".gitignore")) @@ -341,77 +340,49 @@ func TestAccNestedSpacePlusAndHashAreEscapedSync(t *testing.T) { // // In the above scenario sync should delete the empty folder and add foo to the remote // file system -func TestAccIncrementalFileOverwritesFolder(t *testing.T) { - t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV")) - - wsc := databricks.Must(databricks.NewWorkspaceClient()) +func TestAccSyncIncrementalFileOverwritesFolder(t *testing.T) { ctx := context.Background() - - localRepoPath, remoteRepoPath := setupRepo(t, wsc, ctx) - - // Run `databricks sync` in the background. - c := NewCobraTestRunner(t, "sync", localRepoPath, remoteRepoPath, "--watch") - c.RunBackground() - - assertSync := assertSync{ - t: t, - c: c, - w: wsc, - localRoot: localRepoPath, - remoteRoot: remoteRepoPath, - } + assertSync := setupSyncTest(t, "--watch") // create foo/bar.txt - localFilePath := filepath.Join(localRepoPath, "foo/bar.txt") + localFilePath := filepath.Join(assertSync.localRoot, "foo/bar.txt") err := os.MkdirAll(filepath.Dir(localFilePath), 0o755) assert.NoError(t, err) f := testfile.CreateFile(t, localFilePath) defer f.Close(t) + assertSync.waitForCompletionMarker() assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "foo")) assertSync.remoteDirContent(ctx, "foo", []string{"bar.txt"}) assertSync.snapshotContains(append(repoFiles, ".gitignore", filepath.FromSlash("foo/bar.txt"))) // delete foo/bar.txt f.Remove(t) - os.Remove(filepath.Join(localRepoPath, "foo")) + os.Remove(filepath.Join(assertSync.localRoot, "foo")) + assertSync.waitForCompletionMarker() assertSync.remoteDirContent(ctx, "foo", []string{}) assertSync.objectType(ctx, "foo", "DIRECTORY") assertSync.snapshotContains(append(repoFiles, ".gitignore")) - f2 := testfile.CreateFile(t, filepath.Join(localRepoPath, "foo")) + f2 := testfile.CreateFile(t, filepath.Join(assertSync.localRoot, "foo")) defer f2.Close(t) + assertSync.waitForCompletionMarker() assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "foo")) assertSync.objectType(ctx, "foo", "FILE") assertSync.snapshotContains(append(repoFiles, ".gitignore", "foo")) } -func TestAccIncrementalSyncPythonNotebookToFile(t *testing.T) { - t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV")) - - wsc := databricks.Must(databricks.NewWorkspaceClient()) +func TestAccSyncIncrementalSyncPythonNotebookToFile(t *testing.T) { ctx := context.Background() - - localRepoPath, remoteRepoPath := setupRepo(t, wsc, ctx) + assertSync := setupSyncTest(t, "--watch") // create python notebook - localFilePath := filepath.Join(localRepoPath, "foo.py") + localFilePath := filepath.Join(assertSync.localRoot, "foo.py") f := testfile.CreateFile(t, localFilePath) defer f.Close(t) f.Overwrite(t, "# Databricks notebook source") - // Run `databricks sync` in the background. - c := NewCobraTestRunner(t, "sync", localRepoPath, remoteRepoPath, "--watch") - c.RunBackground() - - assertSync := assertSync{ - t: t, - c: c, - w: wsc, - localRoot: localRepoPath, - remoteRoot: remoteRepoPath, - } - // notebook was uploaded properly + assertSync.waitForCompletionMarker() assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "foo")) assertSync.objectType(ctx, "foo", "NOTEBOOK") assertSync.language(ctx, "foo", "PYTHON") @@ -419,40 +390,27 @@ func TestAccIncrementalSyncPythonNotebookToFile(t *testing.T) { // convert to vanilla python file f.Overwrite(t, "# No longer a python notebook") + assertSync.waitForCompletionMarker() assertSync.objectType(ctx, "foo.py", "FILE") assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "foo.py")) assertSync.snapshotContains(append(repoFiles, ".gitignore", "foo.py")) // delete the vanilla python file f.Remove(t) + assertSync.waitForCompletionMarker() assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore")) assertSync.snapshotContains(append(repoFiles, ".gitignore")) } -func TestAccIncrementalSyncFileToPythonNotebook(t *testing.T) { - t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV")) - - wsc := databricks.Must(databricks.NewWorkspaceClient()) +func TestAccSyncIncrementalSyncFileToPythonNotebook(t *testing.T) { ctx := context.Background() - - localRepoPath, remoteRepoPath := setupRepo(t, wsc, ctx) - - // Run `databricks sync` in the background. - c := NewCobraTestRunner(t, "sync", localRepoPath, remoteRepoPath, "--watch") - c.RunBackground() - - assertSync := assertSync{ - t: t, - c: c, - w: wsc, - localRoot: localRepoPath, - remoteRoot: remoteRepoPath, - } + assertSync := setupSyncTest(t, "--watch") // create vanilla python file - localFilePath := filepath.Join(localRepoPath, "foo.py") + localFilePath := filepath.Join(assertSync.localRoot, "foo.py") f := testfile.CreateFile(t, localFilePath) defer f.Close(t) + assertSync.waitForCompletionMarker() // assert file upload assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "foo.py")) @@ -461,37 +419,23 @@ func TestAccIncrementalSyncFileToPythonNotebook(t *testing.T) { // convert to notebook f.Overwrite(t, "# Databricks notebook source") + assertSync.waitForCompletionMarker() assertSync.objectType(ctx, "foo", "NOTEBOOK") assertSync.language(ctx, "foo", "PYTHON") assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "foo")) assertSync.snapshotContains(append(repoFiles, ".gitignore", "foo.py")) } -func TestAccIncrementalSyncPythonNotebookDelete(t *testing.T) { - t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV")) - - wsc := databricks.Must(databricks.NewWorkspaceClient()) +func TestAccSyncIncrementalSyncPythonNotebookDelete(t *testing.T) { ctx := context.Background() - - localRepoPath, remoteRepoPath := setupRepo(t, wsc, ctx) + assertSync := setupSyncTest(t, "--watch") // create python notebook - localFilePath := filepath.Join(localRepoPath, "foo.py") + localFilePath := filepath.Join(assertSync.localRoot, "foo.py") f := testfile.CreateFile(t, localFilePath) defer f.Close(t) f.Overwrite(t, "# Databricks notebook source") - - // Run `databricks sync` in the background. - c := NewCobraTestRunner(t, "sync", localRepoPath, remoteRepoPath, "--watch") - c.RunBackground() - - assertSync := assertSync{ - t: t, - c: c, - w: wsc, - localRoot: localRepoPath, - remoteRoot: remoteRepoPath, - } + assertSync.waitForCompletionMarker() // notebook was uploaded properly assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "foo")) @@ -500,6 +444,7 @@ func TestAccIncrementalSyncPythonNotebookDelete(t *testing.T) { // Delete notebook f.Remove(t) + assertSync.waitForCompletionMarker() assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore")) } From 3dbf7a575a649402ac49b20598cb499b22da6b8f Mon Sep 17 00:00:00 2001 From: Andrew Nester Date: Mon, 5 Jun 2023 16:32:03 +0200 Subject: [PATCH 6/9] Better error message if can not load prompts (#437) ## Changes Better error message if can not load prompts ## Tests Setup 2 jobs with the same name and ran `cli job get` ``` andrew.nester@HFW9Y94129 multiples-tasks % ../../cli/cli jobs get Error: failed to load names for Jobs drop-down. Please manually specify required arguments. Original error: duplicate .Settings.Name: duplicatejob ``` --- .codegen/service.go.tmpl | 2 +- cmd/account/budgets/budgets.go | 4 ++-- cmd/account/credentials/credentials.go | 4 ++-- cmd/account/groups/groups.go | 8 +++---- .../ip-access-lists/ip-access-lists.go | 4 ++-- cmd/account/log-delivery/log-delivery.go | 2 +- cmd/account/networks/networks.go | 6 ++--- cmd/account/private-access/private-access.go | 4 ++-- .../service-principals/service-principals.go | 8 +++---- cmd/account/storage/storage.go | 4 ++-- cmd/account/users/users.go | 8 +++---- cmd/account/vpc-endpoints/vpc-endpoints.go | 6 ++--- cmd/account/workspaces/workspaces.go | 8 +++---- cmd/workspace/alerts/alerts.go | 4 ++-- .../cluster-policies/cluster-policies.go | 6 ++--- cmd/workspace/clusters/clusters.go | 20 ++++++++--------- cmd/workspace/dashboards/dashboards.go | 6 ++--- .../git-credentials/git-credentials.go | 8 +++---- .../global-init-scripts.go | 4 ++-- cmd/workspace/groups/groups.go | 8 +++---- .../instance-pools/instance-pools.go | 4 ++-- .../ip-access-lists/ip-access-lists.go | 4 ++-- cmd/workspace/jobs/jobs.go | 22 +++++++++---------- cmd/workspace/metastores/metastores.go | 8 +++---- cmd/workspace/pipelines/pipelines.go | 16 +++++++------- cmd/workspace/providers/providers.go | 8 +++---- cmd/workspace/queries/queries.go | 8 +++---- cmd/workspace/recipients/recipients.go | 8 +++---- cmd/workspace/repos/repos.go | 6 ++--- cmd/workspace/schemas/schemas.go | 6 ++--- .../service-principals/service-principals.go | 8 +++---- cmd/workspace/tables/tables.go | 6 ++--- .../token-management/token-management.go | 4 ++-- cmd/workspace/tokens/tokens.go | 2 +- cmd/workspace/users/users.go | 8 +++---- cmd/workspace/volumes/volumes.go | 6 ++--- cmd/workspace/warehouses/warehouses.go | 10 ++++----- cmd/workspace/workspace/workspace.go | 10 ++++----- 38 files changed, 134 insertions(+), 134 deletions(-) diff --git a/.codegen/service.go.tmpl b/.codegen/service.go.tmpl index 72aea3705..5bab09608 100644 --- a/.codegen/service.go.tmpl +++ b/.codegen/service.go.tmpl @@ -101,7 +101,7 @@ var {{.CamelName}}Cmd = &cobra.Command{ names, err := {{if .Service.IsAccounts}}a{{else}}w{{end}}.{{(.Service.TrimPrefix "account").PascalName}}.{{.Service.List.NamedIdMap.PascalName}}(ctx{{if .Service.List.Request}}, {{.Service.Package.Name}}.{{.Service.List.Request.PascalName}}{}{{end}}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for {{.Service.TitleName}} drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "{{range .Request.RequiredFields}}{{.Summary | trimSuffix "."}}{{end}}") if err != nil { diff --git a/cmd/account/budgets/budgets.go b/cmd/account/budgets/budgets.go index 8edbe0a6d..ff39aacfd 100755 --- a/cmd/account/budgets/budgets.go +++ b/cmd/account/budgets/budgets.go @@ -99,7 +99,7 @@ var deleteCmd = &cobra.Command{ names, err := a.Budgets.BudgetWithStatusNameToBudgetIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Budgets drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Budget ID") if err != nil { @@ -158,7 +158,7 @@ var getCmd = &cobra.Command{ names, err := a.Budgets.BudgetWithStatusNameToBudgetIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Budgets drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Budget ID") if err != nil { diff --git a/cmd/account/credentials/credentials.go b/cmd/account/credentials/credentials.go index 81f587709..0b2abb80d 100755 --- a/cmd/account/credentials/credentials.go +++ b/cmd/account/credentials/credentials.go @@ -118,7 +118,7 @@ var deleteCmd = &cobra.Command{ names, err := a.Credentials.CredentialCredentialsNameToCredentialsIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Credentials drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Databricks Account API credential configuration ID") if err != nil { @@ -177,7 +177,7 @@ var getCmd = &cobra.Command{ names, err := a.Credentials.CredentialCredentialsNameToCredentialsIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Credentials drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Databricks Account API credential configuration ID") if err != nil { diff --git a/cmd/account/groups/groups.go b/cmd/account/groups/groups.go index 143bbf92c..6b5db4140 100755 --- a/cmd/account/groups/groups.go +++ b/cmd/account/groups/groups.go @@ -116,7 +116,7 @@ var deleteCmd = &cobra.Command{ names, err := a.Groups.GroupDisplayNameToIdMap(ctx, iam.ListAccountGroupsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Account Groups drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Unique ID for a group in the Databricks account") if err != nil { @@ -174,7 +174,7 @@ var getCmd = &cobra.Command{ names, err := a.Groups.GroupDisplayNameToIdMap(ctx, iam.ListAccountGroupsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Account Groups drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Unique ID for a group in the Databricks account") if err != nil { @@ -289,7 +289,7 @@ var patchCmd = &cobra.Command{ names, err := a.Groups.GroupDisplayNameToIdMap(ctx, iam.ListAccountGroupsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Account Groups drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Unique ID for a group in the Databricks account") if err != nil { @@ -355,7 +355,7 @@ var updateCmd = &cobra.Command{ names, err := a.Groups.GroupDisplayNameToIdMap(ctx, iam.ListAccountGroupsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Account Groups drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Databricks group ID") if err != nil { diff --git a/cmd/account/ip-access-lists/ip-access-lists.go b/cmd/account/ip-access-lists/ip-access-lists.go index d52917afe..1719dce81 100755 --- a/cmd/account/ip-access-lists/ip-access-lists.go +++ b/cmd/account/ip-access-lists/ip-access-lists.go @@ -137,7 +137,7 @@ var deleteCmd = &cobra.Command{ names, err := a.IpAccessLists.IpAccessListInfoLabelToListIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Account Ip Access Lists drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The ID for the corresponding IP access list") if err != nil { @@ -195,7 +195,7 @@ var getCmd = &cobra.Command{ names, err := a.IpAccessLists.IpAccessListInfoLabelToListIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Account Ip Access Lists drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The ID for the corresponding IP access list") if err != nil { diff --git a/cmd/account/log-delivery/log-delivery.go b/cmd/account/log-delivery/log-delivery.go index a20972ce7..f42b9d54c 100755 --- a/cmd/account/log-delivery/log-delivery.go +++ b/cmd/account/log-delivery/log-delivery.go @@ -188,7 +188,7 @@ var getCmd = &cobra.Command{ names, err := a.LogDelivery.LogDeliveryConfigurationConfigNameToConfigIdMap(ctx, billing.ListLogDeliveryRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Log Delivery drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Databricks log delivery configuration ID") if err != nil { diff --git a/cmd/account/networks/networks.go b/cmd/account/networks/networks.go index 9a0b77391..e472f0ddb 100755 --- a/cmd/account/networks/networks.go +++ b/cmd/account/networks/networks.go @@ -63,7 +63,7 @@ var createCmd = &cobra.Command{ names, err := a.Networks.NetworkNetworkNameToNetworkIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Networks drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The human-readable name of the network configuration") if err != nil { @@ -126,7 +126,7 @@ var deleteCmd = &cobra.Command{ names, err := a.Networks.NetworkNetworkNameToNetworkIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Networks drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Databricks Account API network configuration ID") if err != nil { @@ -185,7 +185,7 @@ var getCmd = &cobra.Command{ names, err := a.Networks.NetworkNetworkNameToNetworkIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Networks drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Databricks Account API network configuration ID") if err != nil { diff --git a/cmd/account/private-access/private-access.go b/cmd/account/private-access/private-access.go index 0a6f06e50..bc91e1b51 100755 --- a/cmd/account/private-access/private-access.go +++ b/cmd/account/private-access/private-access.go @@ -128,7 +128,7 @@ var deleteCmd = &cobra.Command{ names, err := a.PrivateAccess.PrivateAccessSettingsPrivateAccessSettingsNameToPrivateAccessSettingsIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Private Access drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Databricks Account API private access settings ID") if err != nil { @@ -193,7 +193,7 @@ var getCmd = &cobra.Command{ names, err := a.PrivateAccess.PrivateAccessSettingsPrivateAccessSettingsNameToPrivateAccessSettingsIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Private Access drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Databricks Account API private access settings ID") if err != nil { diff --git a/cmd/account/service-principals/service-principals.go b/cmd/account/service-principals/service-principals.go index f2bce37ab..7be4bc5a2 100755 --- a/cmd/account/service-principals/service-principals.go +++ b/cmd/account/service-principals/service-principals.go @@ -115,7 +115,7 @@ var deleteCmd = &cobra.Command{ names, err := a.ServicePrincipals.ServicePrincipalDisplayNameToIdMap(ctx, iam.ListAccountServicePrincipalsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Account Service Principals drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Unique ID for a service principal in the Databricks account") if err != nil { @@ -174,7 +174,7 @@ var getCmd = &cobra.Command{ names, err := a.ServicePrincipals.ServicePrincipalDisplayNameToIdMap(ctx, iam.ListAccountServicePrincipalsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Account Service Principals drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Unique ID for a service principal in the Databricks account") if err != nil { @@ -290,7 +290,7 @@ var patchCmd = &cobra.Command{ names, err := a.ServicePrincipals.ServicePrincipalDisplayNameToIdMap(ctx, iam.ListAccountServicePrincipalsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Account Service Principals drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Unique ID for a service principal in the Databricks account") if err != nil { @@ -359,7 +359,7 @@ var updateCmd = &cobra.Command{ names, err := a.ServicePrincipals.ServicePrincipalDisplayNameToIdMap(ctx, iam.ListAccountServicePrincipalsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Account Service Principals drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Databricks service principal ID") if err != nil { diff --git a/cmd/account/storage/storage.go b/cmd/account/storage/storage.go index 023d5894a..feedab5e2 100755 --- a/cmd/account/storage/storage.go +++ b/cmd/account/storage/storage.go @@ -114,7 +114,7 @@ var deleteCmd = &cobra.Command{ names, err := a.Storage.StorageConfigurationStorageConfigurationNameToStorageConfigurationIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Storage drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Databricks Account API storage configuration ID") if err != nil { @@ -172,7 +172,7 @@ var getCmd = &cobra.Command{ names, err := a.Storage.StorageConfigurationStorageConfigurationNameToStorageConfigurationIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Storage drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Databricks Account API storage configuration ID") if err != nil { diff --git a/cmd/account/users/users.go b/cmd/account/users/users.go index faf240d8e..8d976b9a6 100755 --- a/cmd/account/users/users.go +++ b/cmd/account/users/users.go @@ -124,7 +124,7 @@ var deleteCmd = &cobra.Command{ names, err := a.Users.UserUserNameToIdMap(ctx, iam.ListAccountUsersRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Account Users drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Unique ID for a user in the Databricks account") if err != nil { @@ -182,7 +182,7 @@ var getCmd = &cobra.Command{ names, err := a.Users.UserUserNameToIdMap(ctx, iam.ListAccountUsersRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Account Users drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Unique ID for a user in the Databricks account") if err != nil { @@ -298,7 +298,7 @@ var patchCmd = &cobra.Command{ names, err := a.Users.UserUserNameToIdMap(ctx, iam.ListAccountUsersRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Account Users drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Unique ID for a user in the Databricks account") if err != nil { @@ -367,7 +367,7 @@ var updateCmd = &cobra.Command{ names, err := a.Users.UserUserNameToIdMap(ctx, iam.ListAccountUsersRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Account Users drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Databricks user ID") if err != nil { diff --git a/cmd/account/vpc-endpoints/vpc-endpoints.go b/cmd/account/vpc-endpoints/vpc-endpoints.go index 295d7621f..778e88966 100755 --- a/cmd/account/vpc-endpoints/vpc-endpoints.go +++ b/cmd/account/vpc-endpoints/vpc-endpoints.go @@ -70,7 +70,7 @@ var createCmd = &cobra.Command{ names, err := a.VpcEndpoints.VpcEndpointVpcEndpointNameToVpcEndpointIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Vpc Endpoints drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The human-readable name of the storage configuration") if err != nil { @@ -136,7 +136,7 @@ var deleteCmd = &cobra.Command{ names, err := a.VpcEndpoints.VpcEndpointVpcEndpointNameToVpcEndpointIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Vpc Endpoints drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Databricks VPC endpoint ID") if err != nil { @@ -198,7 +198,7 @@ var getCmd = &cobra.Command{ names, err := a.VpcEndpoints.VpcEndpointVpcEndpointNameToVpcEndpointIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Vpc Endpoints drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Databricks VPC endpoint ID") if err != nil { diff --git a/cmd/account/workspaces/workspaces.go b/cmd/account/workspaces/workspaces.go index 4dbfe24e4..2c7a996e6 100755 --- a/cmd/account/workspaces/workspaces.go +++ b/cmd/account/workspaces/workspaces.go @@ -89,7 +89,7 @@ var createCmd = &cobra.Command{ names, err := a.Workspaces.WorkspaceWorkspaceNameToWorkspaceIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Workspaces drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The workspace's human-readable name") if err != nil { @@ -171,7 +171,7 @@ var deleteCmd = &cobra.Command{ names, err := a.Workspaces.WorkspaceWorkspaceNameToWorkspaceIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Workspaces drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Workspace ID") if err != nil { @@ -245,7 +245,7 @@ var getCmd = &cobra.Command{ names, err := a.Workspaces.WorkspaceWorkspaceNameToWorkspaceIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Workspaces drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Workspace ID") if err != nil { @@ -459,7 +459,7 @@ var updateCmd = &cobra.Command{ names, err := a.Workspaces.WorkspaceWorkspaceNameToWorkspaceIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Workspaces drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Workspace ID") if err != nil { diff --git a/cmd/workspace/alerts/alerts.go b/cmd/workspace/alerts/alerts.go index e1485d31a..5cdb0d483 100755 --- a/cmd/workspace/alerts/alerts.go +++ b/cmd/workspace/alerts/alerts.go @@ -111,7 +111,7 @@ var deleteCmd = &cobra.Command{ names, err := w.Alerts.AlertNameToIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Alerts drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "") if err != nil { @@ -169,7 +169,7 @@ var getCmd = &cobra.Command{ names, err := w.Alerts.AlertNameToIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Alerts drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "") if err != nil { diff --git a/cmd/workspace/cluster-policies/cluster-policies.go b/cmd/workspace/cluster-policies/cluster-policies.go index dce0a604f..66d3d8352 100755 --- a/cmd/workspace/cluster-policies/cluster-policies.go +++ b/cmd/workspace/cluster-policies/cluster-policies.go @@ -83,7 +83,7 @@ var createCmd = &cobra.Command{ names, err := w.ClusterPolicies.PolicyNameToPolicyIdMap(ctx, compute.ListClusterPoliciesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Cluster Policies drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Cluster Policy name requested by the user") if err != nil { @@ -142,7 +142,7 @@ var deleteCmd = &cobra.Command{ names, err := w.ClusterPolicies.PolicyNameToPolicyIdMap(ctx, compute.ListClusterPoliciesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Cluster Policies drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The ID of the policy to delete") if err != nil { @@ -256,7 +256,7 @@ var getCmd = &cobra.Command{ names, err := w.ClusterPolicies.PolicyNameToPolicyIdMap(ctx, compute.ListClusterPoliciesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Cluster Policies drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Canonical unique identifier for the cluster policy") if err != nil { diff --git a/cmd/workspace/clusters/clusters.go b/cmd/workspace/clusters/clusters.go index 10155161c..3a40b2d47 100755 --- a/cmd/workspace/clusters/clusters.go +++ b/cmd/workspace/clusters/clusters.go @@ -174,7 +174,7 @@ var createCmd = &cobra.Command{ names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Clusters drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The Spark version of the cluster, e.g") if err != nil { @@ -257,7 +257,7 @@ var deleteCmd = &cobra.Command{ names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Clusters drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The cluster to be terminated") if err != nil { @@ -448,7 +448,7 @@ var eventsCmd = &cobra.Command{ names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Clusters drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The ID of the cluster to retrieve events about") if err != nil { @@ -512,7 +512,7 @@ var getCmd = &cobra.Command{ names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Clusters drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The cluster about which to retrieve information") if err != nil { @@ -688,7 +688,7 @@ var permanentDeleteCmd = &cobra.Command{ names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Clusters drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The cluster to be deleted") if err != nil { @@ -748,7 +748,7 @@ var pinCmd = &cobra.Command{ names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Clusters drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "") if err != nil { @@ -815,7 +815,7 @@ var resizeCmd = &cobra.Command{ names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Clusters drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The cluster to be resized") if err != nil { @@ -898,7 +898,7 @@ var restartCmd = &cobra.Command{ names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Clusters drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The cluster to be started") if err != nil { @@ -1013,7 +1013,7 @@ var startCmd = &cobra.Command{ names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Clusters drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The cluster to be started") if err != nil { @@ -1090,7 +1090,7 @@ var unpinCmd = &cobra.Command{ names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Clusters drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "") if err != nil { diff --git a/cmd/workspace/dashboards/dashboards.go b/cmd/workspace/dashboards/dashboards.go index b7b1fa1c8..315d1e740 100755 --- a/cmd/workspace/dashboards/dashboards.go +++ b/cmd/workspace/dashboards/dashboards.go @@ -110,7 +110,7 @@ var deleteCmd = &cobra.Command{ names, err := w.Dashboards.DashboardNameToIdMap(ctx, sql.ListDashboardsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Dashboards drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "") if err != nil { @@ -169,7 +169,7 @@ var getCmd = &cobra.Command{ names, err := w.Dashboards.DashboardNameToIdMap(ctx, sql.ListDashboardsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Dashboards drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "") if err != nil { @@ -279,7 +279,7 @@ var restoreCmd = &cobra.Command{ names, err := w.Dashboards.DashboardNameToIdMap(ctx, sql.ListDashboardsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Dashboards drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "") if err != nil { diff --git a/cmd/workspace/git-credentials/git-credentials.go b/cmd/workspace/git-credentials/git-credentials.go index ea7242da9..161629888 100755 --- a/cmd/workspace/git-credentials/git-credentials.go +++ b/cmd/workspace/git-credentials/git-credentials.go @@ -65,7 +65,7 @@ var createCmd = &cobra.Command{ names, err := w.GitCredentials.CredentialInfoGitProviderToCredentialIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Git Credentials drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Git provider") if err != nil { @@ -123,7 +123,7 @@ var deleteCmd = &cobra.Command{ names, err := w.GitCredentials.CredentialInfoGitProviderToCredentialIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Git Credentials drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The ID for the corresponding credential to access") if err != nil { @@ -184,7 +184,7 @@ var getCmd = &cobra.Command{ names, err := w.GitCredentials.CredentialInfoGitProviderToCredentialIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Git Credentials drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The ID for the corresponding credential to access") if err != nil { @@ -277,7 +277,7 @@ var updateCmd = &cobra.Command{ names, err := w.GitCredentials.CredentialInfoGitProviderToCredentialIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Git Credentials drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The ID for the corresponding credential to access") if err != nil { diff --git a/cmd/workspace/global-init-scripts/global-init-scripts.go b/cmd/workspace/global-init-scripts/global-init-scripts.go index 090a2b352..3a2c3b649 100755 --- a/cmd/workspace/global-init-scripts/global-init-scripts.go +++ b/cmd/workspace/global-init-scripts/global-init-scripts.go @@ -114,7 +114,7 @@ var deleteCmd = &cobra.Command{ names, err := w.GlobalInitScripts.GlobalInitScriptDetailsNameToScriptIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Global Init Scripts drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The ID of the global init script") if err != nil { @@ -172,7 +172,7 @@ var getCmd = &cobra.Command{ names, err := w.GlobalInitScripts.GlobalInitScriptDetailsNameToScriptIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Global Init Scripts drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The ID of the global init script") if err != nil { diff --git a/cmd/workspace/groups/groups.go b/cmd/workspace/groups/groups.go index 9f85cdf33..aa5a7e355 100755 --- a/cmd/workspace/groups/groups.go +++ b/cmd/workspace/groups/groups.go @@ -116,7 +116,7 @@ var deleteCmd = &cobra.Command{ names, err := w.Groups.GroupDisplayNameToIdMap(ctx, iam.ListGroupsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Groups drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Unique ID for a group in the Databricks workspace") if err != nil { @@ -174,7 +174,7 @@ var getCmd = &cobra.Command{ names, err := w.Groups.GroupDisplayNameToIdMap(ctx, iam.ListGroupsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Groups drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Unique ID for a group in the Databricks workspace") if err != nil { @@ -289,7 +289,7 @@ var patchCmd = &cobra.Command{ names, err := w.Groups.GroupDisplayNameToIdMap(ctx, iam.ListGroupsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Groups drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Unique ID for a group in the Databricks workspace") if err != nil { @@ -355,7 +355,7 @@ var updateCmd = &cobra.Command{ names, err := w.Groups.GroupDisplayNameToIdMap(ctx, iam.ListGroupsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Groups drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Databricks group ID") if err != nil { diff --git a/cmd/workspace/instance-pools/instance-pools.go b/cmd/workspace/instance-pools/instance-pools.go index d78ae9396..c80feb59e 100755 --- a/cmd/workspace/instance-pools/instance-pools.go +++ b/cmd/workspace/instance-pools/instance-pools.go @@ -133,7 +133,7 @@ var deleteCmd = &cobra.Command{ names, err := w.InstancePools.InstancePoolAndStatsInstancePoolNameToInstancePoolIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Instance Pools drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The instance pool to be terminated") if err != nil { @@ -253,7 +253,7 @@ var getCmd = &cobra.Command{ names, err := w.InstancePools.InstancePoolAndStatsInstancePoolNameToInstancePoolIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Instance Pools drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The canonical unique identifier for the instance pool") if err != nil { diff --git a/cmd/workspace/ip-access-lists/ip-access-lists.go b/cmd/workspace/ip-access-lists/ip-access-lists.go index e29339747..bbefc063a 100755 --- a/cmd/workspace/ip-access-lists/ip-access-lists.go +++ b/cmd/workspace/ip-access-lists/ip-access-lists.go @@ -138,7 +138,7 @@ var deleteCmd = &cobra.Command{ names, err := w.IpAccessLists.IpAccessListInfoLabelToListIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Ip Access Lists drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The ID for the corresponding IP access list to modify") if err != nil { @@ -196,7 +196,7 @@ var getCmd = &cobra.Command{ names, err := w.IpAccessLists.IpAccessListInfoLabelToListIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Ip Access Lists drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The ID for the corresponding IP access list to modify") if err != nil { diff --git a/cmd/workspace/jobs/jobs.go b/cmd/workspace/jobs/jobs.go index 601293eea..77eea5686 100755 --- a/cmd/workspace/jobs/jobs.go +++ b/cmd/workspace/jobs/jobs.go @@ -74,7 +74,7 @@ var cancelAllRunsCmd = &cobra.Command{ names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Jobs drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The canonical identifier of the job to cancel all runs of") if err != nil { @@ -141,7 +141,7 @@ var cancelRunCmd = &cobra.Command{ names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Jobs drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "This field is required") if err != nil { @@ -290,7 +290,7 @@ var deleteCmd = &cobra.Command{ names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Jobs drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The canonical identifier of the job to delete") if err != nil { @@ -351,7 +351,7 @@ var deleteRunCmd = &cobra.Command{ names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Jobs drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The canonical identifier of the run for which to retrieve the metadata") if err != nil { @@ -414,7 +414,7 @@ var exportRunCmd = &cobra.Command{ names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Jobs drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The canonical identifier for the run") if err != nil { @@ -475,7 +475,7 @@ var getCmd = &cobra.Command{ names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Jobs drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The canonical identifier of the job to retrieve information about") if err != nil { @@ -543,7 +543,7 @@ var getRunCmd = &cobra.Command{ names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Jobs drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The canonical identifier of the run for which to retrieve the metadata") if err != nil { @@ -613,7 +613,7 @@ var getRunOutputCmd = &cobra.Command{ names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Jobs drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The canonical identifier for the run") if err != nil { @@ -802,7 +802,7 @@ var repairRunCmd = &cobra.Command{ names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Jobs drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The job run ID of the run to repair") if err != nil { @@ -951,7 +951,7 @@ var runNowCmd = &cobra.Command{ names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Jobs drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The ID of the job to be executed") if err != nil { @@ -1128,7 +1128,7 @@ var updateCmd = &cobra.Command{ names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Jobs drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The canonical identifier of the job to update") if err != nil { diff --git a/cmd/workspace/metastores/metastores.go b/cmd/workspace/metastores/metastores.go index 589140a06..4df439d49 100755 --- a/cmd/workspace/metastores/metastores.go +++ b/cmd/workspace/metastores/metastores.go @@ -201,7 +201,7 @@ var deleteCmd = &cobra.Command{ names, err := w.Metastores.MetastoreInfoNameToMetastoreIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Metastores drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Unique ID of the metastore") if err != nil { @@ -260,7 +260,7 @@ var getCmd = &cobra.Command{ names, err := w.Metastores.MetastoreInfoNameToMetastoreIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Metastores drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Unique ID of the metastore") if err != nil { @@ -488,7 +488,7 @@ var updateCmd = &cobra.Command{ names, err := w.Metastores.MetastoreInfoNameToMetastoreIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Metastores drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Unique ID of the metastore") if err != nil { @@ -552,7 +552,7 @@ var updateAssignmentCmd = &cobra.Command{ names, err := w.Metastores.MetastoreInfoNameToMetastoreIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Metastores drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "A workspace ID") if err != nil { diff --git a/cmd/workspace/pipelines/pipelines.go b/cmd/workspace/pipelines/pipelines.go index 1d2871749..8ef29664f 100755 --- a/cmd/workspace/pipelines/pipelines.go +++ b/cmd/workspace/pipelines/pipelines.go @@ -136,7 +136,7 @@ var deleteCmd = &cobra.Command{ names, err := w.Pipelines.PipelineStateInfoNameToPipelineIdMap(ctx, pipelines.ListPipelinesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Pipelines drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "") if err != nil { @@ -197,7 +197,7 @@ var getCmd = &cobra.Command{ names, err := w.Pipelines.PipelineStateInfoNameToPipelineIdMap(ctx, pipelines.ListPipelinesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Pipelines drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "") if err != nil { @@ -309,7 +309,7 @@ var listPipelineEventsCmd = &cobra.Command{ names, err := w.Pipelines.PipelineStateInfoNameToPipelineIdMap(ctx, pipelines.ListPipelinesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Pipelines drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "") if err != nil { @@ -423,7 +423,7 @@ var listUpdatesCmd = &cobra.Command{ names, err := w.Pipelines.PipelineStateInfoNameToPipelineIdMap(ctx, pipelines.ListPipelinesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Pipelines drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The pipeline to return updates for") if err != nil { @@ -486,7 +486,7 @@ var resetCmd = &cobra.Command{ names, err := w.Pipelines.PipelineStateInfoNameToPipelineIdMap(ctx, pipelines.ListPipelinesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Pipelines drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "") if err != nil { @@ -566,7 +566,7 @@ var startUpdateCmd = &cobra.Command{ names, err := w.Pipelines.PipelineStateInfoNameToPipelineIdMap(ctx, pipelines.ListPipelinesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Pipelines drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "") if err != nil { @@ -629,7 +629,7 @@ var stopCmd = &cobra.Command{ names, err := w.Pipelines.PipelineStateInfoNameToPipelineIdMap(ctx, pipelines.ListPipelinesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Pipelines drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "") if err != nil { @@ -724,7 +724,7 @@ var updateCmd = &cobra.Command{ names, err := w.Pipelines.PipelineStateInfoNameToPipelineIdMap(ctx, pipelines.ListPipelinesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Pipelines drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Unique identifier for this pipeline") if err != nil { diff --git a/cmd/workspace/providers/providers.go b/cmd/workspace/providers/providers.go index c9dd3cd0a..3fd237528 100755 --- a/cmd/workspace/providers/providers.go +++ b/cmd/workspace/providers/providers.go @@ -111,7 +111,7 @@ var deleteCmd = &cobra.Command{ names, err := w.Providers.ProviderInfoNameToMetastoreIdMap(ctx, sharing.ListProvidersRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Providers drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Name of the provider") if err != nil { @@ -171,7 +171,7 @@ var getCmd = &cobra.Command{ names, err := w.Providers.ProviderInfoNameToMetastoreIdMap(ctx, sharing.ListProvidersRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Providers drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Name of the provider") if err != nil { @@ -283,7 +283,7 @@ var listSharesCmd = &cobra.Command{ names, err := w.Providers.ProviderInfoNameToMetastoreIdMap(ctx, sharing.ListProvidersRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Providers drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Name of the provider in which to list shares") if err != nil { @@ -349,7 +349,7 @@ var updateCmd = &cobra.Command{ names, err := w.Providers.ProviderInfoNameToMetastoreIdMap(ctx, sharing.ListProvidersRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Providers drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The name of the Provider") if err != nil { diff --git a/cmd/workspace/queries/queries.go b/cmd/workspace/queries/queries.go index fa83408aa..ea4d2bac0 100755 --- a/cmd/workspace/queries/queries.go +++ b/cmd/workspace/queries/queries.go @@ -121,7 +121,7 @@ var deleteCmd = &cobra.Command{ names, err := w.Queries.QueryNameToIdMap(ctx, sql.ListQueriesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Queries drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "") if err != nil { @@ -180,7 +180,7 @@ var getCmd = &cobra.Command{ names, err := w.Queries.QueryNameToIdMap(ctx, sql.ListQueriesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Queries drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "") if err != nil { @@ -292,7 +292,7 @@ var restoreCmd = &cobra.Command{ names, err := w.Queries.QueryNameToIdMap(ctx, sql.ListQueriesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Queries drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "") if err != nil { @@ -358,7 +358,7 @@ var updateCmd = &cobra.Command{ names, err := w.Queries.QueryNameToIdMap(ctx, sql.ListQueriesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Queries drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "") if err != nil { diff --git a/cmd/workspace/recipients/recipients.go b/cmd/workspace/recipients/recipients.go index 2f907a6d8..0d615aa4d 100755 --- a/cmd/workspace/recipients/recipients.go +++ b/cmd/workspace/recipients/recipients.go @@ -116,7 +116,7 @@ var deleteCmd = &cobra.Command{ names, err := w.Recipients.RecipientInfoNameToMetastoreIdMap(ctx, sharing.ListRecipientsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Recipients drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Name of the recipient") if err != nil { @@ -176,7 +176,7 @@ var getCmd = &cobra.Command{ names, err := w.Recipients.RecipientInfoNameToMetastoreIdMap(ctx, sharing.ListRecipientsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Recipients drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Name of the recipient") if err != nil { @@ -340,7 +340,7 @@ var sharePermissionsCmd = &cobra.Command{ names, err := w.Recipients.RecipientInfoNameToMetastoreIdMap(ctx, sharing.ListRecipientsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Recipients drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The name of the Recipient") if err != nil { @@ -406,7 +406,7 @@ var updateCmd = &cobra.Command{ names, err := w.Recipients.RecipientInfoNameToMetastoreIdMap(ctx, sharing.ListRecipientsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Recipients drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Name of Recipient") if err != nil { diff --git a/cmd/workspace/repos/repos.go b/cmd/workspace/repos/repos.go index d3e95fc78..09e497dfc 100755 --- a/cmd/workspace/repos/repos.go +++ b/cmd/workspace/repos/repos.go @@ -117,7 +117,7 @@ var deleteCmd = &cobra.Command{ names, err := w.Repos.RepoInfoPathToIdMap(ctx, workspace.ListReposRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Repos drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The ID for the corresponding repo to access") if err != nil { @@ -178,7 +178,7 @@ var getCmd = &cobra.Command{ names, err := w.Repos.RepoInfoPathToIdMap(ctx, workspace.ListReposRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Repos drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The ID for the corresponding repo to access") if err != nil { @@ -295,7 +295,7 @@ var updateCmd = &cobra.Command{ names, err := w.Repos.RepoInfoPathToIdMap(ctx, workspace.ListReposRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Repos drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The ID for the corresponding repo to access") if err != nil { diff --git a/cmd/workspace/schemas/schemas.go b/cmd/workspace/schemas/schemas.go index c4bce9dd5..a1216dfa6 100755 --- a/cmd/workspace/schemas/schemas.go +++ b/cmd/workspace/schemas/schemas.go @@ -114,7 +114,7 @@ var deleteCmd = &cobra.Command{ names, err := w.Schemas.SchemaInfoNameToFullNameMap(ctx, catalog.ListSchemasRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Schemas drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Full name of the schema") if err != nil { @@ -174,7 +174,7 @@ var getCmd = &cobra.Command{ names, err := w.Schemas.SchemaInfoNameToFullNameMap(ctx, catalog.ListSchemasRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Schemas drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Full name of the schema") if err != nil { @@ -293,7 +293,7 @@ var updateCmd = &cobra.Command{ names, err := w.Schemas.SchemaInfoNameToFullNameMap(ctx, catalog.ListSchemasRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Schemas drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Full name of the schema") if err != nil { diff --git a/cmd/workspace/service-principals/service-principals.go b/cmd/workspace/service-principals/service-principals.go index ea52d52a4..db03aad09 100755 --- a/cmd/workspace/service-principals/service-principals.go +++ b/cmd/workspace/service-principals/service-principals.go @@ -115,7 +115,7 @@ var deleteCmd = &cobra.Command{ names, err := w.ServicePrincipals.ServicePrincipalDisplayNameToIdMap(ctx, iam.ListServicePrincipalsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Service Principals drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Unique ID for a service principal in the Databricks workspace") if err != nil { @@ -174,7 +174,7 @@ var getCmd = &cobra.Command{ names, err := w.ServicePrincipals.ServicePrincipalDisplayNameToIdMap(ctx, iam.ListServicePrincipalsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Service Principals drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Unique ID for a service principal in the Databricks workspace") if err != nil { @@ -290,7 +290,7 @@ var patchCmd = &cobra.Command{ names, err := w.ServicePrincipals.ServicePrincipalDisplayNameToIdMap(ctx, iam.ListServicePrincipalsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Service Principals drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Unique ID for a service principal in the Databricks workspace") if err != nil { @@ -359,7 +359,7 @@ var updateCmd = &cobra.Command{ names, err := w.ServicePrincipals.ServicePrincipalDisplayNameToIdMap(ctx, iam.ListServicePrincipalsRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Service Principals drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Databricks service principal ID") if err != nil { diff --git a/cmd/workspace/tables/tables.go b/cmd/workspace/tables/tables.go index c4f0dd80f..a8bee878e 100755 --- a/cmd/workspace/tables/tables.go +++ b/cmd/workspace/tables/tables.go @@ -66,7 +66,7 @@ var deleteCmd = &cobra.Command{ names, err := w.Tables.TableInfoNameToTableIdMap(ctx, catalog.ListTablesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Tables drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Full name of the table") if err != nil { @@ -130,7 +130,7 @@ var getCmd = &cobra.Command{ names, err := w.Tables.TableInfoNameToTableIdMap(ctx, catalog.ListTablesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Tables drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Full name of the table") if err != nil { @@ -261,7 +261,7 @@ var listSummariesCmd = &cobra.Command{ names, err := w.Tables.TableInfoNameToTableIdMap(ctx, catalog.ListTablesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Tables drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Name of parent catalog for tables of interest") if err != nil { diff --git a/cmd/workspace/token-management/token-management.go b/cmd/workspace/token-management/token-management.go index 03c32b595..0b56f7b58 100755 --- a/cmd/workspace/token-management/token-management.go +++ b/cmd/workspace/token-management/token-management.go @@ -110,7 +110,7 @@ var deleteCmd = &cobra.Command{ names, err := w.TokenManagement.TokenInfoCommentToTokenIdMap(ctx, settings.ListTokenManagementRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Token Management drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The ID of the token to get") if err != nil { @@ -168,7 +168,7 @@ var getCmd = &cobra.Command{ names, err := w.TokenManagement.TokenInfoCommentToTokenIdMap(ctx, settings.ListTokenManagementRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Token Management drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The ID of the token to get") if err != nil { diff --git a/cmd/workspace/tokens/tokens.go b/cmd/workspace/tokens/tokens.go index 359f1afd8..7ee5f0c80 100755 --- a/cmd/workspace/tokens/tokens.go +++ b/cmd/workspace/tokens/tokens.go @@ -111,7 +111,7 @@ var deleteCmd = &cobra.Command{ names, err := w.Tokens.TokenInfoCommentToTokenIdMap(ctx) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Tokens drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The ID of the token to be revoked") if err != nil { diff --git a/cmd/workspace/users/users.go b/cmd/workspace/users/users.go index fec18927a..95301548a 100755 --- a/cmd/workspace/users/users.go +++ b/cmd/workspace/users/users.go @@ -124,7 +124,7 @@ var deleteCmd = &cobra.Command{ names, err := w.Users.UserUserNameToIdMap(ctx, iam.ListUsersRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Users drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Unique ID for a user in the Databricks workspace") if err != nil { @@ -182,7 +182,7 @@ var getCmd = &cobra.Command{ names, err := w.Users.UserUserNameToIdMap(ctx, iam.ListUsersRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Users drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Unique ID for a user in the Databricks workspace") if err != nil { @@ -298,7 +298,7 @@ var patchCmd = &cobra.Command{ names, err := w.Users.UserUserNameToIdMap(ctx, iam.ListUsersRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Users drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Unique ID for a user in the Databricks workspace") if err != nil { @@ -367,7 +367,7 @@ var updateCmd = &cobra.Command{ names, err := w.Users.UserUserNameToIdMap(ctx, iam.ListUsersRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Users drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Databricks user ID") if err != nil { diff --git a/cmd/workspace/volumes/volumes.go b/cmd/workspace/volumes/volumes.go index 8364850d4..a584dcebe 100755 --- a/cmd/workspace/volumes/volumes.go +++ b/cmd/workspace/volumes/volumes.go @@ -139,7 +139,7 @@ var deleteCmd = &cobra.Command{ names, err := w.Volumes.VolumeInfoNameToVolumeIdMap(ctx, catalog.ListVolumesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Volumes drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The three-level (fully qualified) name of the volume") if err != nil { @@ -261,7 +261,7 @@ var readCmd = &cobra.Command{ names, err := w.Volumes.VolumeInfoNameToVolumeIdMap(ctx, catalog.ListVolumesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Volumes drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The three-level (fully qualified) name of the volume") if err != nil { @@ -330,7 +330,7 @@ var updateCmd = &cobra.Command{ names, err := w.Volumes.VolumeInfoNameToVolumeIdMap(ctx, catalog.ListVolumesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Volumes drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The three-level (fully qualified) name of the volume") if err != nil { diff --git a/cmd/workspace/warehouses/warehouses.go b/cmd/workspace/warehouses/warehouses.go index ad8ef1c7a..3387e36ee 100755 --- a/cmd/workspace/warehouses/warehouses.go +++ b/cmd/workspace/warehouses/warehouses.go @@ -153,7 +153,7 @@ var deleteCmd = &cobra.Command{ names, err := w.Warehouses.EndpointInfoNameToIdMap(ctx, sql.ListWarehousesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Warehouses drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Required") if err != nil { @@ -254,7 +254,7 @@ var editCmd = &cobra.Command{ names, err := w.Warehouses.EndpointInfoNameToIdMap(ctx, sql.ListWarehousesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Warehouses drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Required") if err != nil { @@ -341,7 +341,7 @@ var getCmd = &cobra.Command{ names, err := w.Warehouses.EndpointInfoNameToIdMap(ctx, sql.ListWarehousesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Warehouses drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Required") if err != nil { @@ -539,7 +539,7 @@ var startCmd = &cobra.Command{ names, err := w.Warehouses.EndpointInfoNameToIdMap(ctx, sql.ListWarehousesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Warehouses drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Required") if err != nil { @@ -626,7 +626,7 @@ var stopCmd = &cobra.Command{ names, err := w.Warehouses.EndpointInfoNameToIdMap(ctx, sql.ListWarehousesRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Warehouses drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "Required") if err != nil { diff --git a/cmd/workspace/workspace/workspace.go b/cmd/workspace/workspace/workspace.go index 03598c5ff..c942d7aa5 100755 --- a/cmd/workspace/workspace/workspace.go +++ b/cmd/workspace/workspace/workspace.go @@ -67,7 +67,7 @@ var deleteCmd = &cobra.Command{ names, err := w.Workspace.ObjectInfoPathToObjectIdMap(ctx, workspace.ListWorkspaceRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Workspace drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The absolute path of the notebook or directory") if err != nil { @@ -135,7 +135,7 @@ var exportCmd = &cobra.Command{ names, err := w.Workspace.ObjectInfoPathToObjectIdMap(ctx, workspace.ListWorkspaceRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Workspace drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The absolute path of the object or directory") if err != nil { @@ -194,7 +194,7 @@ var getStatusCmd = &cobra.Command{ names, err := w.Workspace.ObjectInfoPathToObjectIdMap(ctx, workspace.ListWorkspaceRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Workspace drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The absolute path of the notebook or directory") if err != nil { @@ -260,7 +260,7 @@ var importCmd = &cobra.Command{ names, err := w.Workspace.ObjectInfoPathToObjectIdMap(ctx, workspace.ListWorkspaceRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Workspace drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The absolute path of the object or directory") if err != nil { @@ -375,7 +375,7 @@ var mkdirsCmd = &cobra.Command{ names, err := w.Workspace.ObjectInfoPathToObjectIdMap(ctx, workspace.ListWorkspaceRequest{}) close(promptSpinner) if err != nil { - return err + return fmt.Errorf("failed to load names for Workspace drop-down. Please manually specify required arguments. Original error: %w", err) } id, err := cmdio.Select(ctx, names, "The absolute path of the directory") if err != nil { From 1f130f37224c6f5dd3f1b27d30e38fd5ed853290 Mon Sep 17 00:00:00 2001 From: Andrew Nester Date: Mon, 5 Jun 2023 17:30:40 +0200 Subject: [PATCH 7/9] Do not use FgWhite and FgBlack for terminal output (#435) ## Changes Using white / black color for terminal output will lead to poorly displayed content in either light or dark terminal backgrounds. Some other CLIs experienced same issues (https://github.com/qri-io/qri/pull/774) Instead, let's just use color to highlight some of the output so it's more compatible with different background styles ## Tests Screenshot 2023-06-05 at 16 05 09 --- Screenshot 2023-06-05 at 16 05 20 --- cmd/auth/profiles.go | 4 ++-- cmd/workspace/catalogs/overrides.go | 2 +- cmd/workspace/clusters/overrides.go | 4 ++-- cmd/workspace/dashboards/overrides.go | 2 +- cmd/workspace/external-locations/overrides.go | 4 ++-- cmd/workspace/jobs/overrides.go | 4 ++-- cmd/workspace/metastores/overrides.go | 4 ++-- cmd/workspace/queries/overrides.go | 4 ++-- cmd/workspace/query-history/overrides.go | 2 +- cmd/workspace/schemas/overrides.go | 4 ++-- cmd/workspace/secrets/overrides.go | 2 +- cmd/workspace/storage-credentials/overrides.go | 4 ++-- cmd/workspace/tables/overrides.go | 2 +- cmd/workspace/token-management/overrides.go | 4 ++-- cmd/workspace/tokens/overrides.go | 4 ++-- cmd/workspace/warehouses/overrides.go | 4 ++-- cmd/workspace/workspace/overrides.go | 4 ++-- libs/cmdio/render.go | 8 ++++---- 18 files changed, 33 insertions(+), 33 deletions(-) diff --git a/cmd/auth/profiles.go b/cmd/auth/profiles.go index 465d45bfb..d3b167b77 100644 --- a/cmd/auth/profiles.go +++ b/cmd/auth/profiles.go @@ -99,8 +99,8 @@ var profilesCmd = &cobra.Command{ Short: "Lists profiles from ~/.databrickscfg", Annotations: map[string]string{ "template": cmdio.Heredoc(` - {{white "Name"}} {{white "Host"}} {{white "Valid"}} - {{range .Profiles}}{{.Name | green}} {{.Host|white}} {{bool .Valid}} + {{header "Name"}} {{header "Host"}} {{header "Valid"}} + {{range .Profiles}}{{.Name | green}} {{.Host|cyan}} {{bool .Valid}} {{end}}`), }, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/workspace/catalogs/overrides.go b/cmd/workspace/catalogs/overrides.go index 574c95778..5b8cffea9 100644 --- a/cmd/workspace/catalogs/overrides.go +++ b/cmd/workspace/catalogs/overrides.go @@ -4,7 +4,7 @@ import "github.com/databricks/cli/libs/cmdio" func init() { listCmd.Annotations["template"] = cmdio.Heredoc(` - {{white "Name"}} {{white "Type"}} {{white "Comment"}} + {{header "Name"}} {{header "Type"}} {{header "Comment"}} {{range .}}{{.Name|green}} {{blue "%s" .CatalogType}} {{.Comment}} {{end}}`) } diff --git a/cmd/workspace/clusters/overrides.go b/cmd/workspace/clusters/overrides.go index f98ac5929..1e8818952 100644 --- a/cmd/workspace/clusters/overrides.go +++ b/cmd/workspace/clusters/overrides.go @@ -4,8 +4,8 @@ import "github.com/databricks/cli/libs/cmdio" func init() { listCmd.Annotations["template"] = cmdio.Heredoc(` - {{white "ID"}} {{white "Name"}} {{white "State"}} - {{range .}}{{.ClusterId | green}} {{.ClusterName|white}} {{if eq .State "RUNNING"}}{{green "%s" .State}}{{else if eq .State "TERMINATED"}}{{red "%s" .State}}{{else}}{{blue "%s" .State}}{{end}} + {{header "ID"}} {{header "Name"}} {{header "State"}} + {{range .}}{{.ClusterId | green}} {{.ClusterName | cyan}} {{if eq .State "RUNNING"}}{{green "%s" .State}}{{else if eq .State "TERMINATED"}}{{red "%s" .State}}{{else}}{{blue "%s" .State}}{{end}} {{end}}`) listNodeTypesCmd.Annotations["template"] = cmdio.Heredoc(` diff --git a/cmd/workspace/dashboards/overrides.go b/cmd/workspace/dashboards/overrides.go index 87bc14e4f..ba7e42ec7 100644 --- a/cmd/workspace/dashboards/overrides.go +++ b/cmd/workspace/dashboards/overrides.go @@ -4,7 +4,7 @@ import "github.com/databricks/cli/libs/cmdio" func init() { listCmd.Annotations["template"] = cmdio.Heredoc(` - {{white "ID"}} {{white "Name"}} + {{header "ID"}} {{header "Name"}} {{range .}}{{.Id|green}} {{.Name}} {{end}}`) } diff --git a/cmd/workspace/external-locations/overrides.go b/cmd/workspace/external-locations/overrides.go index 7afd7da0c..7efd193d9 100644 --- a/cmd/workspace/external-locations/overrides.go +++ b/cmd/workspace/external-locations/overrides.go @@ -4,7 +4,7 @@ import "github.com/databricks/cli/libs/cmdio" func init() { listCmd.Annotations["template"] = cmdio.Heredoc(` - {{white "Name"}} {{white "Credential"}} {{white "URL"}} - {{range .}}{{.Name|green}} {{.CredentialName|blue}} {{.Url}} + {{header "Name"}} {{header "Credential"}} {{header "URL"}} + {{range .}}{{.Name|green}} {{.CredentialName|cyan}} {{.Url}} {{end}}`) } diff --git a/cmd/workspace/jobs/overrides.go b/cmd/workspace/jobs/overrides.go index 103176cba..93512c84a 100644 --- a/cmd/workspace/jobs/overrides.go +++ b/cmd/workspace/jobs/overrides.go @@ -8,7 +8,7 @@ func init() { {{end}}`) listRunsCmd.Annotations["template"] = cmdio.Heredoc(` - {{"Job ID"|white}} {{"Run ID"|white}} {{"Result State"|white}} URL - {{range .}}{{green "%d" .JobId}} {{blue "%d" .RunId}} {{if eq .State.ResultState "SUCCESS"}}{{"SUCCESS"|green}}{{else}}{{red "%s" .State.ResultState}}{{end}} {{.RunPageUrl}} + {{header "Job ID"}} {{header "Run ID"}} {{header "Result State"}} URL + {{range .}}{{green "%d" .JobId}} {{cyan "%d" .RunId}} {{if eq .State.ResultState "SUCCESS"}}{{"SUCCESS"|green}}{{else}}{{red "%s" .State.ResultState}}{{end}} {{.RunPageUrl}} {{end}}`) } diff --git a/cmd/workspace/metastores/overrides.go b/cmd/workspace/metastores/overrides.go index d53675d02..9d1c23ac2 100644 --- a/cmd/workspace/metastores/overrides.go +++ b/cmd/workspace/metastores/overrides.go @@ -4,7 +4,7 @@ import "github.com/databricks/cli/libs/cmdio" func init() { listCmd.Annotations["template"] = cmdio.Heredoc(` - {{white "ID"}} {{white "Name"}} {{white "Region"}} - {{range .}}{{.MetastoreId|green}} {{.Name|white}} {{.Region}} + {{header "ID"}} {{header "Name"}} {{"Region"}} + {{range .}}{{.MetastoreId|green}} {{.Name|cyan}} {{.Region}} {{end}}`) } diff --git a/cmd/workspace/queries/overrides.go b/cmd/workspace/queries/overrides.go index cc22ffaee..86f47388e 100644 --- a/cmd/workspace/queries/overrides.go +++ b/cmd/workspace/queries/overrides.go @@ -5,7 +5,7 @@ import "github.com/databricks/cli/libs/cmdio" func init() { // TODO: figure out colored/non-colored headers and colspan shifts listCmd.Annotations["template"] = cmdio.Heredoc(` - {{white "ID"}} {{white "Name"}} {{white "Author"}} - {{range .}}{{.Id|green}} {{.Name|white}} {{.User.Email|white}} + {{header "ID"}} {{header "Name"}} {{header "Author"}} + {{range .}}{{.Id|green}} {{.Name|cyan}} {{.User.Email|cyan}} {{end}}`) } diff --git a/cmd/workspace/query-history/overrides.go b/cmd/workspace/query-history/overrides.go index 11f0d9c8d..7e7020697 100644 --- a/cmd/workspace/query-history/overrides.go +++ b/cmd/workspace/query-history/overrides.go @@ -5,6 +5,6 @@ import "github.com/databricks/cli/libs/cmdio" func init() { // TODO: figure out the right format listCmd.Annotations["template"] = cmdio.Heredoc(` - {{range .}}{{.UserName}} {{white "%s" .Status}} {{.QueryText}} + {{range .}}{{.UserName}} {{cyan "%s" .Status}} {{.QueryText}} {{end}}`) } diff --git a/cmd/workspace/schemas/overrides.go b/cmd/workspace/schemas/overrides.go index fbf4bebcd..4ff8bf124 100644 --- a/cmd/workspace/schemas/overrides.go +++ b/cmd/workspace/schemas/overrides.go @@ -4,7 +4,7 @@ import "github.com/databricks/cli/libs/cmdio" func init() { listCmd.Annotations["template"] = cmdio.Heredoc(` - {{white "Full Name"}} {{white "Owner"}} {{white "Comment"}} - {{range .}}{{.FullName|green}} {{.Owner|white}} {{.Comment}} + {{header "Full Name"}} {{header "Owner"}} {{header "Comment"}} + {{range .}}{{.FullName|green}} {{.Owner|cyan}} {{.Comment}} {{end}}`) } diff --git a/cmd/workspace/secrets/overrides.go b/cmd/workspace/secrets/overrides.go index e3ab714f4..d46284bf6 100644 --- a/cmd/workspace/secrets/overrides.go +++ b/cmd/workspace/secrets/overrides.go @@ -10,7 +10,7 @@ import ( func init() { listScopesCmd.Annotations["template"] = cmdio.Heredoc(` - {{white "Scope"}} {{white "Backend Type"}} + {{header "Scope"}} {{header "Backend Type"}} {{range .}}{{.Name|green}} {{.BackendType}} {{end}}`) diff --git a/cmd/workspace/storage-credentials/overrides.go b/cmd/workspace/storage-credentials/overrides.go index e9643d39b..8bce9ffa2 100644 --- a/cmd/workspace/storage-credentials/overrides.go +++ b/cmd/workspace/storage-credentials/overrides.go @@ -4,7 +4,7 @@ import "github.com/databricks/cli/libs/cmdio" func init() { listCmd.Annotations["template"] = cmdio.Heredoc(` - {{white "ID"}} {{white "Name"}} {{white "Credentials"}} - {{range .}}{{.Id|green}} {{.Name|white}} {{if .AwsIamRole}}{{.AwsIamRole.RoleArn}}{{end}}{{if .AzureServicePrincipal}}{{.AzureServicePrincipal.ApplicationId}}{{end}}{{if .GcpServiceAccountKey}}{{.Email}}{{end}} + {{header "ID"}} {{header "Name"}} {{header "Credentials"}} + {{range .}}{{.Id|green}} {{.Name|cyan}} {{if .AwsIamRole}}{{.AwsIamRole.RoleArn}}{{end}}{{if .AzureServicePrincipal}}{{.AzureServicePrincipal.ApplicationId}}{{end}}{{if .GcpServiceAccountKey}}{{.Email}}{{end}} {{end}}`) } diff --git a/cmd/workspace/tables/overrides.go b/cmd/workspace/tables/overrides.go index 128821c23..ed9c86ed5 100644 --- a/cmd/workspace/tables/overrides.go +++ b/cmd/workspace/tables/overrides.go @@ -4,7 +4,7 @@ import "github.com/databricks/cli/libs/cmdio" func init() { listCmd.Annotations["template"] = cmdio.Heredoc(` - {{white "Full Name"}} {{white "Table Type"}} + {{header "Full Name"}} {{header "Table Type"}} {{range .}}{{.FullName|green}} {{blue "%s" .TableType}} {{end}}`) } diff --git a/cmd/workspace/token-management/overrides.go b/cmd/workspace/token-management/overrides.go index ea3bbaf95..2070e2a2b 100644 --- a/cmd/workspace/token-management/overrides.go +++ b/cmd/workspace/token-management/overrides.go @@ -4,7 +4,7 @@ import "github.com/databricks/cli/libs/cmdio" func init() { listCmd.Annotations["template"] = cmdio.Heredoc(` - {{white "ID"}} {{white "Created By"}} {{white "Comment"}} - {{range .}}{{.TokenId|green}} {{.CreatedByUsername|white}} {{.Comment|white}} + {{header "ID"}} {{header "Created By"}} {{header "Comment"}} + {{range .}}{{.TokenId|green}} {{.CreatedByUsername|cyan}} {{.Comment|cyan}} {{end}}`) } diff --git a/cmd/workspace/tokens/overrides.go b/cmd/workspace/tokens/overrides.go index 8d9ba41f2..b5673c0e9 100644 --- a/cmd/workspace/tokens/overrides.go +++ b/cmd/workspace/tokens/overrides.go @@ -4,7 +4,7 @@ import "github.com/databricks/cli/libs/cmdio" func init() { listCmd.Annotations["template"] = cmdio.Heredoc(` - {{white "ID"}} {{white "Expiry time"}} {{white "Comment"}} - {{range .}}{{.TokenId|green}} {{white "%d" .ExpiryTime}} {{.Comment|white}} + {{header "ID"}} {{header "Expiry time"}} {{header "Comment"}} + {{range .}}{{.TokenId|green}} {{cyan "%d" .ExpiryTime}} {{.Comment|cyan}} {{end}}`) } diff --git a/cmd/workspace/warehouses/overrides.go b/cmd/workspace/warehouses/overrides.go index 5f7723300..82319d6fc 100644 --- a/cmd/workspace/warehouses/overrides.go +++ b/cmd/workspace/warehouses/overrides.go @@ -4,7 +4,7 @@ import "github.com/databricks/cli/libs/cmdio" func init() { listCmd.Annotations["template"] = cmdio.Heredoc(` - {{white "ID"}} {{white "Name"}} {{white "Size"}} {{white "State"}} - {{range .}}{{.Id|green}} {{.Name|white}} {{.ClusterSize|white}} {{if eq .State "RUNNING"}}{{"RUNNING"|green}}{{else if eq .State "STOPPED"}}{{"STOPPED"|red}}{{else}}{{blue "%s" .State}}{{end}} + {{header "ID"}} {{header "Name"}} {{header "Size"}} {{header "State"}} + {{range .}}{{.Id|green}} {{.Name|cyan}} {{.ClusterSize|cyan}} {{if eq .State "RUNNING"}}{{"RUNNING"|green}}{{else if eq .State "STOPPED"}}{{"STOPPED"|red}}{{else}}{{blue "%s" .State}}{{end}} {{end}}`) } diff --git a/cmd/workspace/workspace/overrides.go b/cmd/workspace/workspace/overrides.go index 611868905..0a00ba259 100644 --- a/cmd/workspace/workspace/overrides.go +++ b/cmd/workspace/workspace/overrides.go @@ -5,7 +5,7 @@ import "github.com/databricks/cli/libs/cmdio" func init() { listReq.Path = "/" listCmd.Annotations["template"] = cmdio.Heredoc(` - {{white "ID"}} {{white "Type"}} {{white "Language"}} {{white "Path"}} - {{range .}}{{green "%d" .ObjectId}} {{blue "%s" .ObjectType}} {{cyan "%s" .Language}} {{.Path|white}} + {{header "ID"}} {{header "Type"}} {{header "Language"}} {{header "Path"}} + {{range .}}{{green "%d" .ObjectId}} {{blue "%s" .ObjectType}} {{cyan "%s" .Language}} {{.Path|cyan}} {{end}}`) } diff --git a/libs/cmdio/render.go b/libs/cmdio/render.go index 8aff2b8d2..4ffd563fa 100644 --- a/libs/cmdio/render.go +++ b/libs/cmdio/render.go @@ -58,8 +58,7 @@ func renderTemplate(w io.Writer, tmpl string, v any) error { // we render colored output if stdout is TTY, otherwise we render text. // in the future we'll check if we can explicitly check for stderr being // a TTY - "black": color.BlackString, - "white": color.WhiteString, + "header": color.BlueString, "red": color.RedString, "green": color.GreenString, "blue": color.BlueString, @@ -107,8 +106,9 @@ func fancyJSON(v any) ([]byte, error) { f.FalseColor = color.New(color.FgRed) f.NumberColor = color.New(color.FgCyan) f.NullColor = color.New(color.FgMagenta) - f.FieldColor = color.New(color.FgWhite, color.Bold) - f.FieldQuoteColor = color.New(color.FgWhite) + f.ObjectColor = color.New(color.Reset) + f.CommaColor = color.New(color.Reset) + f.ColonColor = color.New(color.Reset) return jsoncolor.MarshalIndentWithFormatter(v, "", " ", f) } From 6ff00122ade09fbfddf2a5ad73ab71488b2c24a0 Mon Sep 17 00:00:00 2001 From: shreyas-goenka <88374338+shreyas-goenka@users.noreply.github.com> Date: Mon, 5 Jun 2023 17:41:30 +0200 Subject: [PATCH 8/9] Add fs ls command for dbfs (#429) ## Changes 1. Adds fs ls command 2. Adds ability to define multiple templates ## Tests Manually and integration tests --- cmd/fs/fs.go | 7 ++- cmd/fs/helpers.go | 14 ++++++ cmd/fs/helpers_test.go | 38 +++++++++++++++ cmd/fs/ls.go | 82 +++++++++++++++++++++++++++++--- internal/filer_test.go | 2 +- internal/fs_ls_test.go | 104 +++++++++++++++++++++++++++++++++++++++++ libs/cmdio/io.go | 17 +++---- libs/cmdio/render.go | 4 ++ 8 files changed, 249 insertions(+), 19 deletions(-) create mode 100644 cmd/fs/helpers.go create mode 100644 cmd/fs/helpers_test.go create mode 100644 internal/fs_ls_test.go diff --git a/cmd/fs/fs.go b/cmd/fs/fs.go index 74d725d4e..a69c4b62d 100644 --- a/cmd/fs/fs.go +++ b/cmd/fs/fs.go @@ -7,10 +7,9 @@ import ( // fsCmd represents the fs command var fsCmd = &cobra.Command{ - Use: "fs", - Short: "Filesystem related commands", - Long: `Commands to do DBFS operations.`, - Hidden: true, + Use: "fs", + Short: "Filesystem related commands", + Long: `Commands to do DBFS operations.`, } func init() { diff --git a/cmd/fs/helpers.go b/cmd/fs/helpers.go new file mode 100644 index 000000000..e456bff98 --- /dev/null +++ b/cmd/fs/helpers.go @@ -0,0 +1,14 @@ +package fs + +import ( + "fmt" + "strings" +) + +func resolveDbfsPath(path string) (string, error) { + if !strings.HasPrefix(path, "dbfs:/") { + return "", fmt.Errorf("expected dbfs path (with the dbfs:/ prefix): %s", path) + } + + return strings.TrimPrefix(path, "dbfs:"), nil +} diff --git a/cmd/fs/helpers_test.go b/cmd/fs/helpers_test.go new file mode 100644 index 000000000..1d174ef95 --- /dev/null +++ b/cmd/fs/helpers_test.go @@ -0,0 +1,38 @@ +package fs + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestResolveDbfsPath(t *testing.T) { + path, err := resolveDbfsPath("dbfs:/") + assert.NoError(t, err) + assert.Equal(t, "/", path) + + path, err = resolveDbfsPath("dbfs:/abc") + assert.NoError(t, err) + assert.Equal(t, "/abc", path) + + path, err = resolveDbfsPath("dbfs:/a/b/c") + assert.NoError(t, err) + assert.Equal(t, "/a/b/c", path) + + path, err = resolveDbfsPath("dbfs:/a/b/.") + assert.NoError(t, err) + assert.Equal(t, "/a/b/.", path) + + path, err = resolveDbfsPath("dbfs:/a/../c") + assert.NoError(t, err) + assert.Equal(t, "/a/../c", path) + + _, err = resolveDbfsPath("dbf:/a/b/c") + assert.ErrorContains(t, err, "expected dbfs path (with the dbfs:/ prefix): dbf:/a/b/c") + + _, err = resolveDbfsPath("/a/b/c") + assert.ErrorContains(t, err, "expected dbfs path (with the dbfs:/ prefix): /a/b/c") + + _, err = resolveDbfsPath("dbfs:a/b/c") + assert.ErrorContains(t, err, "expected dbfs path (with the dbfs:/ prefix): dbfs:a/b/c") +} diff --git a/cmd/fs/ls.go b/cmd/fs/ls.go index ac1923857..200cbed52 100644 --- a/cmd/fs/ls.go +++ b/cmd/fs/ls.go @@ -1,23 +1,93 @@ package fs import ( - "fmt" + "io/fs" + "sort" + "time" + "github.com/databricks/cli/cmd/root" + "github.com/databricks/cli/libs/cmdio" + "github.com/databricks/cli/libs/filer" "github.com/spf13/cobra" ) +type jsonDirEntry struct { + Name string `json:"name"` + IsDir bool `json:"is_directory"` + Size int64 `json:"size"` + ModTime time.Time `json:"last_modified"` +} + +func toJsonDirEntry(f fs.DirEntry) (*jsonDirEntry, error) { + info, err := f.Info() + if err != nil { + return nil, err + } + + return &jsonDirEntry{ + Name: f.Name(), + IsDir: f.IsDir(), + Size: info.Size(), + ModTime: info.ModTime(), + }, nil +} + // lsCmd represents the ls command var lsCmd = &cobra.Command{ - Use: "ls ", - Short: "Lists files", - Long: `Lists files`, - Hidden: true, + Use: "ls DIR_PATH", + Short: "Lists files", + Long: `Lists files`, + Args: cobra.ExactArgs(1), + PreRunE: root.MustWorkspaceClient, RunE: func(cmd *cobra.Command, args []string) error { - return fmt.Errorf("TODO") + ctx := cmd.Context() + w := root.WorkspaceClient(ctx) + + path, err := resolveDbfsPath(args[0]) + if err != nil { + return err + } + + f, err := filer.NewDbfsClient(w, "/") + if err != nil { + return err + } + + entries, err := f.ReadDir(ctx, path) + if err != nil { + return err + } + + jsonDirEntries := make([]jsonDirEntry, len(entries)) + for i, entry := range entries { + jsonDirEntry, err := toJsonDirEntry(entry) + if err != nil { + return err + } + jsonDirEntries[i] = *jsonDirEntry + } + sort.Slice(jsonDirEntries, func(i, j int) bool { + return jsonDirEntries[i].Name < jsonDirEntries[j].Name + }) + + // Use template for long mode if the flag is set + if longMode { + return cmdio.RenderWithTemplate(ctx, jsonDirEntries, cmdio.Heredoc(` + {{range .}}{{if .IsDir}}DIRECTORY {{else}}FILE {{end}}{{.Size}} {{.ModTime|pretty_date}} {{.Name}} + {{end}} + `)) + } + return cmdio.RenderWithTemplate(ctx, jsonDirEntries, cmdio.Heredoc(` + {{range .}}{{.Name}} + {{end}} + `)) }, } +var longMode bool + func init() { + lsCmd.Flags().BoolVarP(&longMode, "long", "l", false, "Displays full information including size, file type and modification time since Epoch in milliseconds.") fsCmd.AddCommand(lsCmd) } diff --git a/internal/filer_test.go b/internal/filer_test.go index 5037f7840..81c3e4aea 100644 --- a/internal/filer_test.go +++ b/internal/filer_test.go @@ -241,7 +241,7 @@ func TestAccFilerWorkspaceFilesReadDir(t *testing.T) { func temporaryDbfsDir(t *testing.T, w *databricks.WorkspaceClient) string { ctx := context.Background() - path := fmt.Sprintf("/tmp/%s", RandomName("integration-test-filer-dbfs-")) + path := fmt.Sprintf("/tmp/%s", RandomName("integration-test-dbfs-")) // This call fails if the path already exists. t.Logf("mkdir dbfs:%s", path) diff --git a/internal/fs_ls_test.go b/internal/fs_ls_test.go new file mode 100644 index 000000000..060c706df --- /dev/null +++ b/internal/fs_ls_test.go @@ -0,0 +1,104 @@ +package internal + +import ( + "context" + "encoding/json" + "io/fs" + "path" + "regexp" + "strings" + "testing" + + _ "github.com/databricks/cli/cmd/fs" + "github.com/databricks/cli/libs/filer" + "github.com/databricks/databricks-sdk-go" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestFsLsForDbfs(t *testing.T) { + t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV")) + + ctx := context.Background() + w, err := databricks.NewWorkspaceClient() + require.NoError(t, err) + + tmpDir := temporaryDbfsDir(t, w) + + f, err := filer.NewDbfsClient(w, tmpDir) + require.NoError(t, err) + + err = f.Mkdir(ctx, "a") + require.NoError(t, err) + err = f.Write(ctx, "a/hello.txt", strings.NewReader("abc"), filer.CreateParentDirectories) + require.NoError(t, err) + err = f.Write(ctx, "bye.txt", strings.NewReader("def")) + require.NoError(t, err) + + stdout, stderr := RequireSuccessfulRun(t, "fs", "ls", "dbfs:"+tmpDir, "--output=json") + assert.Equal(t, "", stderr.String()) + var parsedStdout []map[string]any + err = json.Unmarshal(stdout.Bytes(), &parsedStdout) + require.NoError(t, err) + + // assert on ls output + assert.Equal(t, "a", parsedStdout[0]["name"]) + assert.Equal(t, true, parsedStdout[0]["is_directory"]) + assert.Equal(t, float64(0), parsedStdout[0]["size"]) + assert.Equal(t, "bye.txt", parsedStdout[1]["name"]) + assert.Equal(t, false, parsedStdout[1]["is_directory"]) + assert.Equal(t, float64(3), parsedStdout[1]["size"]) +} + +func TestFsLsForDbfsOnFile(t *testing.T) { + t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV")) + + ctx := context.Background() + w, err := databricks.NewWorkspaceClient() + require.NoError(t, err) + + tmpDir := temporaryDbfsDir(t, w) + + f, err := filer.NewDbfsClient(w, tmpDir) + require.NoError(t, err) + + err = f.Mkdir(ctx, "a") + require.NoError(t, err) + err = f.Write(ctx, "a/hello.txt", strings.NewReader("abc"), filer.CreateParentDirectories) + require.NoError(t, err) + + _, _, err = RequireErrorRun(t, "fs", "ls", "dbfs:"+path.Join(tmpDir, "a", "hello.txt"), "--output=json") + assert.Regexp(t, regexp.MustCompile("not a directory: .*/a/hello.txt"), err.Error()) +} + +func TestFsLsForDbfsOnEmptyDir(t *testing.T) { + t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV")) + + w, err := databricks.NewWorkspaceClient() + require.NoError(t, err) + + tmpDir := temporaryDbfsDir(t, w) + + stdout, stderr := RequireSuccessfulRun(t, "fs", "ls", "dbfs:"+tmpDir, "--output=json") + assert.Equal(t, "", stderr.String()) + var parsedStdout []map[string]any + err = json.Unmarshal(stdout.Bytes(), &parsedStdout) + require.NoError(t, err) + + // assert on ls output + assert.Equal(t, 0, len(parsedStdout)) +} + +func TestFsLsForDbfsForNonexistingDir(t *testing.T) { + t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV")) + + _, _, err := RequireErrorRun(t, "fs", "ls", "dbfs:/john-cena", "--output=json") + assert.ErrorIs(t, err, fs.ErrNotExist) +} + +func TestFsLsWithoutScheme(t *testing.T) { + t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV")) + + _, _, err := RequireErrorRun(t, "fs", "ls", "/ray-mysterio", "--output=json") + assert.ErrorContains(t, err, "expected dbfs path (with the dbfs:/ prefix): /ray-mysterio") +} diff --git a/libs/cmdio/io.go b/libs/cmdio/io.go index beaa85717..1df6f5c18 100644 --- a/libs/cmdio/io.go +++ b/libs/cmdio/io.go @@ -66,14 +66,20 @@ func (c *cmdIO) IsTTY() bool { return isatty.IsTerminal(fd) || isatty.IsCygwinTerminal(fd) } -func (c *cmdIO) Render(v any) error { +func Render(ctx context.Context, v any) error { + c := fromContext(ctx) + return RenderWithTemplate(ctx, v, c.template) +} + +func RenderWithTemplate(ctx context.Context, v any, template string) error { // TODO: add terminal width & white/dark theme detection + c := fromContext(ctx) switch c.outputFormat { case flags.OutputJSON: return renderJson(c.out, v) case flags.OutputText: - if c.template != "" { - return renderTemplate(c.out, c.template, v) + if template != "" { + return renderTemplate(c.out, template, v) } return renderJson(c.out, v) default: @@ -81,11 +87,6 @@ func (c *cmdIO) Render(v any) error { } } -func Render(ctx context.Context, v any) error { - c := fromContext(ctx) - return c.Render(v) -} - type tuple struct{ Name, Id string } func (c *cmdIO) Select(names map[string]string, label string) (id string, err error) { diff --git a/libs/cmdio/render.go b/libs/cmdio/render.go index 4ffd563fa..c8f2b0dfc 100644 --- a/libs/cmdio/render.go +++ b/libs/cmdio/render.go @@ -6,6 +6,7 @@ import ( "strings" "text/tabwriter" "text/template" + "time" "github.com/fatih/color" "github.com/nwidger/jsoncolor" @@ -85,6 +86,9 @@ func renderTemplate(w io.Writer, tmpl string, v any) error { } return string(b), nil }, + "pretty_date": func(t time.Time) string { + return t.Format("2006-01-02T15:04:05Z") + }, }).Parse(tmpl) if err != nil { return err From df3f5863c7f5ca94d343da1f48ff8ebb7a782d32 Mon Sep 17 00:00:00 2001 From: Andrew Nester Date: Mon, 5 Jun 2023 19:38:45 +0200 Subject: [PATCH 9/9] Do not generate prompts for certain commands (#438) ## Changes Some of the commands do not support prompts, for example `workspace get-status` but we were wrongly suggesting customers some option. Quick fix for this is not to provide prompts for these known commands. Note: it uses a method from this PR in Go SDK https://github.com/databricks/databricks-sdk-go/pull/416 ## Tests Running `workspace get-status` Before ``` andrew.nester@HFW9Y94129 multiples-tasks % ../../cli/cli workspace get-status Error: Path () doesn't start with '/' ``` After ``` andrew.nester@HFW9Y94129 multiples-tasks % ../../cli/cli workspace get-status Error: accepts 1 arg(s), received 0 ``` --- .codegen/service.go.tmpl | 6 ++- cmd/account/networks/networks.go | 26 +++------- cmd/account/vpc-endpoints/vpc-endpoints.go | 26 +++------- cmd/account/workspaces/workspaces.go | 26 +++------- .../cluster-policies/cluster-policies.go | 26 +++------- cmd/workspace/clusters/clusters.go | 26 +++------- .../git-credentials/git-credentials.go | 26 +++------- cmd/workspace/workspace/workspace.go | 52 ++++++------------- internal/clusters_test.go | 5 ++ internal/workspace_test.go | 5 ++ 10 files changed, 79 insertions(+), 145 deletions(-) diff --git a/.codegen/service.go.tmpl b/.codegen/service.go.tmpl index 5bab09608..d098432b6 100644 --- a/.codegen/service.go.tmpl +++ b/.codegen/service.go.tmpl @@ -26,6 +26,7 @@ var Cmd = &cobra.Command{ {{- end}} } +{{- $serviceName := .KebabName -}} {{range .Methods}} {{- $excludes := list "put-secret" -}} @@ -62,11 +63,14 @@ func init() { {{- end}} {{end}} } +{{- $excludeFromPrompts := list "workspace get-status" -}} +{{- $fullCommandName := (print $serviceName " " .KebabName) -}} +{{- $noPrompt := or .IsCrudCreate (in $excludeFromPrompts $fullCommandName) }} {{ $hasPosArgs := and .Request (or .Request.IsAllRequiredFieldsPrimitive (eq .PascalName "RunNow")) -}} {{- $hasSinglePosArg := and $hasPosArgs (eq 1 (len .Request.RequiredFields)) -}} {{- $serviceHasNamedIdMap := and (and .Service.List .Service.List.NamedIdMap) (not (eq .PascalName "List")) -}} -{{- $hasIdPrompt := and $hasSinglePosArg $serviceHasNamedIdMap -}} +{{- $hasIdPrompt := and (not $noPrompt) (and $hasSinglePosArg $serviceHasNamedIdMap) -}} {{- $wait := and .Wait (and (not .IsCrudRead) (not (eq .SnakeName "get_run"))) -}} {{- $hasRequiredArgs := and (not $hasIdPrompt) $hasPosArgs -}} var {{.CamelName}}Cmd = &cobra.Command{ diff --git a/cmd/account/networks/networks.go b/cmd/account/networks/networks.go index e472f0ddb..4b0bf0637 100755 --- a/cmd/account/networks/networks.go +++ b/cmd/account/networks/networks.go @@ -47,7 +47,14 @@ var createCmd = &cobra.Command{ pre-existing VPC and subnets.`, Annotations: map[string]string{}, - PreRunE: root.MustAccountClient, + Args: func(cmd *cobra.Command, args []string) error { + check := cobra.ExactArgs(1) + if cmd.Flags().Changed("json") { + check = cobra.ExactArgs(0) + } + return check(cmd, args) + }, + PreRunE: root.MustAccountClient, RunE: func(cmd *cobra.Command, args []string) (err error) { ctx := cmd.Context() a := root.AccountClient(ctx) @@ -57,23 +64,6 @@ var createCmd = &cobra.Command{ return err } } else { - if len(args) == 0 { - promptSpinner := cmdio.Spinner(ctx) - promptSpinner <- "No NETWORK_NAME argument specified. Loading names for Networks drop-down." - names, err := a.Networks.NetworkNetworkNameToNetworkIdMap(ctx) - close(promptSpinner) - if err != nil { - return fmt.Errorf("failed to load names for Networks drop-down. Please manually specify required arguments. Original error: %w", err) - } - id, err := cmdio.Select(ctx, names, "The human-readable name of the network configuration") - if err != nil { - return err - } - args = append(args, id) - } - if len(args) != 1 { - return fmt.Errorf("expected to have the human-readable name of the network configuration") - } createReq.NetworkName = args[0] } diff --git a/cmd/account/vpc-endpoints/vpc-endpoints.go b/cmd/account/vpc-endpoints/vpc-endpoints.go index 778e88966..1cb72927b 100755 --- a/cmd/account/vpc-endpoints/vpc-endpoints.go +++ b/cmd/account/vpc-endpoints/vpc-endpoints.go @@ -54,7 +54,14 @@ var createCmd = &cobra.Command{ [endpoint service]: https://docs.aws.amazon.com/vpc/latest/privatelink/privatelink-share-your-services.html`, Annotations: map[string]string{}, - PreRunE: root.MustAccountClient, + Args: func(cmd *cobra.Command, args []string) error { + check := cobra.ExactArgs(1) + if cmd.Flags().Changed("json") { + check = cobra.ExactArgs(0) + } + return check(cmd, args) + }, + PreRunE: root.MustAccountClient, RunE: func(cmd *cobra.Command, args []string) (err error) { ctx := cmd.Context() a := root.AccountClient(ctx) @@ -64,23 +71,6 @@ var createCmd = &cobra.Command{ return err } } else { - if len(args) == 0 { - promptSpinner := cmdio.Spinner(ctx) - promptSpinner <- "No VPC_ENDPOINT_NAME argument specified. Loading names for Vpc Endpoints drop-down." - names, err := a.VpcEndpoints.VpcEndpointVpcEndpointNameToVpcEndpointIdMap(ctx) - close(promptSpinner) - if err != nil { - return fmt.Errorf("failed to load names for Vpc Endpoints drop-down. Please manually specify required arguments. Original error: %w", err) - } - id, err := cmdio.Select(ctx, names, "The human-readable name of the storage configuration") - if err != nil { - return err - } - args = append(args, id) - } - if len(args) != 1 { - return fmt.Errorf("expected to have the human-readable name of the storage configuration") - } createReq.VpcEndpointName = args[0] } diff --git a/cmd/account/workspaces/workspaces.go b/cmd/account/workspaces/workspaces.go index 2c7a996e6..ebe793cdd 100755 --- a/cmd/account/workspaces/workspaces.go +++ b/cmd/account/workspaces/workspaces.go @@ -73,7 +73,14 @@ var createCmd = &cobra.Command{ workspace becomes available when the status changes to RUNNING.`, Annotations: map[string]string{}, - PreRunE: root.MustAccountClient, + Args: func(cmd *cobra.Command, args []string) error { + check := cobra.ExactArgs(1) + if cmd.Flags().Changed("json") { + check = cobra.ExactArgs(0) + } + return check(cmd, args) + }, + PreRunE: root.MustAccountClient, RunE: func(cmd *cobra.Command, args []string) (err error) { ctx := cmd.Context() a := root.AccountClient(ctx) @@ -83,23 +90,6 @@ var createCmd = &cobra.Command{ return err } } else { - if len(args) == 0 { - promptSpinner := cmdio.Spinner(ctx) - promptSpinner <- "No WORKSPACE_NAME argument specified. Loading names for Workspaces drop-down." - names, err := a.Workspaces.WorkspaceWorkspaceNameToWorkspaceIdMap(ctx) - close(promptSpinner) - if err != nil { - return fmt.Errorf("failed to load names for Workspaces drop-down. Please manually specify required arguments. Original error: %w", err) - } - id, err := cmdio.Select(ctx, names, "The workspace's human-readable name") - if err != nil { - return err - } - args = append(args, id) - } - if len(args) != 1 { - return fmt.Errorf("expected to have the workspace's human-readable name") - } createReq.WorkspaceName = args[0] } diff --git a/cmd/workspace/cluster-policies/cluster-policies.go b/cmd/workspace/cluster-policies/cluster-policies.go index 66d3d8352..5de2067dc 100755 --- a/cmd/workspace/cluster-policies/cluster-policies.go +++ b/cmd/workspace/cluster-policies/cluster-policies.go @@ -67,7 +67,14 @@ var createCmd = &cobra.Command{ Creates a new policy with prescribed settings.`, Annotations: map[string]string{}, - PreRunE: root.MustWorkspaceClient, + Args: func(cmd *cobra.Command, args []string) error { + check := cobra.ExactArgs(1) + if cmd.Flags().Changed("json") { + check = cobra.ExactArgs(0) + } + return check(cmd, args) + }, + PreRunE: root.MustWorkspaceClient, RunE: func(cmd *cobra.Command, args []string) (err error) { ctx := cmd.Context() w := root.WorkspaceClient(ctx) @@ -77,23 +84,6 @@ var createCmd = &cobra.Command{ return err } } else { - if len(args) == 0 { - promptSpinner := cmdio.Spinner(ctx) - promptSpinner <- "No NAME argument specified. Loading names for Cluster Policies drop-down." - names, err := w.ClusterPolicies.PolicyNameToPolicyIdMap(ctx, compute.ListClusterPoliciesRequest{}) - close(promptSpinner) - if err != nil { - return fmt.Errorf("failed to load names for Cluster Policies drop-down. Please manually specify required arguments. Original error: %w", err) - } - id, err := cmdio.Select(ctx, names, "Cluster Policy name requested by the user") - if err != nil { - return err - } - args = append(args, id) - } - if len(args) != 1 { - return fmt.Errorf("expected to have cluster policy name requested by the user") - } createReq.Name = args[0] } diff --git a/cmd/workspace/clusters/clusters.go b/cmd/workspace/clusters/clusters.go index 3a40b2d47..3a1eb6429 100755 --- a/cmd/workspace/clusters/clusters.go +++ b/cmd/workspace/clusters/clusters.go @@ -158,7 +158,14 @@ var createCmd = &cobra.Command{ informative error message.`, Annotations: map[string]string{}, - PreRunE: root.MustWorkspaceClient, + Args: func(cmd *cobra.Command, args []string) error { + check := cobra.ExactArgs(1) + if cmd.Flags().Changed("json") { + check = cobra.ExactArgs(0) + } + return check(cmd, args) + }, + PreRunE: root.MustWorkspaceClient, RunE: func(cmd *cobra.Command, args []string) (err error) { ctx := cmd.Context() w := root.WorkspaceClient(ctx) @@ -168,23 +175,6 @@ var createCmd = &cobra.Command{ return err } } else { - if len(args) == 0 { - promptSpinner := cmdio.Spinner(ctx) - promptSpinner <- "No SPARK_VERSION argument specified. Loading names for Clusters drop-down." - names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{}) - close(promptSpinner) - if err != nil { - return fmt.Errorf("failed to load names for Clusters drop-down. Please manually specify required arguments. Original error: %w", err) - } - id, err := cmdio.Select(ctx, names, "The Spark version of the cluster, e.g") - if err != nil { - return err - } - args = append(args, id) - } - if len(args) != 1 { - return fmt.Errorf("expected to have the spark version of the cluster, e.g") - } createReq.SparkVersion = args[0] } diff --git a/cmd/workspace/git-credentials/git-credentials.go b/cmd/workspace/git-credentials/git-credentials.go index 161629888..7ac5b020c 100755 --- a/cmd/workspace/git-credentials/git-credentials.go +++ b/cmd/workspace/git-credentials/git-credentials.go @@ -49,7 +49,14 @@ var createCmd = &cobra.Command{ DELETE endpoint to delete existing credentials.`, Annotations: map[string]string{}, - PreRunE: root.MustWorkspaceClient, + Args: func(cmd *cobra.Command, args []string) error { + check := cobra.ExactArgs(1) + if cmd.Flags().Changed("json") { + check = cobra.ExactArgs(0) + } + return check(cmd, args) + }, + PreRunE: root.MustWorkspaceClient, RunE: func(cmd *cobra.Command, args []string) (err error) { ctx := cmd.Context() w := root.WorkspaceClient(ctx) @@ -59,23 +66,6 @@ var createCmd = &cobra.Command{ return err } } else { - if len(args) == 0 { - promptSpinner := cmdio.Spinner(ctx) - promptSpinner <- "No GIT_PROVIDER argument specified. Loading names for Git Credentials drop-down." - names, err := w.GitCredentials.CredentialInfoGitProviderToCredentialIdMap(ctx) - close(promptSpinner) - if err != nil { - return fmt.Errorf("failed to load names for Git Credentials drop-down. Please manually specify required arguments. Original error: %w", err) - } - id, err := cmdio.Select(ctx, names, "Git provider") - if err != nil { - return err - } - args = append(args, id) - } - if len(args) != 1 { - return fmt.Errorf("expected to have git provider") - } createReq.GitProvider = args[0] } diff --git a/cmd/workspace/workspace/workspace.go b/cmd/workspace/workspace/workspace.go index c942d7aa5..14ce4303b 100755 --- a/cmd/workspace/workspace/workspace.go +++ b/cmd/workspace/workspace/workspace.go @@ -178,7 +178,14 @@ var getStatusCmd = &cobra.Command{ call returns an error RESOURCE_DOES_NOT_EXIST.`, Annotations: map[string]string{}, - PreRunE: root.MustWorkspaceClient, + Args: func(cmd *cobra.Command, args []string) error { + check := cobra.ExactArgs(1) + if cmd.Flags().Changed("json") { + check = cobra.ExactArgs(0) + } + return check(cmd, args) + }, + PreRunE: root.MustWorkspaceClient, RunE: func(cmd *cobra.Command, args []string) (err error) { ctx := cmd.Context() w := root.WorkspaceClient(ctx) @@ -188,23 +195,6 @@ var getStatusCmd = &cobra.Command{ return err } } else { - if len(args) == 0 { - promptSpinner := cmdio.Spinner(ctx) - promptSpinner <- "No PATH argument specified. Loading names for Workspace drop-down." - names, err := w.Workspace.ObjectInfoPathToObjectIdMap(ctx, workspace.ListWorkspaceRequest{}) - close(promptSpinner) - if err != nil { - return fmt.Errorf("failed to load names for Workspace drop-down. Please manually specify required arguments. Original error: %w", err) - } - id, err := cmdio.Select(ctx, names, "The absolute path of the notebook or directory") - if err != nil { - return err - } - args = append(args, id) - } - if len(args) != 1 { - return fmt.Errorf("expected to have the absolute path of the notebook or directory") - } getStatusReq.Path = args[0] } @@ -244,7 +234,14 @@ var importCmd = &cobra.Command{ use DBC format to import a directory.`, Annotations: map[string]string{}, - PreRunE: root.MustWorkspaceClient, + Args: func(cmd *cobra.Command, args []string) error { + check := cobra.ExactArgs(1) + if cmd.Flags().Changed("json") { + check = cobra.ExactArgs(0) + } + return check(cmd, args) + }, + PreRunE: root.MustWorkspaceClient, RunE: func(cmd *cobra.Command, args []string) (err error) { ctx := cmd.Context() w := root.WorkspaceClient(ctx) @@ -254,23 +251,6 @@ var importCmd = &cobra.Command{ return err } } else { - if len(args) == 0 { - promptSpinner := cmdio.Spinner(ctx) - promptSpinner <- "No PATH argument specified. Loading names for Workspace drop-down." - names, err := w.Workspace.ObjectInfoPathToObjectIdMap(ctx, workspace.ListWorkspaceRequest{}) - close(promptSpinner) - if err != nil { - return fmt.Errorf("failed to load names for Workspace drop-down. Please manually specify required arguments. Original error: %w", err) - } - id, err := cmdio.Select(ctx, names, "The absolute path of the object or directory") - if err != nil { - return err - } - args = append(args, id) - } - if len(args) != 1 { - return fmt.Errorf("expected to have the absolute path of the object or directory") - } importReq.Path = args[0] } diff --git a/internal/clusters_test.go b/internal/clusters_test.go index 742509724..e8208d047 100644 --- a/internal/clusters_test.go +++ b/internal/clusters_test.go @@ -33,3 +33,8 @@ func TestAccClustersGet(t *testing.T) { assert.Contains(t, outStr, fmt.Sprintf(`"cluster_id":"%s"`, clusterId)) assert.Equal(t, "", stderr.String()) } + +func TestClusterCreateErrorWhenNoArguments(t *testing.T) { + _, _, err := RequireErrorRun(t, "clusters", "create") + assert.Equal(t, "accepts 1 arg(s), received 0", err.Error()) +} diff --git a/internal/workspace_test.go b/internal/workspace_test.go index 83d7be22f..f8830990d 100644 --- a/internal/workspace_test.go +++ b/internal/workspace_test.go @@ -22,3 +22,8 @@ func TestWorkpaceListErrorWhenNoArguments(t *testing.T) { _, _, err := RequireErrorRun(t, "workspace", "list") assert.Equal(t, "accepts 1 arg(s), received 0", err.Error()) } + +func TestWorkpaceGetStatusErrorWhenNoArguments(t *testing.T) { + _, _, err := RequireErrorRun(t, "workspace", "get-status") + assert.Equal(t, "accepts 1 arg(s), received 0", err.Error()) +}