Merge remote-tracking branch 'origin' into import_dir

This commit is contained in:
Shreyas Goenka 2023-06-06 00:36:12 +02:00
commit 59081f7017
No known key found for this signature in database
GPG Key ID: 92A07DF49CCB0622
77 changed files with 1824 additions and 497 deletions

View File

@ -26,6 +26,7 @@ var Cmd = &cobra.Command{
{{- end}} {{- end}}
} }
{{- $serviceName := .KebabName -}}
{{range .Methods}} {{range .Methods}}
{{- $excludes := list "put-secret" -}} {{- $excludes := list "put-secret" -}}
@ -62,11 +63,14 @@ func init() {
{{- end}} {{- end}}
{{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")) -}} {{ $hasPosArgs := and .Request (or .Request.IsAllRequiredFieldsPrimitive (eq .PascalName "RunNow")) -}}
{{- $hasSinglePosArg := and $hasPosArgs (eq 1 (len .Request.RequiredFields)) -}} {{- $hasSinglePosArg := and $hasPosArgs (eq 1 (len .Request.RequiredFields)) -}}
{{- $serviceHasNamedIdMap := and (and .Service.List .Service.List.NamedIdMap) (not (eq .PascalName "List")) -}} {{- $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"))) -}} {{- $wait := and .Wait (and (not .IsCrudRead) (not (eq .SnakeName "get_run"))) -}}
{{- $hasRequiredArgs := and (not $hasIdPrompt) $hasPosArgs -}} {{- $hasRequiredArgs := and (not $hasIdPrompt) $hasPosArgs -}}
var {{.CamelName}}Cmd = &cobra.Command{ var {{.CamelName}}Cmd = &cobra.Command{
@ -96,9 +100,12 @@ var {{.CamelName}}Cmd = &cobra.Command{
} else { } else {
{{- if $hasIdPrompt}} {{- if $hasIdPrompt}}
if len(args) == 0 { 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}}) 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 { 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}}") id, err := cmdio.Select(ctx, names, "{{range .Request.RequiredFields}}{{.Summary | trimSuffix "."}}{{end}}")
if err != nil { if err != nil {

View File

@ -94,9 +94,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := a.Budgets.BudgetWithStatusNameToBudgetIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Budget ID")
if err != nil { if err != nil {
@ -150,9 +153,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := a.Budgets.BudgetWithStatusNameToBudgetIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Budget ID")
if err != nil { if err != nil {

View File

@ -113,9 +113,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := a.Credentials.CredentialCredentialsNameToCredentialsIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Databricks Account API credential configuration ID")
if err != nil { if err != nil {
@ -169,9 +172,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := a.Credentials.CredentialCredentialsNameToCredentialsIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Databricks Account API credential configuration ID")
if err != nil { if err != nil {

View File

@ -111,9 +111,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := a.Groups.GroupDisplayNameToIdMap(ctx, iam.ListAccountGroupsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Unique ID for a group in the Databricks account")
if err != nil { if err != nil {
@ -166,9 +169,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := a.Groups.GroupDisplayNameToIdMap(ctx, iam.ListAccountGroupsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Unique ID for a group in the Databricks account")
if err != nil { if err != nil {
@ -278,9 +284,12 @@ var patchCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := a.Groups.GroupDisplayNameToIdMap(ctx, iam.ListAccountGroupsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Unique ID for a group in the Databricks account")
if err != nil { if err != nil {
@ -341,9 +350,12 @@ var updateCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := a.Groups.GroupDisplayNameToIdMap(ctx, iam.ListAccountGroupsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Databricks group ID")
if err != nil { if err != nil {

View File

@ -132,9 +132,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := a.IpAccessLists.IpAccessListInfoLabelToListIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The ID for the corresponding IP access list")
if err != nil { if err != nil {
@ -187,9 +190,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := a.IpAccessLists.IpAccessListInfoLabelToListIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The ID for the corresponding IP access list")
if err != nil { if err != nil {

View File

@ -183,9 +183,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := a.LogDelivery.LogDeliveryConfigurationConfigNameToConfigIdMap(ctx, billing.ListLogDeliveryRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Databricks log delivery configuration ID")
if err != nil { if err != nil {

View File

@ -47,7 +47,14 @@ var createCmd = &cobra.Command{
pre-existing VPC and subnets.`, pre-existing VPC and subnets.`,
Annotations: map[string]string{}, 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) { RunE: func(cmd *cobra.Command, args []string) (err error) {
ctx := cmd.Context() ctx := cmd.Context()
a := root.AccountClient(ctx) a := root.AccountClient(ctx)
@ -57,20 +64,6 @@ var createCmd = &cobra.Command{
return err return err
} }
} else { } else {
if len(args) == 0 {
names, err := a.Networks.NetworkNetworkNameToNetworkIdMap(ctx)
if err != nil {
return 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] createReq.NetworkName = args[0]
} }
@ -118,9 +111,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := a.Networks.NetworkNetworkNameToNetworkIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Databricks Account API network configuration ID")
if err != nil { if err != nil {
@ -174,9 +170,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := a.Networks.NetworkNetworkNameToNetworkIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Databricks Account API network configuration ID")
if err != nil { if err != nil {

View File

@ -123,9 +123,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := a.PrivateAccess.PrivateAccessSettingsPrivateAccessSettingsNameToPrivateAccessSettingsIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Databricks Account API private access settings ID")
if err != nil { if err != nil {
@ -185,9 +188,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := a.PrivateAccess.PrivateAccessSettingsPrivateAccessSettingsNameToPrivateAccessSettingsIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Databricks Account API private access settings ID")
if err != nil { if err != nil {

View File

@ -110,9 +110,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := a.ServicePrincipals.ServicePrincipalDisplayNameToIdMap(ctx, iam.ListAccountServicePrincipalsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Unique ID for a service principal in the Databricks account")
if err != nil { if err != nil {
@ -166,9 +169,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := a.ServicePrincipals.ServicePrincipalDisplayNameToIdMap(ctx, iam.ListAccountServicePrincipalsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Unique ID for a service principal in the Databricks account")
if err != nil { if err != nil {
@ -279,9 +285,12 @@ var patchCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := a.ServicePrincipals.ServicePrincipalDisplayNameToIdMap(ctx, iam.ListAccountServicePrincipalsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Unique ID for a service principal in the Databricks account")
if err != nil { if err != nil {
@ -345,9 +354,12 @@ var updateCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := a.ServicePrincipals.ServicePrincipalDisplayNameToIdMap(ctx, iam.ListAccountServicePrincipalsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Databricks service principal ID")
if err != nil { if err != nil {

View File

@ -109,9 +109,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := a.Storage.StorageConfigurationStorageConfigurationNameToStorageConfigurationIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Databricks Account API storage configuration ID")
if err != nil { if err != nil {
@ -164,9 +167,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := a.Storage.StorageConfigurationStorageConfigurationNameToStorageConfigurationIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Databricks Account API storage configuration ID")
if err != nil { if err != nil {

View File

@ -119,9 +119,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := a.Users.UserUserNameToIdMap(ctx, iam.ListAccountUsersRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Unique ID for a user in the Databricks account")
if err != nil { if err != nil {
@ -174,9 +177,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := a.Users.UserUserNameToIdMap(ctx, iam.ListAccountUsersRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Unique ID for a user in the Databricks account")
if err != nil { if err != nil {
@ -287,9 +293,12 @@ var patchCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := a.Users.UserUserNameToIdMap(ctx, iam.ListAccountUsersRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Unique ID for a user in the Databricks account")
if err != nil { if err != nil {
@ -353,9 +362,12 @@ var updateCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := a.Users.UserUserNameToIdMap(ctx, iam.ListAccountUsersRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Databricks user ID")
if err != nil { if err != nil {

View File

@ -54,7 +54,14 @@ var createCmd = &cobra.Command{
[endpoint service]: https://docs.aws.amazon.com/vpc/latest/privatelink/privatelink-share-your-services.html`, [endpoint service]: https://docs.aws.amazon.com/vpc/latest/privatelink/privatelink-share-your-services.html`,
Annotations: map[string]string{}, 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) { RunE: func(cmd *cobra.Command, args []string) (err error) {
ctx := cmd.Context() ctx := cmd.Context()
a := root.AccountClient(ctx) a := root.AccountClient(ctx)
@ -64,20 +71,6 @@ var createCmd = &cobra.Command{
return err return err
} }
} else { } else {
if len(args) == 0 {
names, err := a.VpcEndpoints.VpcEndpointVpcEndpointNameToVpcEndpointIdMap(ctx)
if err != nil {
return 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] createReq.VpcEndpointName = args[0]
} }
@ -128,9 +121,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := a.VpcEndpoints.VpcEndpointVpcEndpointNameToVpcEndpointIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Databricks VPC endpoint ID")
if err != nil { if err != nil {
@ -187,9 +183,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := a.VpcEndpoints.VpcEndpointVpcEndpointNameToVpcEndpointIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Databricks VPC endpoint ID")
if err != nil { if err != nil {

View File

@ -73,7 +73,14 @@ var createCmd = &cobra.Command{
workspace becomes available when the status changes to RUNNING.`, workspace becomes available when the status changes to RUNNING.`,
Annotations: map[string]string{}, 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) { RunE: func(cmd *cobra.Command, args []string) (err error) {
ctx := cmd.Context() ctx := cmd.Context()
a := root.AccountClient(ctx) a := root.AccountClient(ctx)
@ -83,20 +90,6 @@ var createCmd = &cobra.Command{
return err return err
} }
} else { } else {
if len(args) == 0 {
names, err := a.Workspaces.WorkspaceWorkspaceNameToWorkspaceIdMap(ctx)
if err != nil {
return 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] createReq.WorkspaceName = args[0]
} }
@ -163,9 +156,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := a.Workspaces.WorkspaceWorkspaceNameToWorkspaceIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Workspace ID")
if err != nil { if err != nil {
@ -234,9 +230,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := a.Workspaces.WorkspaceWorkspaceNameToWorkspaceIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Workspace ID")
if err != nil { if err != nil {
@ -445,9 +444,12 @@ var updateCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := a.Workspaces.WorkspaceWorkspaceNameToWorkspaceIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Workspace ID")
if err != nil { if err != nil {

View File

@ -99,8 +99,8 @@ var profilesCmd = &cobra.Command{
Short: "Lists profiles from ~/.databrickscfg", Short: "Lists profiles from ~/.databrickscfg",
Annotations: map[string]string{ Annotations: map[string]string{
"template": cmdio.Heredoc(` "template": cmdio.Heredoc(`
{{white "Name"}} {{white "Host"}} {{white "Valid"}} {{header "Name"}} {{header "Host"}} {{header "Valid"}}
{{range .Profiles}}{{.Name | green}} {{.Host|white}} {{bool .Valid}} {{range .Profiles}}{{.Name | green}} {{.Host|cyan}} {{bool .Valid}}
{{end}}`), {{end}}`),
}, },
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {

View File

@ -7,10 +7,9 @@ import (
// fsCmd represents the fs command // fsCmd represents the fs command
var fsCmd = &cobra.Command{ var fsCmd = &cobra.Command{
Use: "fs", Use: "fs",
Short: "Filesystem related commands", Short: "Filesystem related commands",
Long: `Commands to do DBFS operations.`, Long: `Commands to do DBFS operations.`,
Hidden: true,
} }
func init() { func init() {

14
cmd/fs/helpers.go Normal file
View File

@ -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
}

38
cmd/fs/helpers_test.go Normal file
View File

@ -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")
}

View File

@ -1,23 +1,93 @@
package fs package fs
import ( 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" "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 // lsCmd represents the ls command
var lsCmd = &cobra.Command{ var lsCmd = &cobra.Command{
Use: "ls <dir-name>", Use: "ls DIR_PATH",
Short: "Lists files", Short: "Lists files",
Long: `Lists files`, Long: `Lists files`,
Hidden: true, Args: cobra.ExactArgs(1),
PreRunE: root.MustWorkspaceClient,
RunE: func(cmd *cobra.Command, args []string) error { 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() { 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) fsCmd.AddCommand(lsCmd)
} }

View File

@ -106,9 +106,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := w.Alerts.AlertNameToIdMap(ctx)
close(promptSpinner)
if err != nil { 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, "") id, err := cmdio.Select(ctx, names, "")
if err != nil { if err != nil {
@ -161,9 +164,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := w.Alerts.AlertNameToIdMap(ctx)
close(promptSpinner)
if err != nil { 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, "") id, err := cmdio.Select(ctx, names, "")
if err != nil { if err != nil {

View File

@ -4,7 +4,7 @@ import "github.com/databricks/cli/libs/cmdio"
func init() { func init() {
listCmd.Annotations["template"] = cmdio.Heredoc(` listCmd.Annotations["template"] = cmdio.Heredoc(`
{{white "Name"}} {{white "Type"}} {{white "Comment"}} {{header "Name"}} {{header "Type"}} {{header "Comment"}}
{{range .}}{{.Name|green}} {{blue "%s" .CatalogType}} {{.Comment}} {{range .}}{{.Name|green}} {{blue "%s" .CatalogType}} {{.Comment}}
{{end}}`) {{end}}`)
} }

View File

@ -67,7 +67,14 @@ var createCmd = &cobra.Command{
Creates a new policy with prescribed settings.`, Creates a new policy with prescribed settings.`,
Annotations: map[string]string{}, 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) { RunE: func(cmd *cobra.Command, args []string) (err error) {
ctx := cmd.Context() ctx := cmd.Context()
w := root.WorkspaceClient(ctx) w := root.WorkspaceClient(ctx)
@ -77,20 +84,6 @@ var createCmd = &cobra.Command{
return err return err
} }
} else { } else {
if len(args) == 0 {
names, err := w.ClusterPolicies.PolicyNameToPolicyIdMap(ctx, compute.ListClusterPoliciesRequest{})
if err != nil {
return 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] createReq.Name = args[0]
} }
@ -134,9 +127,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.ClusterPolicies.PolicyNameToPolicyIdMap(ctx, compute.ListClusterPoliciesRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The ID of the policy to delete")
if err != nil { if err != nil {
@ -245,9 +241,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.ClusterPolicies.PolicyNameToPolicyIdMap(ctx, compute.ListClusterPoliciesRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Canonical unique identifier for the cluster policy")
if err != nil { if err != nil {

View File

@ -158,7 +158,14 @@ var createCmd = &cobra.Command{
informative error message.`, informative error message.`,
Annotations: map[string]string{}, 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) { RunE: func(cmd *cobra.Command, args []string) (err error) {
ctx := cmd.Context() ctx := cmd.Context()
w := root.WorkspaceClient(ctx) w := root.WorkspaceClient(ctx)
@ -168,20 +175,6 @@ var createCmd = &cobra.Command{
return err return err
} }
} else { } else {
if len(args) == 0 {
names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{})
if err != nil {
return 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] createReq.SparkVersion = args[0]
} }
@ -249,9 +242,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The cluster to be terminated")
if err != nil { if err != nil {
@ -437,9 +433,12 @@ var eventsCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The ID of the cluster to retrieve events about")
if err != nil { if err != nil {
@ -498,9 +497,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The cluster about which to retrieve information")
if err != nil { if err != nil {
@ -671,9 +673,12 @@ var permanentDeleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The cluster to be deleted")
if err != nil { if err != nil {
@ -728,9 +733,12 @@ var pinCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{})
close(promptSpinner)
if err != nil { 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, "<needs content added>") id, err := cmdio.Select(ctx, names, "<needs content added>")
if err != nil { if err != nil {
@ -792,9 +800,12 @@ var resizeCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The cluster to be resized")
if err != nil { if err != nil {
@ -872,9 +883,12 @@ var restartCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The cluster to be started")
if err != nil { if err != nil {
@ -984,9 +998,12 @@ var startCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The cluster to be started")
if err != nil { if err != nil {
@ -1058,9 +1075,12 @@ var unpinCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Clusters.ClusterInfoClusterNameToClusterIdMap(ctx, compute.ListClustersRequest{})
close(promptSpinner)
if err != nil { 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, "<needs content added>") id, err := cmdio.Select(ctx, names, "<needs content added>")
if err != nil { if err != nil {

View File

@ -4,8 +4,8 @@ import "github.com/databricks/cli/libs/cmdio"
func init() { func init() {
listCmd.Annotations["template"] = cmdio.Heredoc(` listCmd.Annotations["template"] = cmdio.Heredoc(`
{{white "ID"}} {{white "Name"}} {{white "State"}} {{header "ID"}} {{header "Name"}} {{header "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}} {{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}}`) {{end}}`)
listNodeTypesCmd.Annotations["template"] = cmdio.Heredoc(` listNodeTypesCmd.Annotations["template"] = cmdio.Heredoc(`

View File

@ -105,9 +105,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Dashboards.DashboardNameToIdMap(ctx, sql.ListDashboardsRequest{})
close(promptSpinner)
if err != nil { 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, "") id, err := cmdio.Select(ctx, names, "")
if err != nil { if err != nil {
@ -161,9 +164,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Dashboards.DashboardNameToIdMap(ctx, sql.ListDashboardsRequest{})
close(promptSpinner)
if err != nil { 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, "") id, err := cmdio.Select(ctx, names, "")
if err != nil { if err != nil {
@ -268,9 +274,12 @@ var restoreCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Dashboards.DashboardNameToIdMap(ctx, sql.ListDashboardsRequest{})
close(promptSpinner)
if err != nil { 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, "") id, err := cmdio.Select(ctx, names, "")
if err != nil { if err != nil {

View File

@ -4,7 +4,7 @@ import "github.com/databricks/cli/libs/cmdio"
func init() { func init() {
listCmd.Annotations["template"] = cmdio.Heredoc(` listCmd.Annotations["template"] = cmdio.Heredoc(`
{{white "ID"}} {{white "Name"}} {{header "ID"}} {{header "Name"}}
{{range .}}{{.Id|green}} {{.Name}} {{range .}}{{.Id|green}} {{.Name}}
{{end}}`) {{end}}`)
} }

View File

@ -4,7 +4,7 @@ import "github.com/databricks/cli/libs/cmdio"
func init() { func init() {
listCmd.Annotations["template"] = cmdio.Heredoc(` listCmd.Annotations["template"] = cmdio.Heredoc(`
{{white "Name"}} {{white "Credential"}} {{white "URL"}} {{header "Name"}} {{header "Credential"}} {{header "URL"}}
{{range .}}{{.Name|green}} {{.CredentialName|blue}} {{.Url}} {{range .}}{{.Name|green}} {{.CredentialName|cyan}} {{.Url}}
{{end}}`) {{end}}`)
} }

View File

@ -49,7 +49,14 @@ var createCmd = &cobra.Command{
DELETE endpoint to delete existing credentials.`, DELETE endpoint to delete existing credentials.`,
Annotations: map[string]string{}, 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) { RunE: func(cmd *cobra.Command, args []string) (err error) {
ctx := cmd.Context() ctx := cmd.Context()
w := root.WorkspaceClient(ctx) w := root.WorkspaceClient(ctx)
@ -59,20 +66,6 @@ var createCmd = &cobra.Command{
return err return err
} }
} else { } else {
if len(args) == 0 {
names, err := w.GitCredentials.CredentialInfoGitProviderToCredentialIdMap(ctx)
if err != nil {
return 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] createReq.GitProvider = args[0]
} }
@ -115,9 +108,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := w.GitCredentials.CredentialInfoGitProviderToCredentialIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The ID for the corresponding credential to access")
if err != nil { if err != nil {
@ -173,9 +169,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := w.GitCredentials.CredentialInfoGitProviderToCredentialIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The ID for the corresponding credential to access")
if err != nil { if err != nil {
@ -263,9 +262,12 @@ var updateCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := w.GitCredentials.CredentialInfoGitProviderToCredentialIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The ID for the corresponding credential to access")
if err != nil { if err != nil {

View File

@ -109,9 +109,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := w.GlobalInitScripts.GlobalInitScriptDetailsNameToScriptIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The ID of the global init script")
if err != nil { if err != nil {
@ -164,9 +167,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := w.GlobalInitScripts.GlobalInitScriptDetailsNameToScriptIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The ID of the global init script")
if err != nil { if err != nil {

View File

@ -111,9 +111,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Groups.GroupDisplayNameToIdMap(ctx, iam.ListGroupsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Unique ID for a group in the Databricks workspace")
if err != nil { if err != nil {
@ -166,9 +169,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Groups.GroupDisplayNameToIdMap(ctx, iam.ListGroupsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Unique ID for a group in the Databricks workspace")
if err != nil { if err != nil {
@ -278,9 +284,12 @@ var patchCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Groups.GroupDisplayNameToIdMap(ctx, iam.ListGroupsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Unique ID for a group in the Databricks workspace")
if err != nil { if err != nil {
@ -341,9 +350,12 @@ var updateCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Groups.GroupDisplayNameToIdMap(ctx, iam.ListGroupsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Databricks group ID")
if err != nil { if err != nil {

View File

@ -128,9 +128,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := w.InstancePools.InstancePoolAndStatsInstancePoolNameToInstancePoolIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The instance pool to be terminated")
if err != nil { if err != nil {
@ -245,9 +248,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := w.InstancePools.InstancePoolAndStatsInstancePoolNameToInstancePoolIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The canonical unique identifier for the instance pool")
if err != nil { if err != nil {

View File

@ -133,9 +133,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := w.IpAccessLists.IpAccessListInfoLabelToListIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The ID for the corresponding IP access list to modify")
if err != nil { if err != nil {
@ -188,9 +191,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := w.IpAccessLists.IpAccessListInfoLabelToListIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The ID for the corresponding IP access list to modify")
if err != nil { if err != nil {

View File

@ -69,9 +69,12 @@ var cancelAllRunsCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The canonical identifier of the job to cancel all runs of")
if err != nil { if err != nil {
@ -133,9 +136,12 @@ var cancelRunCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "This field is required")
if err != nil { if err != nil {
@ -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().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.`) createCmd.Flags().StringVar(&createReq.Name, "name", createReq.Name, `An optional name for the job.`)
// TODO: complex arg: notification_settings // TODO: complex arg: notification_settings
// TODO: complex arg: run_as
// TODO: complex arg: schedule // TODO: complex arg: schedule
// TODO: map via StringToStringVar: tags // TODO: map via StringToStringVar: tags
// TODO: array: tasks // TODO: array: tasks
@ -278,9 +285,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The canonical identifier of the job to delete")
if err != nil { if err != nil {
@ -336,9 +346,12 @@ var deleteRunCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The canonical identifier of the run for which to retrieve the metadata")
if err != nil { if err != nil {
@ -396,9 +409,12 @@ var exportRunCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The canonical identifier for the run")
if err != nil { if err != nil {
@ -454,9 +470,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The canonical identifier of the job to retrieve information about")
if err != nil { if err != nil {
@ -519,9 +538,12 @@ var getRunCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The canonical identifier of the run for which to retrieve the metadata")
if err != nil { if err != nil {
@ -586,9 +608,12 @@ var getRunOutputCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The canonical identifier for the run")
if err != nil { if err != nil {
@ -772,9 +797,12 @@ var repairRunCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The job run ID of the run to repair")
if err != nil { if err != nil {
@ -918,9 +946,12 @@ var runNowCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The ID of the job to be executed")
if err != nil { if err != nil {
@ -1092,9 +1123,12 @@ var updateCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Jobs.BaseJobSettingsNameToJobIdMap(ctx, jobs.ListJobsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The canonical identifier of the job to update")
if err != nil { if err != nil {

View File

@ -8,7 +8,7 @@ func init() {
{{end}}`) {{end}}`)
listRunsCmd.Annotations["template"] = cmdio.Heredoc(` listRunsCmd.Annotations["template"] = cmdio.Heredoc(`
{{"Job ID"|white}} {{"Run ID"|white}} {{"Result State"|white}} URL {{header "Job ID"}} {{header "Run ID"}} {{header "Result State"}} URL
{{range .}}{{green "%d" .JobId}} {{blue "%d" .RunId}} {{if eq .State.ResultState "SUCCESS"}}{{"SUCCESS"|green}}{{else}}{{red "%s" .State.ResultState}}{{end}} {{.RunPageUrl}} {{range .}}{{green "%d" .JobId}} {{cyan "%d" .RunId}} {{if eq .State.ResultState "SUCCESS"}}{{"SUCCESS"|green}}{{else}}{{red "%s" .State.ResultState}}{{end}} {{.RunPageUrl}}
{{end}}`) {{end}}`)
} }

View File

@ -196,9 +196,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := w.Metastores.MetastoreInfoNameToMetastoreIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Unique ID of the metastore")
if err != nil { if err != nil {
@ -252,9 +255,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := w.Metastores.MetastoreInfoNameToMetastoreIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Unique ID of the metastore")
if err != nil { if err != nil {
@ -477,9 +483,12 @@ var updateCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := w.Metastores.MetastoreInfoNameToMetastoreIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Unique ID of the metastore")
if err != nil { if err != nil {
@ -538,9 +547,12 @@ var updateAssignmentCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := w.Metastores.MetastoreInfoNameToMetastoreIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "A workspace ID")
if err != nil { if err != nil {

View File

@ -4,7 +4,7 @@ import "github.com/databricks/cli/libs/cmdio"
func init() { func init() {
listCmd.Annotations["template"] = cmdio.Heredoc(` listCmd.Annotations["template"] = cmdio.Heredoc(`
{{white "ID"}} {{white "Name"}} {{white "Region"}} {{header "ID"}} {{header "Name"}} {{"Region"}}
{{range .}}{{.MetastoreId|green}} {{.Name|white}} {{.Region}} {{range .}}{{.MetastoreId|green}} {{.Name|cyan}} {{.Region}}
{{end}}`) {{end}}`)
} }

View File

@ -605,8 +605,8 @@ func init() {
var deleteTransitionRequestCmd = &cobra.Command{ var deleteTransitionRequestCmd = &cobra.Command{
Use: "delete-transition-request NAME VERSION STAGE CREATOR", Use: "delete-transition-request NAME VERSION STAGE CREATOR",
Short: `Delete a ransition request.`, Short: `Delete a transition request.`,
Long: `Delete a ransition request. Long: `Delete a transition request.
Cancels a model version stage transition request.`, Cancels a model version stage transition request.`,

View File

@ -131,9 +131,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Pipelines.PipelineStateInfoNameToPipelineIdMap(ctx, pipelines.ListPipelinesRequest{})
close(promptSpinner)
if err != nil { 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, "") id, err := cmdio.Select(ctx, names, "")
if err != nil { if err != nil {
@ -189,9 +192,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Pipelines.PipelineStateInfoNameToPipelineIdMap(ctx, pipelines.ListPipelinesRequest{})
close(promptSpinner)
if err != nil { 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, "") id, err := cmdio.Select(ctx, names, "")
if err != nil { if err != nil {
@ -298,9 +304,12 @@ var listPipelineEventsCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Pipelines.PipelineStateInfoNameToPipelineIdMap(ctx, pipelines.ListPipelinesRequest{})
close(promptSpinner)
if err != nil { 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, "") id, err := cmdio.Select(ctx, names, "")
if err != nil { if err != nil {
@ -409,9 +418,12 @@ var listUpdatesCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Pipelines.PipelineStateInfoNameToPipelineIdMap(ctx, pipelines.ListPipelinesRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The pipeline to return updates for")
if err != nil { if err != nil {
@ -469,9 +481,12 @@ var resetCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Pipelines.PipelineStateInfoNameToPipelineIdMap(ctx, pipelines.ListPipelinesRequest{})
close(promptSpinner)
if err != nil { 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, "") id, err := cmdio.Select(ctx, names, "")
if err != nil { if err != nil {
@ -546,9 +561,12 @@ var startUpdateCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Pipelines.PipelineStateInfoNameToPipelineIdMap(ctx, pipelines.ListPipelinesRequest{})
close(promptSpinner)
if err != nil { 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, "") id, err := cmdio.Select(ctx, names, "")
if err != nil { if err != nil {
@ -606,9 +624,12 @@ var stopCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Pipelines.PipelineStateInfoNameToPipelineIdMap(ctx, pipelines.ListPipelinesRequest{})
close(promptSpinner)
if err != nil { 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, "") id, err := cmdio.Select(ctx, names, "")
if err != nil { if err != nil {
@ -698,9 +719,12 @@ var updateCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Pipelines.PipelineStateInfoNameToPipelineIdMap(ctx, pipelines.ListPipelinesRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Unique identifier for this pipeline")
if err != nil { if err != nil {

View File

@ -106,9 +106,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Providers.ProviderInfoNameToMetastoreIdMap(ctx, sharing.ListProvidersRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Name of the provider")
if err != nil { if err != nil {
@ -163,9 +166,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Providers.ProviderInfoNameToMetastoreIdMap(ctx, sharing.ListProvidersRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Name of the provider")
if err != nil { if err != nil {
@ -272,9 +278,12 @@ var listSharesCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Providers.ProviderInfoNameToMetastoreIdMap(ctx, sharing.ListProvidersRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Name of the provider in which to list shares")
if err != nil { if err != nil {
@ -335,9 +344,12 @@ var updateCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Providers.ProviderInfoNameToMetastoreIdMap(ctx, sharing.ListProvidersRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The name of the Provider")
if err != nil { if err != nil {

View File

@ -5,7 +5,7 @@ import "github.com/databricks/cli/libs/cmdio"
func init() { func init() {
// TODO: figure out colored/non-colored headers and colspan shifts // TODO: figure out colored/non-colored headers and colspan shifts
listCmd.Annotations["template"] = cmdio.Heredoc(` listCmd.Annotations["template"] = cmdio.Heredoc(`
{{white "ID"}} {{white "Name"}} {{white "Author"}} {{header "ID"}} {{header "Name"}} {{header "Author"}}
{{range .}}{{.Id|green}} {{.Name|white}} {{.User.Email|white}} {{range .}}{{.Id|green}} {{.Name|cyan}} {{.User.Email|cyan}}
{{end}}`) {{end}}`)
} }

View File

@ -116,9 +116,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Queries.QueryNameToIdMap(ctx, sql.ListQueriesRequest{})
close(promptSpinner)
if err != nil { 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, "") id, err := cmdio.Select(ctx, names, "")
if err != nil { if err != nil {
@ -172,9 +175,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Queries.QueryNameToIdMap(ctx, sql.ListQueriesRequest{})
close(promptSpinner)
if err != nil { 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, "") id, err := cmdio.Select(ctx, names, "")
if err != nil { if err != nil {
@ -281,9 +287,12 @@ var restoreCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Queries.QueryNameToIdMap(ctx, sql.ListQueriesRequest{})
close(promptSpinner)
if err != nil { 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, "") id, err := cmdio.Select(ctx, names, "")
if err != nil { if err != nil {
@ -344,9 +353,12 @@ var updateCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Queries.QueryNameToIdMap(ctx, sql.ListQueriesRequest{})
close(promptSpinner)
if err != nil { 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, "") id, err := cmdio.Select(ctx, names, "")
if err != nil { if err != nil {

View File

@ -5,6 +5,6 @@ import "github.com/databricks/cli/libs/cmdio"
func init() { func init() {
// TODO: figure out the right format // TODO: figure out the right format
listCmd.Annotations["template"] = cmdio.Heredoc(` listCmd.Annotations["template"] = cmdio.Heredoc(`
{{range .}}{{.UserName}} {{white "%s" .Status}} {{.QueryText}} {{range .}}{{.UserName}} {{cyan "%s" .Status}} {{.QueryText}}
{{end}}`) {{end}}`)
} }

View File

@ -111,9 +111,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Recipients.RecipientInfoNameToMetastoreIdMap(ctx, sharing.ListRecipientsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Name of the recipient")
if err != nil { if err != nil {
@ -168,9 +171,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Recipients.RecipientInfoNameToMetastoreIdMap(ctx, sharing.ListRecipientsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Name of the recipient")
if err != nil { if err != nil {
@ -329,9 +335,12 @@ var sharePermissionsCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Recipients.RecipientInfoNameToMetastoreIdMap(ctx, sharing.ListRecipientsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The name of the Recipient")
if err != nil { if err != nil {
@ -392,9 +401,12 @@ var updateCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Recipients.RecipientInfoNameToMetastoreIdMap(ctx, sharing.ListRecipientsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Name of Recipient")
if err != nil { if err != nil {

View File

@ -112,9 +112,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Repos.RepoInfoPathToIdMap(ctx, workspace.ListReposRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The ID for the corresponding repo to access")
if err != nil { if err != nil {
@ -170,9 +173,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Repos.RepoInfoPathToIdMap(ctx, workspace.ListReposRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The ID for the corresponding repo to access")
if err != nil { if err != nil {
@ -284,9 +290,12 @@ var updateCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Repos.RepoInfoPathToIdMap(ctx, workspace.ListReposRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The ID for the corresponding repo to access")
if err != nil { if err != nil {

View File

@ -4,7 +4,7 @@ import "github.com/databricks/cli/libs/cmdio"
func init() { func init() {
listCmd.Annotations["template"] = cmdio.Heredoc(` listCmd.Annotations["template"] = cmdio.Heredoc(`
{{white "Full Name"}} {{white "Owner"}} {{white "Comment"}} {{header "Full Name"}} {{header "Owner"}} {{header "Comment"}}
{{range .}}{{.FullName|green}} {{.Owner|white}} {{.Comment}} {{range .}}{{.FullName|green}} {{.Owner|cyan}} {{.Comment}}
{{end}}`) {{end}}`)
} }

View File

@ -109,9 +109,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Schemas.SchemaInfoNameToFullNameMap(ctx, catalog.ListSchemasRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Full name of the schema")
if err != nil { if err != nil {
@ -166,9 +169,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Schemas.SchemaInfoNameToFullNameMap(ctx, catalog.ListSchemasRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Full name of the schema")
if err != nil { if err != nil {
@ -282,9 +288,12 @@ var updateCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Schemas.SchemaInfoNameToFullNameMap(ctx, catalog.ListSchemasRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Full name of the schema")
if err != nil { if err != nil {

View File

@ -10,7 +10,7 @@ import (
func init() { func init() {
listScopesCmd.Annotations["template"] = cmdio.Heredoc(` listScopesCmd.Annotations["template"] = cmdio.Heredoc(`
{{white "Scope"}} {{white "Backend Type"}} {{header "Scope"}} {{header "Backend Type"}}
{{range .}}{{.Name|green}} {{.BackendType}} {{range .}}{{.Name|green}} {{.BackendType}}
{{end}}`) {{end}}`)

View File

@ -110,9 +110,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.ServicePrincipals.ServicePrincipalDisplayNameToIdMap(ctx, iam.ListServicePrincipalsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Unique ID for a service principal in the Databricks workspace")
if err != nil { if err != nil {
@ -166,9 +169,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.ServicePrincipals.ServicePrincipalDisplayNameToIdMap(ctx, iam.ListServicePrincipalsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Unique ID for a service principal in the Databricks workspace")
if err != nil { if err != nil {
@ -279,9 +285,12 @@ var patchCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.ServicePrincipals.ServicePrincipalDisplayNameToIdMap(ctx, iam.ListServicePrincipalsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Unique ID for a service principal in the Databricks workspace")
if err != nil { if err != nil {
@ -345,9 +354,12 @@ var updateCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.ServicePrincipals.ServicePrincipalDisplayNameToIdMap(ctx, iam.ListServicePrincipalsRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Databricks service principal ID")
if err != nil { if err != nil {

View File

@ -4,7 +4,7 @@ import "github.com/databricks/cli/libs/cmdio"
func init() { func init() {
listCmd.Annotations["template"] = cmdio.Heredoc(` listCmd.Annotations["template"] = cmdio.Heredoc(`
{{white "ID"}} {{white "Name"}} {{white "Credentials"}} {{header "ID"}} {{header "Name"}} {{header "Credentials"}}
{{range .}}{{.Id|green}} {{.Name|white}} {{if .AwsIamRole}}{{.AwsIamRole.RoleArn}}{{end}}{{if .AzureServicePrincipal}}{{.AzureServicePrincipal.ApplicationId}}{{end}}{{if .GcpServiceAccountKey}}{{.Email}}{{end}} {{range .}}{{.Id|green}} {{.Name|cyan}} {{if .AwsIamRole}}{{.AwsIamRole.RoleArn}}{{end}}{{if .AzureServicePrincipal}}{{.AzureServicePrincipal.ApplicationId}}{{end}}{{if .GcpServiceAccountKey}}{{.Email}}{{end}}
{{end}}`) {{end}}`)
} }

View File

@ -4,7 +4,7 @@ import "github.com/databricks/cli/libs/cmdio"
func init() { func init() {
listCmd.Annotations["template"] = cmdio.Heredoc(` listCmd.Annotations["template"] = cmdio.Heredoc(`
{{white "Full Name"}} {{white "Table Type"}} {{header "Full Name"}} {{header "Table Type"}}
{{range .}}{{.FullName|green}} {{blue "%s" .TableType}} {{range .}}{{.FullName|green}} {{blue "%s" .TableType}}
{{end}}`) {{end}}`)
} }

View File

@ -61,9 +61,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Tables.TableInfoNameToTableIdMap(ctx, catalog.ListTablesRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Full name of the table")
if err != nil { if err != nil {
@ -122,9 +125,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Tables.TableInfoNameToTableIdMap(ctx, catalog.ListTablesRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Full name of the table")
if err != nil { if err != nil {
@ -250,9 +256,12 @@ var listSummariesCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Tables.TableInfoNameToTableIdMap(ctx, catalog.ListTablesRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Name of parent catalog for tables of interest")
if err != nil { if err != nil {

View File

@ -4,7 +4,7 @@ import "github.com/databricks/cli/libs/cmdio"
func init() { func init() {
listCmd.Annotations["template"] = cmdio.Heredoc(` listCmd.Annotations["template"] = cmdio.Heredoc(`
{{white "ID"}} {{white "Created By"}} {{white "Comment"}} {{header "ID"}} {{header "Created By"}} {{header "Comment"}}
{{range .}}{{.TokenId|green}} {{.CreatedByUsername|white}} {{.Comment|white}} {{range .}}{{.TokenId|green}} {{.CreatedByUsername|cyan}} {{.Comment|cyan}}
{{end}}`) {{end}}`)
} }

View File

@ -105,9 +105,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.TokenManagement.TokenInfoCommentToTokenIdMap(ctx, settings.ListTokenManagementRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The ID of the token to get")
if err != nil { if err != nil {
@ -160,9 +163,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.TokenManagement.TokenInfoCommentToTokenIdMap(ctx, settings.ListTokenManagementRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The ID of the token to get")
if err != nil { if err != nil {

View File

@ -4,7 +4,7 @@ import "github.com/databricks/cli/libs/cmdio"
func init() { func init() {
listCmd.Annotations["template"] = cmdio.Heredoc(` listCmd.Annotations["template"] = cmdio.Heredoc(`
{{white "ID"}} {{white "Expiry time"}} {{white "Comment"}} {{header "ID"}} {{header "Expiry time"}} {{header "Comment"}}
{{range .}}{{.TokenId|green}} {{white "%d" .ExpiryTime}} {{.Comment|white}} {{range .}}{{.TokenId|green}} {{cyan "%d" .ExpiryTime}} {{.Comment|cyan}}
{{end}}`) {{end}}`)
} }

View File

@ -106,9 +106,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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) names, err := w.Tokens.TokenInfoCommentToTokenIdMap(ctx)
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The ID of the token to be revoked")
if err != nil { if err != nil {

View File

@ -119,9 +119,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Users.UserUserNameToIdMap(ctx, iam.ListUsersRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Unique ID for a user in the Databricks workspace")
if err != nil { if err != nil {
@ -174,9 +177,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Users.UserUserNameToIdMap(ctx, iam.ListUsersRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Unique ID for a user in the Databricks workspace")
if err != nil { if err != nil {
@ -287,9 +293,12 @@ var patchCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Users.UserUserNameToIdMap(ctx, iam.ListUsersRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Unique ID for a user in the Databricks workspace")
if err != nil { if err != nil {
@ -353,9 +362,12 @@ var updateCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Users.UserUserNameToIdMap(ctx, iam.ListUsersRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Databricks user ID")
if err != nil { if err != nil {

View File

@ -134,9 +134,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Volumes.VolumeInfoNameToVolumeIdMap(ctx, catalog.ListVolumesRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The three-level (fully qualified) name of the volume")
if err != nil { if err != nil {
@ -253,9 +256,12 @@ var readCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Volumes.VolumeInfoNameToVolumeIdMap(ctx, catalog.ListVolumesRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The three-level (fully qualified) name of the volume")
if err != nil { if err != nil {
@ -319,9 +325,12 @@ var updateCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Volumes.VolumeInfoNameToVolumeIdMap(ctx, catalog.ListVolumesRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The three-level (fully qualified) name of the volume")
if err != nil { if err != nil {

View File

@ -4,7 +4,7 @@ import "github.com/databricks/cli/libs/cmdio"
func init() { func init() {
listCmd.Annotations["template"] = cmdio.Heredoc(` listCmd.Annotations["template"] = cmdio.Heredoc(`
{{white "ID"}} {{white "Name"}} {{white "Size"}} {{white "State"}} {{header "ID"}} {{header "Name"}} {{header "Size"}} {{header "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}} {{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}}`) {{end}}`)
} }

View File

@ -148,9 +148,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Warehouses.EndpointInfoNameToIdMap(ctx, sql.ListWarehousesRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Required")
if err != nil { if err != nil {
@ -246,9 +249,12 @@ var editCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Warehouses.EndpointInfoNameToIdMap(ctx, sql.ListWarehousesRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Required")
if err != nil { if err != nil {
@ -330,9 +336,12 @@ var getCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Warehouses.EndpointInfoNameToIdMap(ctx, sql.ListWarehousesRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Required")
if err != nil { if err != nil {
@ -525,9 +534,12 @@ var startCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Warehouses.EndpointInfoNameToIdMap(ctx, sql.ListWarehousesRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Required")
if err != nil { if err != nil {
@ -609,9 +621,12 @@ var stopCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Warehouses.EndpointInfoNameToIdMap(ctx, sql.ListWarehousesRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "Required")
if err != nil { if err != nil {

View File

@ -5,7 +5,7 @@ import "github.com/databricks/cli/libs/cmdio"
func init() { func init() {
listReq.Path = "/" listReq.Path = "/"
listCmd.Annotations["template"] = cmdio.Heredoc(` listCmd.Annotations["template"] = cmdio.Heredoc(`
{{white "ID"}} {{white "Type"}} {{white "Language"}} {{white "Path"}} {{header "ID"}} {{header "Type"}} {{header "Language"}} {{header "Path"}}
{{range .}}{{green "%d" .ObjectId}} {{blue "%s" .ObjectType}} {{cyan "%s" .Language}} {{.Path|white}} {{range .}}{{green "%d" .ObjectId}} {{blue "%s" .ObjectType}} {{cyan "%s" .Language}} {{.Path|cyan}}
{{end}}`) {{end}}`)
} }

View File

@ -62,9 +62,12 @@ var deleteCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Workspace.ObjectInfoPathToObjectIdMap(ctx, workspace.ListWorkspaceRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The absolute path of the notebook or directory")
if err != nil { if err != nil {
@ -127,9 +130,12 @@ var exportCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Workspace.ObjectInfoPathToObjectIdMap(ctx, workspace.ListWorkspaceRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The absolute path of the object or directory")
if err != nil { if err != nil {
@ -172,7 +178,14 @@ var getStatusCmd = &cobra.Command{
call returns an error RESOURCE_DOES_NOT_EXIST.`, call returns an error RESOURCE_DOES_NOT_EXIST.`,
Annotations: map[string]string{}, 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) { RunE: func(cmd *cobra.Command, args []string) (err error) {
ctx := cmd.Context() ctx := cmd.Context()
w := root.WorkspaceClient(ctx) w := root.WorkspaceClient(ctx)
@ -182,20 +195,6 @@ var getStatusCmd = &cobra.Command{
return err return err
} }
} else { } else {
if len(args) == 0 {
names, err := w.Workspace.ObjectInfoPathToObjectIdMap(ctx, workspace.ListWorkspaceRequest{})
if err != nil {
return 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] getStatusReq.Path = args[0]
} }
@ -235,7 +234,14 @@ var importCmd = &cobra.Command{
use DBC format to import a directory.`, use DBC format to import a directory.`,
Annotations: map[string]string{}, 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) { RunE: func(cmd *cobra.Command, args []string) (err error) {
ctx := cmd.Context() ctx := cmd.Context()
w := root.WorkspaceClient(ctx) w := root.WorkspaceClient(ctx)
@ -245,20 +251,6 @@ var importCmd = &cobra.Command{
return err return err
} }
} else { } else {
if len(args) == 0 {
names, err := w.Workspace.ObjectInfoPathToObjectIdMap(ctx, workspace.ListWorkspaceRequest{})
if err != nil {
return 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] importReq.Path = args[0]
} }
@ -358,9 +350,12 @@ var mkdirsCmd = &cobra.Command{
} }
} else { } else {
if len(args) == 0 { 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{}) names, err := w.Workspace.ObjectInfoPathToObjectIdMap(ctx, workspace.ListWorkspaceRequest{})
close(promptSpinner)
if err != nil { 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") id, err := cmdio.Select(ctx, names, "The absolute path of the directory")
if err != nil { if err != nil {

View File

@ -33,3 +33,8 @@ func TestAccClustersGet(t *testing.T) {
assert.Contains(t, outStr, fmt.Sprintf(`"cluster_id":"%s"`, clusterId)) assert.Contains(t, outStr, fmt.Sprintf(`"cluster_id":"%s"`, clusterId))
assert.Equal(t, "", stderr.String()) 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())
}

104
internal/fs_ls_test.go Normal file
View File

@ -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")
}

View File

@ -26,7 +26,7 @@ import (
var ( var (
repoUrl = "https://github.com/databricks/databricks-empty-ide-project.git" 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. // 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 return localRoot, remoteRoot
} }
type assertSync struct { type syncTest struct {
t *testing.T t *testing.T
c *cobraTestRunner c *cobraTestRunner
w *databricks.WorkspaceClient w *databricks.WorkspaceClient
@ -67,7 +67,54 @@ type assertSync struct {
remoteRoot string 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) remoteDir := path.Join(a.remoteRoot, relativeDir)
a.c.Eventually(func() bool { a.c.Eventually(func() bool {
objects, err := a.w.Workspace.ListAll(ctx, workspace.ListWorkspaceRequest{ 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) filePath := path.Join(a.remoteRoot, relativePath)
// Remove leading "/" so we can use it in the URL. // 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) }, 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) path := path.Join(a.remoteRoot, relativePath)
a.c.Eventually(func() bool { 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) }, 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) path := path.Join(a.remoteRoot, relativePath)
a.c.Eventually(func() bool { 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) }, 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)) snapshotPath := filepath.Join(a.localRoot, ".databricks/sync-snapshots", sync.GetFileName(a.w.Config.Host, a.remoteRoot))
assert.FileExists(a.t, snapshotPath) assert.FileExists(a.t, snapshotPath)
@ -160,123 +207,87 @@ func (a *assertSync) snapshotContains(files []string) {
assert.Equal(a.t, len(files), len(s.LastUpdatedTimes)) assert.Equal(a.t, len(files), len(s.LastUpdatedTimes))
} }
func TestAccFullFileSync(t *testing.T) { func TestAccSyncFullFileSync(t *testing.T) {
t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV"))
wsc := databricks.Must(databricks.NewWorkspaceClient())
ctx := context.Background() ctx := context.Background()
assertSync := setupSyncTest(t, "--full", "--watch")
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,
}
// .gitignore is created by the sync process to enforce .databricks is not synced // .gitignore is created by the sync process to enforce .databricks is not synced
assertSync.waitForCompletionMarker()
assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore")) assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore"))
// New file // New file
localFilePath := filepath.Join(localRepoPath, "foo.txt") localFilePath := filepath.Join(assertSync.localRoot, "foo.txt")
f := testfile.CreateFile(t, localFilePath) f := testfile.CreateFile(t, localFilePath)
defer f.Close(t) defer f.Close(t)
assertSync.waitForCompletionMarker()
assertSync.remoteDirContent(ctx, "", append(repoFiles, "foo.txt", ".gitignore")) assertSync.remoteDirContent(ctx, "", append(repoFiles, "foo.txt", ".gitignore"))
assertSync.remoteFileContent(ctx, "foo.txt", "") assertSync.remoteFileContent(ctx, "foo.txt", "")
// Write to file // Write to file
f.Overwrite(t, `{"statement": "Mi Gente"}`) f.Overwrite(t, `{"statement": "Mi Gente"}`)
assertSync.waitForCompletionMarker()
assertSync.remoteFileContent(ctx, "foo.txt", `{"statement": "Mi Gente"}`) assertSync.remoteFileContent(ctx, "foo.txt", `{"statement": "Mi Gente"}`)
// Write again // Write again
f.Overwrite(t, `{"statement": "Young Dumb & Broke"}`) f.Overwrite(t, `{"statement": "Young Dumb & Broke"}`)
assertSync.waitForCompletionMarker()
assertSync.remoteFileContent(ctx, "foo.txt", `{"statement": "Young Dumb & Broke"}`) assertSync.remoteFileContent(ctx, "foo.txt", `{"statement": "Young Dumb & Broke"}`)
// delete // delete
f.Remove(t) f.Remove(t)
assertSync.waitForCompletionMarker()
assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore")) assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore"))
} }
func TestAccIncrementalFileSync(t *testing.T) { func TestAccSyncIncrementalFileSync(t *testing.T) {
t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV"))
wsc := databricks.Must(databricks.NewWorkspaceClient())
ctx := context.Background() ctx := context.Background()
assertSync := setupSyncTest(t, "--watch")
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,
}
// .gitignore is created by the sync process to enforce .databricks is not synced // .gitignore is created by the sync process to enforce .databricks is not synced
assertSync.waitForCompletionMarker()
assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore")) assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore"))
// New file // New file
localFilePath := filepath.Join(localRepoPath, "foo.txt") localFilePath := filepath.Join(assertSync.localRoot, "foo.txt")
f := testfile.CreateFile(t, localFilePath) f := testfile.CreateFile(t, localFilePath)
defer f.Close(t) defer f.Close(t)
assertSync.waitForCompletionMarker()
assertSync.remoteDirContent(ctx, "", append(repoFiles, "foo.txt", ".gitignore")) assertSync.remoteDirContent(ctx, "", append(repoFiles, "foo.txt", ".gitignore"))
assertSync.remoteFileContent(ctx, "foo.txt", "") assertSync.remoteFileContent(ctx, "foo.txt", "")
assertSync.snapshotContains(append(repoFiles, "foo.txt", ".gitignore")) assertSync.snapshotContains(append(repoFiles, "foo.txt", ".gitignore"))
// Write to file // Write to file
f.Overwrite(t, `{"statement": "Mi Gente"}`) f.Overwrite(t, `{"statement": "Mi Gente"}`)
assertSync.waitForCompletionMarker()
assertSync.remoteFileContent(ctx, "foo.txt", `{"statement": "Mi Gente"}`) assertSync.remoteFileContent(ctx, "foo.txt", `{"statement": "Mi Gente"}`)
// Write again // Write again
f.Overwrite(t, `{"statement": "Young Dumb & Broke"}`) f.Overwrite(t, `{"statement": "Young Dumb & Broke"}`)
assertSync.waitForCompletionMarker()
assertSync.remoteFileContent(ctx, "foo.txt", `{"statement": "Young Dumb & Broke"}`) assertSync.remoteFileContent(ctx, "foo.txt", `{"statement": "Young Dumb & Broke"}`)
// delete // delete
f.Remove(t) f.Remove(t)
assertSync.waitForCompletionMarker()
assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore")) assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore"))
assertSync.snapshotContains(append(repoFiles, ".gitignore")) assertSync.snapshotContains(append(repoFiles, ".gitignore"))
} }
func TestAccNestedFolderSync(t *testing.T) { func TestAccSyncNestedFolderSync(t *testing.T) {
t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV"))
wsc := databricks.Must(databricks.NewWorkspaceClient())
ctx := context.Background() ctx := context.Background()
assertSync := setupSyncTest(t, "--watch")
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,
}
// .gitignore is created by the sync process to enforce .databricks is not synced // .gitignore is created by the sync process to enforce .databricks is not synced
assertSync.waitForCompletionMarker()
assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore")) assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore"))
// New file // 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) err := os.MkdirAll(filepath.Dir(localFilePath), 0o755)
assert.NoError(t, err) assert.NoError(t, err)
f := testfile.CreateFile(t, localFilePath) f := testfile.CreateFile(t, localFilePath)
defer f.Close(t) defer f.Close(t)
assertSync.waitForCompletionMarker()
assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "dir1")) assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "dir1"))
assertSync.remoteDirContent(ctx, "dir1", []string{"dir2"}) assertSync.remoteDirContent(ctx, "dir1", []string{"dir2"})
assertSync.remoteDirContent(ctx, "dir1/dir2", []string{"dir3"}) assertSync.remoteDirContent(ctx, "dir1/dir2", []string{"dir3"})
@ -285,40 +296,27 @@ func TestAccNestedFolderSync(t *testing.T) {
// delete // delete
f.Remove(t) f.Remove(t)
assertSync.waitForCompletionMarker()
// directories are not cleaned up right now. This is not ideal // directories are not cleaned up right now. This is not ideal
assertSync.remoteDirContent(ctx, "dir1/dir2/dir3", []string{}) assertSync.remoteDirContent(ctx, "dir1/dir2/dir3", []string{})
assertSync.snapshotContains(append(repoFiles, ".gitignore")) assertSync.snapshotContains(append(repoFiles, ".gitignore"))
} }
func TestAccNestedSpacePlusAndHashAreEscapedSync(t *testing.T) { func TestAccSyncNestedSpacePlusAndHashAreEscapedSync(t *testing.T) {
t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV"))
wsc := databricks.Must(databricks.NewWorkspaceClient())
ctx := context.Background() ctx := context.Background()
assertSync := setupSyncTest(t, "--watch")
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,
}
// .gitignore is created by the sync process to enforce .databricks is not synced // .gitignore is created by the sync process to enforce .databricks is not synced
assertSync.waitForCompletionMarker()
assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore")) assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore"))
// New file // 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) err := os.MkdirAll(filepath.Dir(localFilePath), 0o755)
assert.NoError(t, err) assert.NoError(t, err)
f := testfile.CreateFile(t, localFilePath) f := testfile.CreateFile(t, localFilePath)
defer f.Close(t) defer f.Close(t)
assertSync.waitForCompletionMarker()
assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "dir1")) assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "dir1"))
assertSync.remoteDirContent(ctx, "dir1", []string{"a b+c"}) assertSync.remoteDirContent(ctx, "dir1", []string{"a b+c"})
assertSync.remoteDirContent(ctx, "dir1/a b+c", []string{"c+d e"}) assertSync.remoteDirContent(ctx, "dir1/a b+c", []string{"c+d e"})
@ -327,6 +325,7 @@ func TestAccNestedSpacePlusAndHashAreEscapedSync(t *testing.T) {
// delete // delete
f.Remove(t) f.Remove(t)
assertSync.waitForCompletionMarker()
// directories are not cleaned up right now. This is not ideal // directories are not cleaned up right now. This is not ideal
assertSync.remoteDirContent(ctx, "dir1/a b+c/c+d e", []string{}) assertSync.remoteDirContent(ctx, "dir1/a b+c/c+d e", []string{})
assertSync.snapshotContains(append(repoFiles, ".gitignore")) 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 // In the above scenario sync should delete the empty folder and add foo to the remote
// file system // file system
func TestAccIncrementalFileOverwritesFolder(t *testing.T) { func TestAccSyncIncrementalFileOverwritesFolder(t *testing.T) {
t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV"))
wsc := databricks.Must(databricks.NewWorkspaceClient())
ctx := context.Background() ctx := context.Background()
assertSync := setupSyncTest(t, "--watch")
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,
}
// create foo/bar.txt // 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) err := os.MkdirAll(filepath.Dir(localFilePath), 0o755)
assert.NoError(t, err) assert.NoError(t, err)
f := testfile.CreateFile(t, localFilePath) f := testfile.CreateFile(t, localFilePath)
defer f.Close(t) defer f.Close(t)
assertSync.waitForCompletionMarker()
assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "foo")) assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "foo"))
assertSync.remoteDirContent(ctx, "foo", []string{"bar.txt"}) assertSync.remoteDirContent(ctx, "foo", []string{"bar.txt"})
assertSync.snapshotContains(append(repoFiles, ".gitignore", filepath.FromSlash("foo/bar.txt"))) assertSync.snapshotContains(append(repoFiles, ".gitignore", filepath.FromSlash("foo/bar.txt")))
// delete foo/bar.txt // delete foo/bar.txt
f.Remove(t) f.Remove(t)
os.Remove(filepath.Join(localRepoPath, "foo")) os.Remove(filepath.Join(assertSync.localRoot, "foo"))
assertSync.waitForCompletionMarker()
assertSync.remoteDirContent(ctx, "foo", []string{}) assertSync.remoteDirContent(ctx, "foo", []string{})
assertSync.objectType(ctx, "foo", "DIRECTORY") assertSync.objectType(ctx, "foo", "DIRECTORY")
assertSync.snapshotContains(append(repoFiles, ".gitignore")) 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) defer f2.Close(t)
assertSync.waitForCompletionMarker()
assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "foo")) assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "foo"))
assertSync.objectType(ctx, "foo", "FILE") assertSync.objectType(ctx, "foo", "FILE")
assertSync.snapshotContains(append(repoFiles, ".gitignore", "foo")) assertSync.snapshotContains(append(repoFiles, ".gitignore", "foo"))
} }
func TestAccIncrementalSyncPythonNotebookToFile(t *testing.T) { func TestAccSyncIncrementalSyncPythonNotebookToFile(t *testing.T) {
t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV"))
wsc := databricks.Must(databricks.NewWorkspaceClient())
ctx := context.Background() ctx := context.Background()
assertSync := setupSyncTest(t, "--watch")
localRepoPath, remoteRepoPath := setupRepo(t, wsc, ctx)
// create python notebook // create python notebook
localFilePath := filepath.Join(localRepoPath, "foo.py") localFilePath := filepath.Join(assertSync.localRoot, "foo.py")
f := testfile.CreateFile(t, localFilePath) f := testfile.CreateFile(t, localFilePath)
defer f.Close(t) defer f.Close(t)
f.Overwrite(t, "# Databricks notebook source") 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 // notebook was uploaded properly
assertSync.waitForCompletionMarker()
assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "foo")) assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "foo"))
assertSync.objectType(ctx, "foo", "NOTEBOOK") assertSync.objectType(ctx, "foo", "NOTEBOOK")
assertSync.language(ctx, "foo", "PYTHON") assertSync.language(ctx, "foo", "PYTHON")
@ -419,40 +390,27 @@ func TestAccIncrementalSyncPythonNotebookToFile(t *testing.T) {
// convert to vanilla python file // convert to vanilla python file
f.Overwrite(t, "# No longer a python notebook") f.Overwrite(t, "# No longer a python notebook")
assertSync.waitForCompletionMarker()
assertSync.objectType(ctx, "foo.py", "FILE") assertSync.objectType(ctx, "foo.py", "FILE")
assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "foo.py")) assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "foo.py"))
assertSync.snapshotContains(append(repoFiles, ".gitignore", "foo.py")) assertSync.snapshotContains(append(repoFiles, ".gitignore", "foo.py"))
// delete the vanilla python file // delete the vanilla python file
f.Remove(t) f.Remove(t)
assertSync.waitForCompletionMarker()
assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore")) assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore"))
assertSync.snapshotContains(append(repoFiles, ".gitignore")) assertSync.snapshotContains(append(repoFiles, ".gitignore"))
} }
func TestAccIncrementalSyncFileToPythonNotebook(t *testing.T) { func TestAccSyncIncrementalSyncFileToPythonNotebook(t *testing.T) {
t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV"))
wsc := databricks.Must(databricks.NewWorkspaceClient())
ctx := context.Background() ctx := context.Background()
assertSync := setupSyncTest(t, "--watch")
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,
}
// create vanilla python file // create vanilla python file
localFilePath := filepath.Join(localRepoPath, "foo.py") localFilePath := filepath.Join(assertSync.localRoot, "foo.py")
f := testfile.CreateFile(t, localFilePath) f := testfile.CreateFile(t, localFilePath)
defer f.Close(t) defer f.Close(t)
assertSync.waitForCompletionMarker()
// assert file upload // assert file upload
assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "foo.py")) assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "foo.py"))
@ -461,37 +419,23 @@ func TestAccIncrementalSyncFileToPythonNotebook(t *testing.T) {
// convert to notebook // convert to notebook
f.Overwrite(t, "# Databricks notebook source") f.Overwrite(t, "# Databricks notebook source")
assertSync.waitForCompletionMarker()
assertSync.objectType(ctx, "foo", "NOTEBOOK") assertSync.objectType(ctx, "foo", "NOTEBOOK")
assertSync.language(ctx, "foo", "PYTHON") assertSync.language(ctx, "foo", "PYTHON")
assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "foo")) assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "foo"))
assertSync.snapshotContains(append(repoFiles, ".gitignore", "foo.py")) assertSync.snapshotContains(append(repoFiles, ".gitignore", "foo.py"))
} }
func TestAccIncrementalSyncPythonNotebookDelete(t *testing.T) { func TestAccSyncIncrementalSyncPythonNotebookDelete(t *testing.T) {
t.Log(GetEnvOrSkipTest(t, "CLOUD_ENV"))
wsc := databricks.Must(databricks.NewWorkspaceClient())
ctx := context.Background() ctx := context.Background()
assertSync := setupSyncTest(t, "--watch")
localRepoPath, remoteRepoPath := setupRepo(t, wsc, ctx)
// create python notebook // create python notebook
localFilePath := filepath.Join(localRepoPath, "foo.py") localFilePath := filepath.Join(assertSync.localRoot, "foo.py")
f := testfile.CreateFile(t, localFilePath) f := testfile.CreateFile(t, localFilePath)
defer f.Close(t) defer f.Close(t)
f.Overwrite(t, "# Databricks notebook source") f.Overwrite(t, "# Databricks notebook source")
assertSync.waitForCompletionMarker()
// 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 // notebook was uploaded properly
assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "foo")) assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore", "foo"))
@ -500,6 +444,7 @@ func TestAccIncrementalSyncPythonNotebookDelete(t *testing.T) {
// Delete notebook // Delete notebook
f.Remove(t) f.Remove(t)
assertSync.waitForCompletionMarker()
assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore")) assertSync.remoteDirContent(ctx, "", append(repoFiles, ".gitignore"))
} }

View File

@ -22,3 +22,8 @@ func TestWorkpaceListErrorWhenNoArguments(t *testing.T) {
_, _, err := RequireErrorRun(t, "workspace", "list") _, _, err := RequireErrorRun(t, "workspace", "list")
assert.Equal(t, "accepts 1 arg(s), received 0", err.Error()) 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())
}

View File

@ -16,6 +16,8 @@ import (
"time" "time"
"github.com/databricks/cli/libs/auth/cache" "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/databricks/databricks-sdk-go/retries"
"github.com/pkg/browser" "github.com/pkg/browser"
"golang.org/x/oauth2" "golang.org/x/oauth2"
@ -95,6 +97,16 @@ func (a *PersistentAuth) Load(ctx context.Context) (*oauth2.Token, error) {
return refreshed, nil 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 { func (a *PersistentAuth) Challenge(ctx context.Context) error {
err := a.init(ctx) err := a.init(ctx)
if err != nil { if err != nil {
@ -120,7 +132,12 @@ func (a *PersistentAuth) Challenge(ctx context.Context) error {
if err != nil { if err != nil {
return fmt.Errorf("store: %w", err) 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 { func (a *PersistentAuth) init(ctx context.Context) error {

View File

@ -66,14 +66,20 @@ func (c *cmdIO) IsTTY() bool {
return isatty.IsTerminal(fd) || isatty.IsCygwinTerminal(fd) 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 // TODO: add terminal width & white/dark theme detection
c := fromContext(ctx)
switch c.outputFormat { switch c.outputFormat {
case flags.OutputJSON: case flags.OutputJSON:
return renderJson(c.out, v) return renderJson(c.out, v)
case flags.OutputText: case flags.OutputText:
if c.template != "" { if template != "" {
return renderTemplate(c.out, c.template, v) return renderTemplate(c.out, template, v)
} }
return renderJson(c.out, v) return renderJson(c.out, v)
default: 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 } type tuple struct{ Name, Id string }
func (c *cmdIO) Select(names map[string]string, label string) (id string, err error) { func (c *cmdIO) Select(names map[string]string, label string) (id string, err error) {

View File

@ -6,6 +6,7 @@ import (
"strings" "strings"
"text/tabwriter" "text/tabwriter"
"text/template" "text/template"
"time"
"github.com/fatih/color" "github.com/fatih/color"
"github.com/nwidger/jsoncolor" "github.com/nwidger/jsoncolor"
@ -58,8 +59,7 @@ func renderTemplate(w io.Writer, tmpl string, v any) error {
// we render colored output if stdout is TTY, otherwise we render text. // 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 // in the future we'll check if we can explicitly check for stderr being
// a TTY // a TTY
"black": color.BlackString, "header": color.BlueString,
"white": color.WhiteString,
"red": color.RedString, "red": color.RedString,
"green": color.GreenString, "green": color.GreenString,
"blue": color.BlueString, "blue": color.BlueString,
@ -86,6 +86,9 @@ func renderTemplate(w io.Writer, tmpl string, v any) error {
} }
return string(b), nil return string(b), nil
}, },
"pretty_date": func(t time.Time) string {
return t.Format("2006-01-02T15:04:05Z")
},
}).Parse(tmpl) }).Parse(tmpl)
if err != nil { if err != nil {
return err return err
@ -107,8 +110,9 @@ func fancyJSON(v any) ([]byte, error) {
f.FalseColor = color.New(color.FgRed) f.FalseColor = color.New(color.FgRed)
f.NumberColor = color.New(color.FgCyan) f.NumberColor = color.New(color.FgCyan)
f.NullColor = color.New(color.FgMagenta) f.NullColor = color.New(color.FgMagenta)
f.FieldColor = color.New(color.FgWhite, color.Bold) f.ObjectColor = color.New(color.Reset)
f.FieldQuoteColor = color.New(color.FgWhite) f.CommaColor = color.New(color.Reset)
f.ColonColor = color.New(color.Reset)
return jsoncolor.MarshalIndentWithFormatter(v, "", " ", f) return jsoncolor.MarshalIndentWithFormatter(v, "", " ", f)
} }

View File

@ -2,6 +2,7 @@ package databrickscfg
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"os" "os"
"strings" "strings"
@ -13,6 +14,43 @@ import (
var ResolveProfileFromHost = profileFromHostLoader{} 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{} type profileFromHostLoader struct{}
func (l profileFromHostLoader) Name() string { func (l profileFromHostLoader) Name() string {
@ -27,6 +65,7 @@ func (l profileFromHostLoader) Configure(cfg *config.Config) error {
return nil return nil
} }
ctx := context.Background()
configFile, err := config.LoadFile(cfg.ConfigFile) configFile, err := config.LoadFile(cfg.ConfigFile)
if err != nil { if err != nil {
if os.IsNotExist(err) { 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) return fmt.Errorf("cannot parse config file: %w", err)
} }
// Normalized version of the configured host. // Normalized version of the configured host.
host := normalizeHost(cfg.Host) host := normalizeHost(cfg.Host)
match, err := findMatchingProfile(configFile, func(s *ini.Section) bool {
// Look for sections in the configuration file that match the configured host. key, err := s.GetKey("host")
var matching []*ini.Section
for _, section := range configFile.Sections() {
key, err := section.GetKey("host")
if err != nil { if err != nil {
log.Tracef(context.Background(), "section %s: %s", section.Name(), err) log.Tracef(ctx, "section %s: %s", s.Name(), err)
continue return false
} }
// Ignore this section if the normalized host doesn't match. // Check if this section matches the normalized host
if normalizeHost(key.Value()) != host { return normalizeHost(key.Value()) == host
continue })
} if err == errNoMatchingProfiles {
matching = append(matching, section)
}
// If there are no matching sections, we don't do anything.
if len(matching) == 0 {
return nil return nil
} }
if err, ok := err.(errMultipleProfiles); ok {
// 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())
}
return fmt.Errorf( return fmt.Errorf(
"multiple profiles for host %s (%s): please set DATABRICKS_CONFIG_PROFILE to specify one", "%s: %w: please set DATABRICKS_CONFIG_PROFILE to specify one",
host, host, err)
strings.Join(names, ", "), }
) if err != nil {
return err
} }
match := matching[0] log.Debugf(ctx, "Loading profile %s because of host match", match.Name())
log.Debugf(context.Background(), "Loading profile %s because of host match", match.Name())
err = config.ConfigAttributes.ResolveFromStringMap(cfg, match.KeysHash()) err = config.ConfigAttributes.ResolveFromStringMap(cfg, match.KeysHash())
if err != nil { if err != nil {
return fmt.Errorf("%s %s profile: %w", configFile.Path(), match.Name(), err) return fmt.Errorf("%s %s profile: %w", configFile.Path(), match.Name(), err)
} }
return nil return nil
} }
func (l profileFromHostLoader) isAnyAuthConfigured(cfg *config.Config) bool { func (l profileFromHostLoader) isAnyAuthConfigured(cfg *config.Config) bool {

View File

@ -126,5 +126,5 @@ func TestLoaderErrorsOnMultipleMatches(t *testing.T) {
err := cfg.EnsureResolved() err := cfg.EnsureResolved()
assert.Error(t, err) 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")
} }

122
libs/databrickscfg/ops.go Normal file
View File

@ -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())
}

View File

@ -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"])
}

View File

@ -14,6 +14,10 @@ token = query
host = https://foo host = https://foo
token = foo1 token = foo1
[acc]
host = https://accounts.cloud.databricks.com
account_id = abc
# Duplicate entry for https://foo # Duplicate entry for https://foo
[foo2] [foo2]
host = https://foo host = https://foo

View File

@ -222,6 +222,10 @@ func (w *DbfsClient) ReadDir(ctx context.Context, name string) ([]fs.DirEntry, e
return nil, err return nil, err
} }
if len(res.Files) == 1 && res.Files[0].Path == absPath {
return nil, NotADirectory{absPath}
}
info := make([]fs.DirEntry, len(res.Files)) info := make([]fs.DirEntry, len(res.Files))
for i, v := range res.Files { for i, v := range res.Files {
info[i] = dbfsDirEntry{dbfsFileInfo: dbfsFileInfo{fi: v}} info[i] = dbfsDirEntry{dbfsFileInfo: dbfsFileInfo{fi: v}}

View File

@ -51,6 +51,18 @@ func (err NoSuchDirectoryError) Is(other error) bool {
return other == fs.ErrNotExist 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. // Filer is used to access files in a workspace.
// It has implementations for accessing files in WSFS and in DBFS. // It has implementations for accessing files in WSFS and in DBFS.
type Filer interface { type Filer interface {

151
libs/filer/fs.go Normal file
View File

@ -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
}

288
libs/filer/fs_test.go Normal file
View File

@ -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())
}

View File

@ -222,6 +222,11 @@ func (w *WorkspaceFilesClient) ReadDir(ctx context.Context, name string) ([]fs.D
objects, err := w.workspaceClient.Workspace.ListAll(ctx, workspace.ListWorkspaceRequest{ objects, err := w.workspaceClient.Workspace.ListAll(ctx, workspace.ListWorkspaceRequest{
Path: absPath, Path: absPath,
}) })
if len(objects) == 1 && objects[0].Path == absPath {
return nil, NotADirectory{absPath}
}
if err != nil { if err != nil {
// If we got an API error we deal with it below. // If we got an API error we deal with it below.
var aerr *apierr.APIError var aerr *apierr.APIError