From 98477699a0ded474824179393d43672d75708e3c Mon Sep 17 00:00:00 2001 From: Andrew Nester Date: Wed, 17 Jan 2024 14:14:20 +0000 Subject: [PATCH] Always require path parameters as positional arguments (#1129) ## Changes Always require path parameters as positional arguments Note: uses a generator with this SDK change: https://github.com/databricks/databricks-sdk-go/pull/773 Fixes https://github.com/databricks/cli/issues/1121 --- .codegen/service.go.tmpl | 57 +++++++++++-------- cmd/account/budgets/budgets.go | 13 ++++- .../workspace-assignment.go | 21 ++++++- cmd/workspace/alerts/alerts.go | 8 ++- .../artifact-allowlists.go | 16 +++++- cmd/workspace/connections/connections.go | 13 ++++- .../dashboard-widgets/dashboard-widgets.go | 13 ++++- .../query-visualizations.go | 13 ++++- .../vector-search-indexes.go | 27 +++++++-- 9 files changed, 140 insertions(+), 41 deletions(-) diff --git a/.codegen/service.go.tmpl b/.codegen/service.go.tmpl index 8026e94f..a0cd0219 100644 --- a/.codegen/service.go.tmpl +++ b/.codegen/service.go.tmpl @@ -125,18 +125,20 @@ func new{{.PascalName}}() *cobra.Command { {{- $fullCommandName := (print $serviceName " " .KebabName) -}} {{- $noPrompt := or .IsCrudCreate (in $excludeFromPrompts $fullCommandName) }} - {{- $hasPosArgs := and (not .MustUseJson) (and .Request (or .Request.IsAllRequiredFieldsPrimitive (eq .PascalName "RunNow"))) -}} + {{- $hasPosArgs := .HasRequiredPositionalArguments -}} {{- $hasSinglePosArg := and $hasPosArgs (eq 1 (len .Request.RequiredFields)) -}} {{- $serviceHasNamedIdMap := and (and .Service.List .Service.List.NamedIdMap) (not (eq .PascalName "List")) -}} {{- $hasIdPrompt := and (not $noPrompt) (and $hasSinglePosArg $serviceHasNamedIdMap) -}} {{- $wait := and .Wait (and (not .IsCrudRead) (not (eq .SnakeName "get_run"))) -}} {{- $hasRequiredArgs := and (not $hasIdPrompt) $hasPosArgs -}} {{- $hasSingleRequiredRequestBodyFieldWithPrompt := and (and $hasIdPrompt .Request) (eq 1 (len .Request.RequiredRequestBodyFields)) -}} - {{- $hasCustomArgHandler := and (not .MustUseJson) (or $hasRequiredArgs (and .CanUseJson .Request.HasRequiredRequestBodyFields)) -}} + {{- $onlyPathArgsRequiredAsPositionalArguments := and .Request (eq (len .RequiredPositionalArguments) (len .Request.RequiredPathFields)) -}} + {{- $hasDifferentArgsWithJsonFlag := and (not $onlyPathArgsRequiredAsPositionalArguments) (and .CanUseJson .Request.HasRequiredRequestBodyFields) -}} + {{- $hasCustomArgHandler := or $hasRequiredArgs $hasDifferentArgsWithJsonFlag -}} {{- $atleastOneArgumentWithDescription := false -}} {{- if $hasPosArgs -}} - {{- range .Request.RequiredFields -}} + {{- range .RequiredPositionalArguments -}} {{- if .HasComment -}} {{- $atleastOneArgumentWithDescription = true -}} {{- break -}} @@ -144,14 +146,14 @@ func new{{.PascalName}}() *cobra.Command { {{- end -}} {{- end -}} - cmd.Use = "{{.KebabName}}{{if $hasPosArgs}}{{range .Request.RequiredFields}} {{.ConstantName}}{{end}}{{end}}" + cmd.Use = "{{.KebabName}}{{if $hasPosArgs}}{{range .RequiredPositionalArguments}} {{.ConstantName}}{{end}}{{end}}" {{- if .Description }} cmd.Short = `{{.Summary | without "`"}}` cmd.Long = `{{.Comment " " 80 | without "`"}} {{- if $atleastOneArgumentWithDescription }} Arguments: - {{- range .Request.RequiredFields }} + {{- range .RequiredPositionalArguments }} {{ .ConstantName }}: {{.Comment " " 80 | without "`"}} {{- end -}} {{- end -}} @@ -166,7 +168,7 @@ func new{{.PascalName}}() *cobra.Command { cmd.Annotations = make(map[string]string) {{ if $hasCustomArgHandler }} cmd.Args = func(cmd *cobra.Command, args []string) error { - {{- if and .CanUseJson .Request.HasRequiredRequestBodyFields }} + {{- if $hasDifferentArgsWithJsonFlag }} if cmd.Flags().Changed("json") { err := cobra.ExactArgs({{len .Request.RequiredPathFields}})(cmd, args) if err != nil { @@ -180,7 +182,7 @@ func new{{.PascalName}}() *cobra.Command { } {{- end }} {{- if $hasRequiredArgs }} - check := cobra.ExactArgs({{len .Request.RequiredFields}}) + check := cobra.ExactArgs({{len .RequiredPositionalArguments}}) return check(cmd, args) {{- else}} return nil @@ -201,7 +203,7 @@ func new{{.PascalName}}() *cobra.Command { }{{end}}{{ if .MustUseJson }}else { return fmt.Errorf("please provide command input in JSON format by specifying the --json flag") }{{- end}} - {{- if (not .MustUseJson) }} + {{- if $hasPosArgs }} {{- if and .CanUseJson $hasSingleRequiredRequestBodyFieldWithPrompt }} else { {{- end}} {{- if $hasIdPrompt}} @@ -225,23 +227,9 @@ func new{{.PascalName}}() *cobra.Command { {{- end -}} {{$method := .}} - {{- range $arg, $field := .Request.RequiredFields}} - {{- $optionalIfJsonIsUsed := and (not $hasIdPrompt) (and $field.IsRequestBodyField $method.CanUseJson) }} - {{- if $optionalIfJsonIsUsed }} - if !cmd.Flags().Changed("json") { - {{- end }} - {{if not $field.Entity.IsString -}} - _, err = fmt.Sscan(args[{{$arg}}], &{{$method.CamelName}}Req.{{$field.PascalName}}) - if err != nil { - return fmt.Errorf("invalid {{$field.ConstantName}}: %s", args[{{$arg}}]) - }{{else -}} - {{$method.CamelName}}Req.{{$field.PascalName}} = args[{{$arg}}] - {{- end -}} - {{- if $optionalIfJsonIsUsed }} - } - {{- end }} + {{- range $arg, $field := .RequiredPositionalArguments}} + {{- template "args-scan" (dict "Arg" $arg "Field" $field "Method" $method "HasIdPrompt" $hasIdPrompt)}} {{- end -}} - {{- if and .CanUseJson $hasSingleRequiredRequestBodyFieldWithPrompt }} } {{- end}} @@ -338,3 +326,24 @@ func init() { {{- else}}/* NOT PRIMITIVE */ {{- end -}} {{- end -}} + +{{- define "args-scan" -}} + {{- $field := .Field -}} + {{- $method := .Method -}} + {{- $arg := .Arg -}} + {{- $hasIdPrompt := .HasIdPrompt -}} + {{- $optionalIfJsonIsUsed := and (not $hasIdPrompt) (and $field.IsRequestBodyField $method.CanUseJson) }} + {{- if $optionalIfJsonIsUsed }} + if !cmd.Flags().Changed("json") { + {{- end }} + {{if not $field.Entity.IsString -}} + _, err = fmt.Sscan(args[{{$arg}}], &{{$method.CamelName}}Req.{{$field.PascalName}}) + if err != nil { + return fmt.Errorf("invalid {{$field.ConstantName}}: %s", args[{{$arg}}]) + }{{else -}} + {{$method.CamelName}}Req.{{$field.PascalName}} = args[{{$arg}}] + {{- end -}} + {{- if $optionalIfJsonIsUsed }} + } + {{- end }} +{{- end -}} diff --git a/cmd/account/budgets/budgets.go b/cmd/account/budgets/budgets.go index d5ffe663..69237900 100755 --- a/cmd/account/budgets/budgets.go +++ b/cmd/account/budgets/budgets.go @@ -324,15 +324,23 @@ func newUpdate() *cobra.Command { // TODO: short flags cmd.Flags().Var(&updateJson, "json", `either inline JSON string or @path/to/file.json with request body`) - cmd.Use = "update" + cmd.Use = "update BUDGET_ID" cmd.Short = `Modify budget.` cmd.Long = `Modify budget. Modifies a budget in this account. Budget properties are completely - overwritten.` + overwritten. + + Arguments: + BUDGET_ID: Budget ID` cmd.Annotations = make(map[string]string) + cmd.Args = func(cmd *cobra.Command, args []string) error { + check := cobra.ExactArgs(1) + return check(cmd, args) + } + cmd.PreRunE = root.MustAccountClient cmd.RunE = func(cmd *cobra.Command, args []string) (err error) { ctx := cmd.Context() @@ -346,6 +354,7 @@ func newUpdate() *cobra.Command { } else { return fmt.Errorf("please provide command input in JSON format by specifying the --json flag") } + updateReq.BudgetId = args[0] err = a.Budgets.Update(ctx, updateReq) if err != nil { diff --git a/cmd/account/workspace-assignment/workspace-assignment.go b/cmd/account/workspace-assignment/workspace-assignment.go index f442b03e..7780d90f 100755 --- a/cmd/account/workspace-assignment/workspace-assignment.go +++ b/cmd/account/workspace-assignment/workspace-assignment.go @@ -262,15 +262,24 @@ func newUpdate() *cobra.Command { // TODO: short flags cmd.Flags().Var(&updateJson, "json", `either inline JSON string or @path/to/file.json with request body`) - cmd.Use = "update" + cmd.Use = "update WORKSPACE_ID PRINCIPAL_ID" cmd.Short = `Create or update permissions assignment.` cmd.Long = `Create or update permissions assignment. Creates or updates the workspace permissions assignment in a given account and - workspace for the specified principal.` + workspace for the specified principal. + + Arguments: + WORKSPACE_ID: The workspace ID. + PRINCIPAL_ID: The ID of the user, service principal, or group.` cmd.Annotations = make(map[string]string) + cmd.Args = func(cmd *cobra.Command, args []string) error { + check := cobra.ExactArgs(2) + return check(cmd, args) + } + cmd.PreRunE = root.MustAccountClient cmd.RunE = func(cmd *cobra.Command, args []string) (err error) { ctx := cmd.Context() @@ -284,6 +293,14 @@ func newUpdate() *cobra.Command { } else { return fmt.Errorf("please provide command input in JSON format by specifying the --json flag") } + _, err = fmt.Sscan(args[0], &updateReq.WorkspaceId) + if err != nil { + return fmt.Errorf("invalid WORKSPACE_ID: %s", args[0]) + } + _, err = fmt.Sscan(args[1], &updateReq.PrincipalId) + if err != nil { + return fmt.Errorf("invalid PRINCIPAL_ID: %s", args[1]) + } err = a.WorkspaceAssignment.Update(ctx, updateReq) if err != nil { diff --git a/cmd/workspace/alerts/alerts.go b/cmd/workspace/alerts/alerts.go index 7c98f7ee..773a3487 100755 --- a/cmd/workspace/alerts/alerts.go +++ b/cmd/workspace/alerts/alerts.go @@ -325,7 +325,7 @@ func newUpdate() *cobra.Command { cmd.Flags().IntVar(&updateReq.Rearm, "rearm", updateReq.Rearm, `Number of seconds after being triggered before the alert rearms itself and can be triggered again.`) - cmd.Use = "update" + cmd.Use = "update ALERT_ID" cmd.Short = `Update an alert.` cmd.Long = `Update an alert. @@ -333,6 +333,11 @@ func newUpdate() *cobra.Command { cmd.Annotations = make(map[string]string) + cmd.Args = func(cmd *cobra.Command, args []string) error { + check := cobra.ExactArgs(1) + return check(cmd, args) + } + cmd.PreRunE = root.MustWorkspaceClient cmd.RunE = func(cmd *cobra.Command, args []string) (err error) { ctx := cmd.Context() @@ -346,6 +351,7 @@ func newUpdate() *cobra.Command { } else { return fmt.Errorf("please provide command input in JSON format by specifying the --json flag") } + updateReq.AlertId = args[0] err = w.Alerts.Update(ctx, updateReq) if err != nil { diff --git a/cmd/workspace/artifact-allowlists/artifact-allowlists.go b/cmd/workspace/artifact-allowlists/artifact-allowlists.go index 21fdba12..e0b36ff9 100755 --- a/cmd/workspace/artifact-allowlists/artifact-allowlists.go +++ b/cmd/workspace/artifact-allowlists/artifact-allowlists.go @@ -123,16 +123,24 @@ func newUpdate() *cobra.Command { // TODO: short flags cmd.Flags().Var(&updateJson, "json", `either inline JSON string or @path/to/file.json with request body`) - cmd.Use = "update" + cmd.Use = "update ARTIFACT_TYPE" cmd.Short = `Set an artifact allowlist.` cmd.Long = `Set an artifact allowlist. Set the artifact allowlist of a certain artifact type. The whole artifact allowlist is replaced with the new allowlist. The caller must be a metastore - admin or have the **MANAGE ALLOWLIST** privilege on the metastore.` + admin or have the **MANAGE ALLOWLIST** privilege on the metastore. + + Arguments: + ARTIFACT_TYPE: The artifact type of the allowlist.` cmd.Annotations = make(map[string]string) + cmd.Args = func(cmd *cobra.Command, args []string) error { + check := cobra.ExactArgs(1) + return check(cmd, args) + } + cmd.PreRunE = root.MustWorkspaceClient cmd.RunE = func(cmd *cobra.Command, args []string) (err error) { ctx := cmd.Context() @@ -146,6 +154,10 @@ func newUpdate() *cobra.Command { } else { return fmt.Errorf("please provide command input in JSON format by specifying the --json flag") } + _, err = fmt.Sscan(args[0], &updateReq.ArtifactType) + if err != nil { + return fmt.Errorf("invalid ARTIFACT_TYPE: %s", args[0]) + } response, err := w.ArtifactAllowlists.Update(ctx, updateReq) if err != nil { diff --git a/cmd/workspace/connections/connections.go b/cmd/workspace/connections/connections.go index 99161613..5ad0c199 100755 --- a/cmd/workspace/connections/connections.go +++ b/cmd/workspace/connections/connections.go @@ -340,14 +340,22 @@ func newUpdate() *cobra.Command { cmd.Flags().StringVar(&updateReq.NewName, "new-name", updateReq.NewName, `New name for the connection.`) cmd.Flags().StringVar(&updateReq.Owner, "owner", updateReq.Owner, `Username of current owner of the connection.`) - cmd.Use = "update" + cmd.Use = "update NAME_ARG" cmd.Short = `Update a connection.` cmd.Long = `Update a connection. - Updates the connection that matches the supplied name.` + Updates the connection that matches the supplied name. + + Arguments: + NAME_ARG: Name of the connection.` cmd.Annotations = make(map[string]string) + cmd.Args = func(cmd *cobra.Command, args []string) error { + check := cobra.ExactArgs(1) + return check(cmd, args) + } + cmd.PreRunE = root.MustWorkspaceClient cmd.RunE = func(cmd *cobra.Command, args []string) (err error) { ctx := cmd.Context() @@ -361,6 +369,7 @@ func newUpdate() *cobra.Command { } else { return fmt.Errorf("please provide command input in JSON format by specifying the --json flag") } + updateReq.NameArg = args[0] response, err := w.Connections.Update(ctx, updateReq) if err != nil { diff --git a/cmd/workspace/dashboard-widgets/dashboard-widgets.go b/cmd/workspace/dashboard-widgets/dashboard-widgets.go index c3b3ae03..43a972e0 100755 --- a/cmd/workspace/dashboard-widgets/dashboard-widgets.go +++ b/cmd/workspace/dashboard-widgets/dashboard-widgets.go @@ -183,12 +183,20 @@ func newUpdate() *cobra.Command { // TODO: short flags cmd.Flags().Var(&updateJson, "json", `either inline JSON string or @path/to/file.json with request body`) - cmd.Use = "update" + cmd.Use = "update ID" cmd.Short = `Update existing widget.` - cmd.Long = `Update existing widget.` + cmd.Long = `Update existing widget. + + Arguments: + ID: Widget ID returned by :method:dashboardwidgets/create` cmd.Annotations = make(map[string]string) + cmd.Args = func(cmd *cobra.Command, args []string) error { + check := cobra.ExactArgs(1) + return check(cmd, args) + } + cmd.PreRunE = root.MustWorkspaceClient cmd.RunE = func(cmd *cobra.Command, args []string) (err error) { ctx := cmd.Context() @@ -202,6 +210,7 @@ func newUpdate() *cobra.Command { } else { return fmt.Errorf("please provide command input in JSON format by specifying the --json flag") } + updateReq.Id = args[0] response, err := w.DashboardWidgets.Update(ctx, updateReq) if err != nil { diff --git a/cmd/workspace/query-visualizations/query-visualizations.go b/cmd/workspace/query-visualizations/query-visualizations.go index 042faa5b..4f04c426 100755 --- a/cmd/workspace/query-visualizations/query-visualizations.go +++ b/cmd/workspace/query-visualizations/query-visualizations.go @@ -183,12 +183,20 @@ func newUpdate() *cobra.Command { // TODO: short flags cmd.Flags().Var(&updateJson, "json", `either inline JSON string or @path/to/file.json with request body`) - cmd.Use = "update" + cmd.Use = "update ID" cmd.Short = `Edit existing visualization.` - cmd.Long = `Edit existing visualization.` + cmd.Long = `Edit existing visualization. + + Arguments: + ID: The UUID for this visualization.` cmd.Annotations = make(map[string]string) + cmd.Args = func(cmd *cobra.Command, args []string) error { + check := cobra.ExactArgs(1) + return check(cmd, args) + } + cmd.PreRunE = root.MustWorkspaceClient cmd.RunE = func(cmd *cobra.Command, args []string) (err error) { ctx := cmd.Context() @@ -202,6 +210,7 @@ func newUpdate() *cobra.Command { } else { return fmt.Errorf("please provide command input in JSON format by specifying the --json flag") } + updateReq.Id = args[0] response, err := w.QueryVisualizations.Update(ctx, updateReq) if err != nil { diff --git a/cmd/workspace/vector-search-indexes/vector-search-indexes.go b/cmd/workspace/vector-search-indexes/vector-search-indexes.go index c9b25ad1..8999967f 100755 --- a/cmd/workspace/vector-search-indexes/vector-search-indexes.go +++ b/cmd/workspace/vector-search-indexes/vector-search-indexes.go @@ -163,14 +163,23 @@ func newDeleteDataVectorIndex() *cobra.Command { // TODO: short flags cmd.Flags().Var(&deleteDataVectorIndexJson, "json", `either inline JSON string or @path/to/file.json with request body`) - cmd.Use = "delete-data-vector-index" + cmd.Use = "delete-data-vector-index NAME" cmd.Short = `Delete data from index.` cmd.Long = `Delete data from index. - Handles the deletion of data from a specified vector index.` + Handles the deletion of data from a specified vector index. + + Arguments: + NAME: Name of the vector index where data is to be deleted. Must be a Direct + Vector Access Index.` cmd.Annotations = make(map[string]string) + cmd.Args = func(cmd *cobra.Command, args []string) error { + check := cobra.ExactArgs(1) + return check(cmd, args) + } + cmd.PreRunE = root.MustWorkspaceClient cmd.RunE = func(cmd *cobra.Command, args []string) (err error) { ctx := cmd.Context() @@ -184,6 +193,7 @@ func newDeleteDataVectorIndex() *cobra.Command { } else { return fmt.Errorf("please provide command input in JSON format by specifying the --json flag") } + deleteDataVectorIndexReq.Name = args[0] response, err := w.VectorSearchIndexes.DeleteDataVectorIndex(ctx, deleteDataVectorIndexReq) if err != nil { @@ -427,14 +437,22 @@ func newQueryIndex() *cobra.Command { cmd.Flags().StringVar(&queryIndexReq.QueryText, "query-text", queryIndexReq.QueryText, `Query text.`) // TODO: array: query_vector - cmd.Use = "query-index" + cmd.Use = "query-index INDEX_NAME" cmd.Short = `Query an index.` cmd.Long = `Query an index. - Query the specified vector index.` + Query the specified vector index. + + Arguments: + INDEX_NAME: Name of the vector index to query.` cmd.Annotations = make(map[string]string) + cmd.Args = func(cmd *cobra.Command, args []string) error { + check := cobra.ExactArgs(1) + return check(cmd, args) + } + cmd.PreRunE = root.MustWorkspaceClient cmd.RunE = func(cmd *cobra.Command, args []string) (err error) { ctx := cmd.Context() @@ -448,6 +466,7 @@ func newQueryIndex() *cobra.Command { } else { return fmt.Errorf("please provide command input in JSON format by specifying the --json flag") } + queryIndexReq.IndexName = args[0] response, err := w.VectorSearchIndexes.QueryIndex(ctx, queryIndexReq) if err != nil {