diff --git a/.nextchanges/cli/pipelines-public-api.md b/.nextchanges/cli/pipelines-public-api.md new file mode 100644 index 00000000000..d48928f4a91 --- /dev/null +++ b/.nextchanges/cli/pipelines-public-api.md @@ -0,0 +1 @@ +* Show table names and a hint for previewing more rows in `pipelines show`, and support pipeline IDs in `pipelines history`. ([#6871](https://github.com/databricks/cli/pull/6871)) diff --git a/acceptance/pipelines/history/basic/out.test.toml b/acceptance/pipelines/history/basic/out.test.toml new file mode 100644 index 00000000000..0938e678987 --- /dev/null +++ b/acceptance/pipelines/history/basic/out.test.toml @@ -0,0 +1,2 @@ +Cloud = false +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["direct"] diff --git a/acceptance/pipelines/history/basic/output.txt b/acceptance/pipelines/history/basic/output.txt new file mode 100644 index 00000000000..b6b5dc0b39e --- /dev/null +++ b/acceptance/pipelines/history/basic/output.txt @@ -0,0 +1,59 @@ + +=== default history by pipeline id + +>>> [CLI] pipelines history [UUID] +Updates Summary for pipeline [UUID]: +Update ID: update-3 + State: COMPLETED + Creation Time: [TIMESTAMP] + Full Refresh: false + Validate Only: false +Update ID: update-2 + State: FAILED + Creation Time: [TIMESTAMP] + Full Refresh: false + Validate Only: true +Update ID: update-1 + State: CANCELED + Creation Time: [TIMESTAMP] + Full Refresh: false + Validate Only: false + +=== json output + +>>> [CLI] pipelines history [UUID] --output json +{ + "Key": "[UUID]", + "Updates": [ + { + "creation_time": [NUMID], + "state": "COMPLETED", + "update_id": "update-3", + "validate_only": false + }, + { + "creation_time": [NUMID], + "state": "FAILED", + "update_id": "update-2", + "validate_only": true + }, + { + "creation_time": [NUMID], + "state": "CANCELED", + "update_id": "update-1", + "validate_only": false + } + ] +} + +=== wire request uses pipeline id + +>>> print_requests.py //api/2.0/pipelines/[UUID]/updates --get +{ + "method": "GET", + "path": "/api/2.0/pipelines/[UUID]/updates" +} +{ + "method": "GET", + "path": "/api/2.0/pipelines/[UUID]/updates" +} diff --git a/acceptance/pipelines/history/basic/script b/acceptance/pipelines/history/basic/script new file mode 100644 index 00000000000..42fb9e14eb3 --- /dev/null +++ b/acceptance/pipelines/history/basic/script @@ -0,0 +1,8 @@ +title "default history by pipeline id\n" +trace $CLI pipelines history 3fb8e5a1-0d2c-4a6b-9f1e-2c7d8e9f0a1b + +title "json output\n" +trace $CLI pipelines history 3fb8e5a1-0d2c-4a6b-9f1e-2c7d8e9f0a1b --output json + +title "wire request uses pipeline id\n" +trace print_requests.py //api/2.0/pipelines/3fb8e5a1-0d2c-4a6b-9f1e-2c7d8e9f0a1b/updates --get diff --git a/acceptance/pipelines/history/basic/test.toml b/acceptance/pipelines/history/basic/test.toml new file mode 100644 index 00000000000..3f23481ca91 --- /dev/null +++ b/acceptance/pipelines/history/basic/test.toml @@ -0,0 +1,16 @@ +Cloud = false + +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["direct"] +RecordRequests = true + +[[Server]] +Pattern = "GET /api/2.0/pipelines/{pipeline_id}/updates" +Response.Body = ''' +{ + "updates": [ + {"update_id": "update-3", "state": "COMPLETED", "creation_time": 1640995200000, "validate_only": false}, + {"update_id": "update-2", "state": "FAILED", "creation_time": 1640908800000, "validate_only": true}, + {"update_id": "update-1", "state": "CANCELED", "creation_time": 1640822400000, "validate_only": false} + ] +} +''' diff --git a/acceptance/pipelines/show/basic/output.txt b/acceptance/pipelines/show/basic/output.txt index 87fe70aeeee..bb981cb69c2 100644 --- a/acceptance/pipelines/show/basic/output.txt +++ b/acceptance/pipelines/show/basic/output.txt @@ -2,6 +2,7 @@ === table output >>> [CLI] pipelines show main.default.people +Table: main.default.people id name -- ----- 1 alice diff --git a/acceptance/pipelines/show/rendering/output.txt b/acceptance/pipelines/show/rendering/output.txt index 499332abbba..9f981acd458 100644 --- a/acceptance/pipelines/show/rendering/output.txt +++ b/acceptance/pipelines/show/rendering/output.txt @@ -2,6 +2,7 @@ === table output: long note truncated, ragged row blank cell >>> [CLI] pipelines show main.default.people +Table: main.default.people name id note ----- -- ---------------------------------------- alice 1 this is a very long note value that e... diff --git a/cmd/pipelines/history.go b/cmd/pipelines/history.go index 6c30d1e72bd..e0c49222402 100644 --- a/cmd/pipelines/history.go +++ b/cmd/pipelines/history.go @@ -2,21 +2,26 @@ package pipelines import ( "fmt" + "regexp" "github.com/databricks/cli/cmd/bundle/utils" "github.com/databricks/cli/cmd/root" + "github.com/databricks/cli/libs/cmdctx" "github.com/databricks/cli/libs/cmdgroup" "github.com/databricks/cli/libs/cmdio" + databricks "github.com/databricks/databricks-sdk-go" "github.com/databricks/databricks-sdk-go/service/pipelines" "github.com/spf13/cobra" ) +var pipelineIDRegex = regexp.MustCompile(`^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`) + func historyCommand() *cobra.Command { cmd := &cobra.Command{ - Use: "history [flags] [KEY]", + Use: "history [flags] [KEY|PIPELINE_ID]", Args: root.MaximumNArgs(1), Short: "Retrieve past runs for a pipeline", - Long: `Retrieve past runs for a pipeline identified by KEY, the unique name of the pipeline as defined in its YAML file.`, + Long: `Retrieve past runs for a pipeline identified by KEY, the unique name of the pipeline as defined in its YAML file, or by PIPELINE_ID, the unique identifier of the pipeline.`, } var startTimeStr string @@ -34,25 +39,36 @@ func historyCommand() *cobra.Command { wrappedCmd.AddFlagGroup(historyGroup) cmd.RunE = func(cmd *cobra.Command, args []string) error { - b, err := utils.ProcessBundle(cmd, utils.ProcessOptions{ - InitIDs: true, - }) - if err != nil { - return err - } - ctx := cmd.Context() + var key, pipelineId string + var w *databricks.WorkspaceClient + if len(args) == 1 && pipelineIDRegex.MatchString(args[0]) { + if err := root.MustWorkspaceClient(cmd, args); err != nil { + return err + } + pipelineId = args[0] + key = pipelineId + w = cmdctx.WorkspaceClient(cmd.Context()) + } else { + b, err := utils.ProcessBundle(cmd, utils.ProcessOptions{ + InitIDs: true, + }) + if err != nil { + return err + } + ctx := cmd.Context() - key, err := resolvePipelineArgument(ctx, b, args) - if err != nil { - return err - } + key, err = resolvePipelineArgument(ctx, b, args) + if err != nil { + return err + } - pipelineId, err := resolvePipelineIdFromKey(ctx, b, key) - if err != nil { - return err + pipelineId, err = resolvePipelineIdFromKey(ctx, b, key) + if err != nil { + return err + } + w = b.WorkspaceClient(ctx) } - - w := b.WorkspaceClient(ctx) + ctx := cmd.Context() startTimePtr, err := parseTimeToUnixMillis(startTimeStr) if err != nil { diff --git a/cmd/pipelines/show.go b/cmd/pipelines/show.go index 0e115e0508d..b19880d6896 100644 --- a/cmd/pipelines/show.go +++ b/cmd/pipelines/show.go @@ -64,7 +64,16 @@ schema.table (legacy Hive metastore).`, return err } - return render(ctx, cmd, result.Columns, result.Rows) + if root.OutputType(cmd) == flags.OutputText { + fmt.Fprintf(cmd.OutOrStdout(), "Table: %s\n", args[0]) + } + if err := render(ctx, cmd, result.Columns, result.Rows); err != nil { + return err + } + if root.OutputType(cmd) == flags.OutputText && !cmd.Flags().Changed("limit") && len(result.Rows) == limit { + fmt.Fprintln(cmd.OutOrStdout(), "Use --limit to preview more rows.") + } + return nil }, }