From 38c47657a02aa71c39430b88109a0953c1e770c4 Mon Sep 17 00:00:00 2001 From: "databricks-ci-ghec-1[bot]" <184311507+databricks-ci-ghec-1[bot]@users.noreply.github.com> Date: Tue, 20 Oct 2026 03:12:36 +0000 Subject: [PATCH] Release sdk-go --- .codegen/_last_sha | 2 +- aigateway/CHANGELOG.md | 2 + aigateway/internal/version.go | 2 +- aigateway/v1/model.go | 11 +- budgets/CHANGELOG.md | 2 + budgets/internal/version.go | 2 +- budgets/v1/model.go | 30 +- go.work | 1 + pipelines/CHANGELOG.md | 2 + pipelines/internal/version.go | 2 +- pipelines/v2/model.go | 4 +- workspacefiles/.package.json | 3 + workspacefiles/CHANGELOG.md | 3 + workspacefiles/README.md | 26 ++ workspacefiles/go.mod | 28 ++ workspacefiles/internal/version.go | 5 + workspacefiles/v1/client.go | 483 +++++++++++++++++++++++++++++ workspacefiles/v1/genhelper.go | 193 ++++++++++++ workspacefiles/v1/model.go | 208 +++++++++++++ workspacefiles/v1/wire.go | 260 ++++++++++++++++ 20 files changed, 1254 insertions(+), 15 deletions(-) create mode 100644 workspacefiles/.package.json create mode 100644 workspacefiles/CHANGELOG.md create mode 100644 workspacefiles/README.md create mode 100644 workspacefiles/go.mod create mode 100644 workspacefiles/internal/version.go create mode 100644 workspacefiles/v1/client.go create mode 100644 workspacefiles/v1/genhelper.go create mode 100644 workspacefiles/v1/model.go create mode 100644 workspacefiles/v1/wire.go diff --git a/.codegen/_last_sha b/.codegen/_last_sha index cc9f694d..5532150a 100644 --- a/.codegen/_last_sha +++ b/.codegen/_last_sha @@ -1 +1 @@ -5cd95ddabc415e86749fbabb65a0e621f7cef3d3 \ No newline at end of file +1ea8ad95f75e332e4f295424abb4fba79c5d239b \ No newline at end of file diff --git a/aigateway/CHANGELOG.md b/aigateway/CHANGELOG.md index c3b6cbb0..52eb407f 100644 --- a/aigateway/CHANGELOG.md +++ b/aigateway/CHANGELOG.md @@ -1,5 +1,7 @@ # Version changelog +## Release v0.10.0 (2026-10-20) + ## Release v0.9.0 (2026-10-14) ## Release v0.8.0 (2026-10-13) diff --git a/aigateway/internal/version.go b/aigateway/internal/version.go index a150823a..39395133 100644 --- a/aigateway/internal/version.go +++ b/aigateway/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-aigateway" -const Version = "0.9.0" +const Version = "0.10.0" diff --git a/aigateway/v1/model.go b/aigateway/v1/model.go index 274d01d2..4072fdb6 100644 --- a/aigateway/v1/model.go +++ b/aigateway/v1/model.go @@ -333,7 +333,7 @@ type ListMcpServicesRequest struct { // Parent schema to list within, in the form `schemas/{catalog}.{schema}`. // Required. Each `{...}` component is capped at 255 characters individually. Parent *string - // Maximum number of MCP services to return. Defaults to 100 when unset or 0; + // Maximum number of MCP services to return. Defaults to 200 when unset or 0; // the maximum is 200. Use `page_token` to retrieve additional pages. PageSize *int // Opaque pagination token from the previous response. @@ -359,7 +359,7 @@ type ListModelProviderServicesRequest struct { // Parent schema to list within, in the form `schemas/{catalog}.{schema}`. // Required. Each `{...}` component is capped at 255 characters individually. Parent *string - // Maximum number of provider services to return. Defaults to 100 when unset or + // Maximum number of provider services to return. Defaults to 200 when unset or // 0; the maximum is 200. Use `page_token` to retrieve additional pages. PageSize *int // Opaque pagination token from the previous response. @@ -385,7 +385,7 @@ type ListModelServicesRequest struct { // Parent schema to list within, in the form `schemas/{catalog}.{schema}`. // Required. Each `{...}` component is capped at 255 characters individually. Parent *string - // Maximum number of model services to return. Defaults to 100 when unset or 0; + // Maximum number of model services to return. Defaults to 200 when unset or 0; // the maximum is 200. Use `page_token` to retrieve additional pages. PageSize *int // Opaque pagination token from the previous response. @@ -414,7 +414,7 @@ type ListSkillsRequest struct { // is schema-scoped, so `parent` must be set; an unset or empty `parent` is // rejected with INVALID_PARAMETER_VALUE. Parent *string - // Maximum number of skills to return. Defaults to 100 when unset or 0; the + // Maximum number of skills to return. Defaults to 200 when unset or 0; the // maximum is 200. Use `page_token` to retrieve additional pages. PageSize *int // Opaque pagination token from a previous request. @@ -1004,8 +1004,7 @@ type ModelProviderServiceConfig_CustomProviderApiKeyHeaderAuth struct { ApiKeyValue *ModelProviderServiceConfig_ProviderSecret `fieldmask:"api_key_value"` } -// Custom OpenAI-compatible provider configuration with bearer-token -// authentication.. +// Custom OpenAI-compatible provider configuration.. type ModelProviderServiceConfig_CustomProviderConfig struct { // Provider configuration mode. Exactly one variant may be set. (-- Wrapped in a // oneof so future non-direct modes can be added as additional variants without diff --git a/budgets/CHANGELOG.md b/budgets/CHANGELOG.md index 2fca2529..c48d9918 100644 --- a/budgets/CHANGELOG.md +++ b/budgets/CHANGELOG.md @@ -1,5 +1,7 @@ # Version changelog +## Release v0.4.0 (2026-10-20) + ## Release v0.3.0 (2026-10-13) ## Release v0.2.0 (2026-10-06) diff --git a/budgets/internal/version.go b/budgets/internal/version.go index b04d5f91..9f03153a 100644 --- a/budgets/internal/version.go +++ b/budgets/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-budgets" -const Version = "0.3.0" +const Version = "0.4.0" diff --git a/budgets/v1/model.go b/budgets/v1/model.go index d5f1b575..d73a345c 100644 --- a/budgets/v1/model.go +++ b/budgets/v1/model.go @@ -109,7 +109,15 @@ type BudgetConfiguration struct { // Update time of this budget configuration. UpdateTime *int64 // Alerts to configure when this budget is in a triggered state. Budgets must - // have exactly one alert configuration. + // have at least one alert configuration. A budget can have up to four shared + // alerts per time period, each with a unique `quantity_threshold`. Budgets with + // `resource_type` set to `BUDGET_RESOURCE_TYPE_UNITY_AI_GATEWAY` can also use + // per-user alerts, with optional `principal_overrides`. These budgets can have + // at most one per-user alert per time period, and can use shared alerts, a + // per-user alert, or both. The `BLOCK_USAGE` action is only supported on + // budgets with `resource_type` set to `BUDGET_RESOURCE_TYPE_UNITY_AI_GATEWAY`. + // At most one shared alert per time period can have a `BLOCK_USAGE` action, and + // it must be the shared alert with the highest threshold in that period. AlertConfigurations []AlertConfiguration // Configured filters for this budget. These are applied to your account's usage // to limit the scope of what is considered for this budget. Leave empty to @@ -151,7 +159,15 @@ type CreateBudgetConfigurationBudget struct { // account ID. AccountId *string // Alerts to configure when this budget is in a triggered state. Budgets must - // have exactly one alert configuration. + // have at least one alert configuration. A budget can have up to four shared + // alerts per time period, each with a unique `quantity_threshold`. Budgets with + // `resource_type` set to `BUDGET_RESOURCE_TYPE_UNITY_AI_GATEWAY` can also use + // per-user alerts, with optional `principal_overrides`. These budgets can have + // at most one per-user alert per time period, and can use shared alerts, a + // per-user alert, or both. The `BLOCK_USAGE` action is only supported on + // budgets with `resource_type` set to `BUDGET_RESOURCE_TYPE_UNITY_AI_GATEWAY`. + // At most one shared alert per time period can have a `BLOCK_USAGE` action, and + // it must be the shared alert with the highest threshold in that period. AlertConfigurations []CreateBudgetConfigurationBudgetAlertConfigurations // Configured filters for this budget. These are applied to your account's usage // to limit the scope of what is considered for this budget. Leave empty to @@ -260,7 +276,15 @@ type UpdateBudgetConfigurationBudget struct { // account ID. AccountId *string // Alerts to configure when this budget is in a triggered state. Budgets must - // have exactly one alert configuration. + // have at least one alert configuration. A budget can have up to four shared + // alerts per time period, each with a unique `quantity_threshold`. Budgets with + // `resource_type` set to `BUDGET_RESOURCE_TYPE_UNITY_AI_GATEWAY` can also use + // per-user alerts, with optional `principal_overrides`. These budgets can have + // at most one per-user alert per time period, and can use shared alerts, a + // per-user alert, or both. The `BLOCK_USAGE` action is only supported on + // budgets with `resource_type` set to `BUDGET_RESOURCE_TYPE_UNITY_AI_GATEWAY`. + // At most one shared alert per time period can have a `BLOCK_USAGE` action, and + // it must be the shared alert with the highest threshold in that period. AlertConfigurations []AlertConfiguration // Configured filters for this budget. These are applied to your account's usage // to limit the scope of what is considered for this budget. Leave empty to diff --git a/go.work b/go.work index 401ab2f1..4f5f9f56 100644 --- a/go.work +++ b/go.work @@ -93,5 +93,6 @@ use ( ./usagedashboards ./vectorsearch ./warehouses + ./workspacefiles ./workspaces ) diff --git a/pipelines/CHANGELOG.md b/pipelines/CHANGELOG.md index 42f7b216..79fa15d9 100644 --- a/pipelines/CHANGELOG.md +++ b/pipelines/CHANGELOG.md @@ -1,5 +1,7 @@ # Version changelog +## Release v0.7.0 (2026-10-20) + ## Release v0.6.0 (2026-10-19) ## Release v0.5.0 (2026-10-13) diff --git a/pipelines/internal/version.go b/pipelines/internal/version.go index 48ae2bf2..5c16ec9b 100644 --- a/pipelines/internal/version.go +++ b/pipelines/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-pipelines" -const Version = "0.6.0" +const Version = "0.7.0" diff --git a/pipelines/v2/model.go b/pipelines/v2/model.go index 8ae00e94..3667ee1c 100644 --- a/pipelines/v2/model.go +++ b/pipelines/v2/model.go @@ -1643,8 +1643,8 @@ type ListPipelinesRequest struct { // maximum value is 100. An error is returned if the value of max_results is // greater than 100. MaxResults *int - // A list of strings specifying the order of results. Supported order_by fields - // are id and name. The default is id asc. This field is optional. + // A list of strings specifying the order of results. The supported order_by + // field is id. The default is id asc. This field is optional. OrderBy []string // Select a subset of results based on the specified criteria. The supported // filters are: diff --git a/workspacefiles/.package.json b/workspacefiles/.package.json new file mode 100644 index 00000000..56f39094 --- /dev/null +++ b/workspacefiles/.package.json @@ -0,0 +1,3 @@ +{ + "package": "workspacefiles" +} diff --git a/workspacefiles/CHANGELOG.md b/workspacefiles/CHANGELOG.md new file mode 100644 index 00000000..2e32fe6f --- /dev/null +++ b/workspacefiles/CHANGELOG.md @@ -0,0 +1,3 @@ +# Version changelog + +## Release v0.1.0 (2026-10-20) diff --git a/workspacefiles/README.md b/workspacefiles/README.md new file mode 100644 index 00000000..6c5d7c96 --- /dev/null +++ b/workspacefiles/README.md @@ -0,0 +1,26 @@ +# github.com/databricks/sdk-go/workspacefiles + +> [!NOTE] +> +> ## Beta +> +> **This SDK is in Beta and is supported for production use cases.** Interfaces might still change slightly before GA (e.g. name standardization and minor ergonomic tweaks). We are keen to hear feedback from early adopters — please [file issues](https://github.com/databricks/sdk-go/issues), and we will address them. + +## Installation + +```bash +go get github.com/databricks/sdk-go/workspacefiles@latest +``` + +## Usage + +```go +import "github.com/databricks/sdk-go/workspacefiles/v1" + +client, err := workspacefiles.NewClient(ctx) +if err != nil { + return err +} +``` + +For a full getting-started guide, see the [root README](../README.md). diff --git a/workspacefiles/go.mod b/workspacefiles/go.mod new file mode 100644 index 00000000..677b0440 --- /dev/null +++ b/workspacefiles/go.mod @@ -0,0 +1,28 @@ +module github.com/databricks/sdk-go/workspacefiles + +go 1.26.0 + +replace github.com/databricks/sdk-go/auth => ../auth + +replace github.com/databricks/sdk-go/core => ../core + +replace github.com/databricks/sdk-go/options => ../options + +require ( + github.com/databricks/sdk-go/auth v0.2.0 + github.com/databricks/sdk-go/core v0.1.0 + github.com/databricks/sdk-go/options v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect +) diff --git a/workspacefiles/internal/version.go b/workspacefiles/internal/version.go new file mode 100644 index 00000000..f9843b55 --- /dev/null +++ b/workspacefiles/internal/version.go @@ -0,0 +1,5 @@ +package internal + +const ModuleName = "sdk-go-workspacefiles" + +const Version = "0.1.0" diff --git a/workspacefiles/v1/client.go b/workspacefiles/v1/client.go new file mode 100644 index 00000000..92d9b485 --- /dev/null +++ b/workspacefiles/v1/client.go @@ -0,0 +1,483 @@ +// Code generated by Databricks SDK Generator. DO NOT EDIT. + +package workspacefiles + +import ( + "bytes" + "context" + "encoding/json" + "log/slog" + "net/http" + "net/url" + "sync" + "time" + + "github.com/databricks/sdk-go/auth" + "github.com/databricks/sdk-go/core/clientinfo" + "github.com/databricks/sdk-go/options/call" + "github.com/databricks/sdk-go/options/client" + "github.com/databricks/sdk-go/options/internaloptions" + "github.com/databricks/sdk-go/workspacefiles/internal" +) + +type Client struct { + internalClient + + // extensions is a per-client store for hand-written mixins to attach + // lazily-built state. Keys should be unexported types private to the + // mixin, following the context.Value convention, to avoid collisions. + // The zero value is ready to use; it is safe for concurrent use. + extensions sync.Map +} + +type internalClient struct { + httpClient *http.Client + callTimeout *time.Duration + credentials auth.Credentials + logger *slog.Logger + userAgent func() (string, error) + host string + workspaceID string + accountID string +} + +func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { + cfg := internaloptions.ClientOptions{} + for _, opt := range opts { + if err := opt(&cfg); err != nil { + return nil, err + } + } + if err := cfg.Resolve(); err != nil { + return nil, err + } + userAgent := func() (string, error) { + info, err := clientinfo.Default().With( + internal.ModuleName, internal.Version, + "auth", cfg.Credentials.Name(), + ) + if err != nil { + return "", err + } + return info.String(), nil + } + + return &Client{ + internalClient: internalClient{ + httpClient: cfg.HTTPClient, + callTimeout: cfg.Timeout, + credentials: cfg.Credentials, + logger: cfg.Logger, + userAgent: userAgent, + host: cfg.Host, + workspaceID: cfg.WorkspaceID, + accountID: cfg.AccountID, + }, + }, nil +} + +// Deletes an object or a directory (and optionally recursively deletes all +// objects in the directory). * If `path` does not exist, this call returns an +// error `RESOURCE_DOES_NOT_EXIST`. * If `path` is a non-empty directory and +// `recursive` is set to `false`, this call returns an error +// `DIRECTORY_NOT_EMPTY`. +// +// Object deletion cannot be undone and deleting a directory recursively is not +// atomic. +func (c *internalClient) Delete(ctx context.Context, req DeleteRequest, opts ...call.Option) (*DeleteResponse, error) { + wireReq, err := deleteRequestToWire(&req) + if err != nil { + return nil, err + } + body, err := json.Marshal(wireReq) + if err != nil { + return nil, err + } + + headers := http.Header{} + headers.Set("Content-Type", "application/json") + if c.workspaceID != "" { + headers.Set("X-Databricks-Workspace-Id", c.workspaceID) + } + + baseURL, err := url.Parse(c.host) + if err != nil { + return nil, err + } + baseURL.Path = "/api/2.0/workspace/delete" + queryParams := url.Values{} + baseURL.RawQuery = queryParams.Encode() + urlStr := baseURL.String() + + var resp *DeleteResponse + + call := func(ctx context.Context) error { + httpReq, err := newHTTPRequest(ctx, httpRequestOptions{ + Method: "POST", + URL: urlStr, + Credentials: c.credentials, + UserAgent: c.userAgent, + Headers: headers, + Body: bytes.NewBuffer(body), + }) + if err != nil { + return err + } + + respBody, _, err := executeHTTPCall(httpCallOptions{ + req: httpReq, + client: c.httpClient, + logger: c.logger, + }) + if err != nil { + return err + } + _ = respBody + resp = &DeleteResponse{} + return nil + } + + if err := c.executeCall(ctx, call, opts); err != nil { + return nil, err + } + return resp, nil +} + +// Exports an object or the contents of an entire directory. If `path` does not +// exist, this call returns an error `RESOURCE_DOES_NOT_EXIST`. If the exported +// data would exceed size limit, this call returns `MAX_NOTEBOOK_SIZE_EXCEEDED`. +// Currently, this API does not support exporting a library. +func (c *internalClient) Export(ctx context.Context, req ExportRequest, opts ...call.Option) (*ExportResponse, error) { + wireReq, err := exportRequestToWire(&req) + if err != nil { + return nil, err + } + + headers := http.Header{} + headers.Set("Content-Type", "application/json") + if c.workspaceID != "" { + headers.Set("X-Databricks-Workspace-Id", c.workspaceID) + } + + baseURL, err := url.Parse(c.host) + if err != nil { + return nil, err + } + baseURL.Path = "/api/2.0/workspace/export" + queryParams := url.Values{} + if err := addQueryValue(queryParams, "path", wireReq.Path); err != nil { + return nil, err + } + if wireReq.Format != "" { + if err := addQueryValue(queryParams, "format", wireReq.Format); err != nil { + return nil, err + } + } + if err := addQueryValue(queryParams, "direct_download", wireReq.DirectDownload); err != nil { + return nil, err + } + baseURL.RawQuery = queryParams.Encode() + urlStr := baseURL.String() + + var resp *ExportResponse + + call := func(ctx context.Context) error { + httpReq, err := newHTTPRequest(ctx, httpRequestOptions{ + Method: "GET", + URL: urlStr, + Credentials: c.credentials, + UserAgent: c.userAgent, + Headers: headers, + }) + if err != nil { + return err + } + + respBody, _, err := executeHTTPCall(httpCallOptions{ + req: httpReq, + client: c.httpClient, + logger: c.logger, + }) + if err != nil { + return err + } + var wireResp exportResponseWire + if err := json.Unmarshal(respBody, &wireResp); err != nil { + return err + } + resp, err = exportResponseFromWire(&wireResp) + if err != nil { + return err + } + return nil + } + + if err := c.executeCall(ctx, call, opts); err != nil { + return nil, err + } + return resp, nil +} + +// Gets the status of an object or a directory. If `path` does not exist, this +// call returns an error `RESOURCE_DOES_NOT_EXIST`. +func (c *internalClient) GetStatus(ctx context.Context, req GetStatusRequest, opts ...call.Option) (*ObjectInfo, error) { + wireReq, err := getStatusRequestToWire(&req) + if err != nil { + return nil, err + } + + headers := http.Header{} + headers.Set("Content-Type", "application/json") + if c.workspaceID != "" { + headers.Set("X-Databricks-Workspace-Id", c.workspaceID) + } + + baseURL, err := url.Parse(c.host) + if err != nil { + return nil, err + } + baseURL.Path = "/api/2.0/workspace/get-status" + queryParams := url.Values{} + if err := addQueryValue(queryParams, "path", wireReq.Path); err != nil { + return nil, err + } + baseURL.RawQuery = queryParams.Encode() + urlStr := baseURL.String() + + var resp *ObjectInfo + + call := func(ctx context.Context) error { + httpReq, err := newHTTPRequest(ctx, httpRequestOptions{ + Method: "GET", + URL: urlStr, + Credentials: c.credentials, + UserAgent: c.userAgent, + Headers: headers, + }) + if err != nil { + return err + } + + respBody, _, err := executeHTTPCall(httpCallOptions{ + req: httpReq, + client: c.httpClient, + logger: c.logger, + }) + if err != nil { + return err + } + var wireResp objectInfoWire + if err := json.Unmarshal(respBody, &wireResp); err != nil { + return err + } + resp, err = objectInfoFromWire(&wireResp) + if err != nil { + return err + } + return nil + } + + if err := c.executeCall(ctx, call, opts); err != nil { + return nil, err + } + return resp, nil +} + +// Imports a workspace object (for example, a notebook or file) or the contents +// of an entire directory. If `path` already exists and `overwrite` is set to +// `false`, this call returns an error `RESOURCE_ALREADY_EXISTS`. To import a +// directory, you can use either the `DBC` format or the `SOURCE` format with +// the `language` field unset. To import a single file as `SOURCE`, you must set +// the `language` field. Zip files within directories are not supported. +func (c *internalClient) Import(ctx context.Context, req ImportRequest, opts ...call.Option) (*ImportResponse, error) { + wireReq, err := importRequestToWire(&req) + if err != nil { + return nil, err + } + body, err := json.Marshal(wireReq) + if err != nil { + return nil, err + } + + headers := http.Header{} + headers.Set("Content-Type", "application/json") + if c.workspaceID != "" { + headers.Set("X-Databricks-Workspace-Id", c.workspaceID) + } + + baseURL, err := url.Parse(c.host) + if err != nil { + return nil, err + } + baseURL.Path = "/api/2.0/workspace/import" + queryParams := url.Values{} + baseURL.RawQuery = queryParams.Encode() + urlStr := baseURL.String() + + var resp *ImportResponse + + call := func(ctx context.Context) error { + httpReq, err := newHTTPRequest(ctx, httpRequestOptions{ + Method: "POST", + URL: urlStr, + Credentials: c.credentials, + UserAgent: c.userAgent, + Headers: headers, + Body: bytes.NewBuffer(body), + }) + if err != nil { + return err + } + + respBody, _, err := executeHTTPCall(httpCallOptions{ + req: httpReq, + client: c.httpClient, + logger: c.logger, + }) + if err != nil { + return err + } + _ = respBody + resp = &ImportResponse{} + return nil + } + + if err := c.executeCall(ctx, call, opts); err != nil { + return nil, err + } + return resp, nil +} + +// Lists the contents of a directory, or the object if it is not a directory. If +// the input path does not exist, this call returns an error +// `RESOURCE_DOES_NOT_EXIST`. +func (c *internalClient) List(ctx context.Context, req ListRequest, opts ...call.Option) (*ListResponse, error) { + wireReq, err := listRequestToWire(&req) + if err != nil { + return nil, err + } + + headers := http.Header{} + headers.Set("Content-Type", "application/json") + if c.workspaceID != "" { + headers.Set("X-Databricks-Workspace-Id", c.workspaceID) + } + + baseURL, err := url.Parse(c.host) + if err != nil { + return nil, err + } + baseURL.Path = "/api/2.0/workspace/list" + queryParams := url.Values{} + if err := addQueryValue(queryParams, "path", wireReq.Path); err != nil { + return nil, err + } + if err := addQueryValue(queryParams, "notebooks_modified_after", wireReq.NotebooksModifiedAfter); err != nil { + return nil, err + } + baseURL.RawQuery = queryParams.Encode() + urlStr := baseURL.String() + + var resp *ListResponse + + call := func(ctx context.Context) error { + httpReq, err := newHTTPRequest(ctx, httpRequestOptions{ + Method: "GET", + URL: urlStr, + Credentials: c.credentials, + UserAgent: c.userAgent, + Headers: headers, + }) + if err != nil { + return err + } + + respBody, _, err := executeHTTPCall(httpCallOptions{ + req: httpReq, + client: c.httpClient, + logger: c.logger, + }) + if err != nil { + return err + } + var wireResp listResponseWire + if err := json.Unmarshal(respBody, &wireResp); err != nil { + return err + } + resp, err = listResponseFromWire(&wireResp) + if err != nil { + return err + } + return nil + } + + if err := c.executeCall(ctx, call, opts); err != nil { + return nil, err + } + return resp, nil +} + +// Creates the specified directory (and necessary parent directories if they do +// not exist). If there is an object (not a directory) at any prefix of the +// input path, this call returns an error `RESOURCE_ALREADY_EXISTS`. +// +// Note that if this operation fails it may have succeeded in creating some of +// the necessary parent directories. +func (c *internalClient) Mkdirs(ctx context.Context, req MkdirsRequest, opts ...call.Option) (*MkdirsResponse, error) { + wireReq, err := mkdirsRequestToWire(&req) + if err != nil { + return nil, err + } + body, err := json.Marshal(wireReq) + if err != nil { + return nil, err + } + + headers := http.Header{} + headers.Set("Content-Type", "application/json") + if c.workspaceID != "" { + headers.Set("X-Databricks-Workspace-Id", c.workspaceID) + } + + baseURL, err := url.Parse(c.host) + if err != nil { + return nil, err + } + baseURL.Path = "/api/2.0/workspace/mkdirs" + queryParams := url.Values{} + baseURL.RawQuery = queryParams.Encode() + urlStr := baseURL.String() + + var resp *MkdirsResponse + + call := func(ctx context.Context) error { + httpReq, err := newHTTPRequest(ctx, httpRequestOptions{ + Method: "POST", + URL: urlStr, + Credentials: c.credentials, + UserAgent: c.userAgent, + Headers: headers, + Body: bytes.NewBuffer(body), + }) + if err != nil { + return err + } + + respBody, _, err := executeHTTPCall(httpCallOptions{ + req: httpReq, + client: c.httpClient, + logger: c.logger, + }) + if err != nil { + return err + } + _ = respBody + resp = &MkdirsResponse{} + return nil + } + + if err := c.executeCall(ctx, call, opts); err != nil { + return nil, err + } + return resp, nil +} diff --git a/workspacefiles/v1/genhelper.go b/workspacefiles/v1/genhelper.go new file mode 100644 index 00000000..4491cd10 --- /dev/null +++ b/workspacefiles/v1/genhelper.go @@ -0,0 +1,193 @@ +// Code generated by Databricks SDK Generator. DO NOT EDIT. + +package workspacefiles + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "log/slog" + "net/http" + "net/url" + "time" + + "github.com/databricks/sdk-go/auth" + "github.com/databricks/sdk-go/core/apierr" + "github.com/databricks/sdk-go/core/ops" + "github.com/databricks/sdk-go/options/call" + "github.com/databricks/sdk-go/options/internaloptions" +) + +type httpCallOptions struct { + req *http.Request + client *http.Client + logger *slog.Logger +} + +type httpRequestOptions struct { + Method string + URL string + Credentials auth.Credentials + UserAgent func() (string, error) + Headers http.Header + Body io.Reader +} + +func newHTTPRequest(ctx context.Context, opts httpRequestOptions) (*http.Request, error) { + req, err := http.NewRequestWithContext(ctx, opts.Method, opts.URL, opts.Body) + if err != nil { + closeBody(opts.Body) + return nil, err + } + + req.Header = opts.Headers.Clone() + if opts.Credentials != nil { + headers, err := opts.Credentials.AuthHeaders(ctx) + if err != nil { + closeBody(opts.Body) + return nil, err + } + for _, h := range headers { + req.Header.Add(h.Key, h.Value) + } + } + if opts.UserAgent != nil { + userAgent, err := opts.UserAgent() + if err != nil { + closeBody(opts.Body) + return nil, err + } + if userAgent != "" { + req.Header.Set("User-Agent", userAgent) + } + } + + return req, nil +} + +func closeBody(body io.Reader) { + if body == nil { + return + } + if rc, ok := body.(io.ReadCloser); ok { + _ = rc.Close() + } +} + +// lazyRequest implements slog.LogValuer for lazy evaluation of request +// logging. +type lazyRequest struct{ req *http.Request } + +func (r lazyRequest) LogValue() slog.Value { + return slog.GroupValue( + slog.String("method", r.req.Method), + slog.String("url", r.req.URL.String()), + ) +} + +// lazyResponse implements slog.LogValuer for lazy evaluation of response +// logging. +type lazyResponse struct { + resp *http.Response + body []byte +} + +func (r lazyResponse) LogValue() slog.Value { + return slog.GroupValue( + slog.Int("status", r.resp.StatusCode), + slog.String("body", string(r.body)), + ) +} + +// executeHTTPCall executes an HTTP call and returns the response body and +// headers, or an error. The headers are returned so callers can populate +// header-mapped response fields alongside the JSON body. This function takes +// care of logging the request and response. +func executeHTTPCall(opts httpCallOptions) ([]byte, http.Header, error) { + opts.logger.Debug("HTTP request", "request", lazyRequest{opts.req}) + resp, err := opts.client.Do(opts.req) + if err != nil { + return nil, nil, err + } + defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + if err != nil { + opts.logger.Debug("HTTP response", "response", lazyResponse{resp, nil}) + return nil, nil, err + } + opts.logger.Debug("HTTP response", "response", lazyResponse{resp, body}) + if err := apierr.FromHTTPError(resp.StatusCode, resp.Header, body); err != nil { + return nil, nil, err + } + return body, resp.Header, nil +} + +func (c *internalClient) resolveCallOptions( + opts []call.Option, + timeout time.Duration, +) (internaloptions.CallOptions, error) { + cfg := internaloptions.CallOptions{Timeout: timeout} + if c.callTimeout != nil { + cfg.Timeout = *c.callTimeout + } + for _, opt := range opts { + if err := opt(&cfg); err != nil { + return internaloptions.CallOptions{}, err + } + } + return cfg, nil +} + +func (c *internalClient) executeCall( + ctx context.Context, + op func(context.Context) error, + opts []call.Option, +) error { + cfg, err := c.resolveCallOptions(opts, 5*time.Minute) + if err != nil { + return err + } + return executeResolvedCall(ctx, op, cfg) +} + +func executeResolvedCall(ctx context.Context, op func(context.Context) error, cfg internaloptions.CallOptions) error { + return ops.Execute(ctx, op, + ops.WithRetrier(cfg.Retrier), + ops.WithLimiter(cfg.RateLimiter), + ops.WithTimeout(cfg.Timeout), + ) +} + +func addQueryValue(params url.Values, key string, value any) error { + data, err := json.Marshal(value) + if err != nil { + return err + } + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.UseNumber() + var decoded any + if err := decoder.Decode(&decoded); err != nil { + return err + } + flattenQueryValue(params, key, decoded) + return nil +} + +func flattenQueryValue(params url.Values, key string, value any) { + switch value := value.(type) { + case nil: + // JSON null represents an absent query value. + case map[string]any: + for childKey, child := range value { + flattenQueryValue(params, key+"."+childKey, child) + } + case []any: + for _, item := range value { + params.Add(key, fmt.Sprintf("%v", item)) + } + default: + params.Add(key, fmt.Sprintf("%v", value)) + } +} diff --git a/workspacefiles/v1/model.go b/workspacefiles/v1/model.go new file mode 100644 index 00000000..4ee814dd --- /dev/null +++ b/workspacefiles/v1/model.go @@ -0,0 +1,208 @@ +// Code generated by Databricks SDK Generator. DO NOT EDIT. + +package workspacefiles + +// The format for workspace import and export. +type ExportFormat string + +const ( + ExportFormat_Unspecified ExportFormat = "" + // The notebook will be imported/exported as source code. + ExportFormat_Source ExportFormat = "SOURCE" + // The notebook will be imported/exported as an HTML file. + ExportFormat_Html ExportFormat = "HTML" + // The notebook will be imported/exported as a Jupyter/IPython Notebook file. + ExportFormat_Jupyter ExportFormat = "JUPYTER" + // The notebook will be imported/exported as Databricks archive format. + ExportFormat_Dbc ExportFormat = "DBC" + // The notebook will be imported/exported as a R Markdown document. + ExportFormat_RMarkdown ExportFormat = "R_MARKDOWN" + // We will inspect the content of the payload to determine the type + ExportFormat_Auto ExportFormat = "AUTO" + // This is introduced to unblock a DR use case importing .zip file as is. If you + // import .zip file with AUTO format, it will be imported as a folder. In + // workspace 3.0 folder import will be supported via a different API. + ExportFormat_Raw ExportFormat = "RAW" +) + +// The language of notebook. +type Language string + +const ( + Language_Unspecified Language = "" + // Scala notebook. + Language_Scala Language = "SCALA" + // Python notebook. + Language_Python Language = "PYTHON" + // SQL notebook. + Language_Sql Language = "SQL" + // R notebook. + Language_R Language = "R" +) + +// The type of the object in workspace. +type ObjectType string + +const ( + ObjectType_Unspecified ObjectType = "" + ObjectType_Notebook ObjectType = "NOTEBOOK" + ObjectType_Directory ObjectType = "DIRECTORY" + ObjectType_Library ObjectType = "LIBRARY" + ObjectType_File ObjectType = "FILE" + ObjectType_Repo ObjectType = "REPO" + // Lakeview Dashboard. Using this since DBSQL dashboards will be deprecated soon + // and are planning on using the dbsql_dashboard prefix in permissions APIs + ObjectType_Dashboard ObjectType = "DASHBOARD" +) + +type DeleteRequest struct { + // The absolute path of the notebook or directory. + Path *string + // The flag that specifies whether to delete the object recursively. It is + // `false` by default. Please note this deleting directory is not atomic. If it + // fails in the middle, some of objects under this directory may be deleted and + // cannot be undone. + Recursive *bool +} + +type DeleteResponse struct { +} + +// Additional metadata about a directory.. +type DirectoryInfo struct { + // Whether the directory is a Git folder, whose contents are version-controlled + // by a remote Git repository. How a Git folder is represented depends on + // whether it has Git CLI access: + // + // - A Git folder with Git CLI access has an object type of ``DIRECTORY``, with + // this field set to ``true``. - A standard Git folder, which does not have Git + // CLI access, has an object type of ``REPO`` and does not include this field. - + // A directory that is not Git-backed has this field set to ``false``. + // + // Use this field together with ``object_type`` to identify every Git folder in + // a workspace. + IsGitFolder *bool +} + +type ExportRequest struct { + // The absolute path of the object or directory. Exporting a directory is only + // supported for the `DBC`, `SOURCE`, and `AUTO` format. + Path *string + // This specifies the format of the exported file. By default, this is `SOURCE`. + // + // The value is case sensitive. + // + // - `SOURCE`: The notebook is exported as source code. Directory exports will + // not include non-notebook entries. - `HTML`: The notebook is exported as an + // HTML file. - `JUPYTER`: The notebook is exported as a Jupyter/IPython + // Notebook file. - `DBC`: The notebook is exported in archive + // format. Directory exports will not include non-notebook entries. - + // `R_MARKDOWN`: The notebook is exported to R Markdown format. - `AUTO`: The + // object or directory is exported depending on the objects type. Directory + // exports will include notebooks and workspace files. + Format ExportFormat + // Flag to enable direct download. If it is `true`, the response is the exported + // file itself. Otherwise, by default, the response contains content in the form + // of a base64 encoded string. + DirectDownload *bool +} + +// The request field `direct_download` determines whether a JSON response or +// binary contents are returned by this endpoint.. +type ExportResponse struct { + // The base64-encoded content. If the limit (10MB) is exceeded, exception with + // error code **MAX_NOTEBOOK_SIZE_EXCEEDED** is thrown. + Content []byte + // The file type of the exported file. + FileType *string +} + +type GetStatusRequest struct { + // The absolute path of the notebook or directory. + Path *string +} + +type ImportRequest struct { + // The absolute path of the object or directory. Importing a directory is only + // supported for the `DBC` and `SOURCE` formats. + Path *string + // This specifies the format of the file to be imported. + // + // The value is case sensitive. + // + // - `AUTO`: The item is imported depending on an analysis of the item's + // extension and the header content provided in the request. If the item is + // imported as a notebook, then the item's extension is automatically removed. - + // `SOURCE`: The notebook or directory is imported as source code. - `HTML`: The + // notebook is imported as an HTML file. - `JUPYTER`: The notebook is imported + // as a Jupyter/IPython Notebook file. - `DBC`: The notebook is imported in + // archive format. Required for directories. - `R_MARKDOWN`: The + // notebook is imported from R Markdown format. + Format ExportFormat + // The language of the object. This value is set only if the object type is + // `NOTEBOOK`. + Language Language + // The base64-encoded content. This has a limit of 10 MB. If the limit (10MB) is + // exceeded, exception with error code **MAX_NOTEBOOK_SIZE_EXCEEDED** is thrown. + // This parameter might be absent, and instead a posted file is used. + Content []byte + // The flag that specifies whether to overwrite existing object. It is `false` + // by default. For `DBC` format, `overwrite` is not supported since it may + // contain a directory. + Overwrite *bool +} + +type ImportResponse struct { +} + +type ListRequest struct { + // The absolute path of the notebook or directory. + Path *string + // UTC timestamp in milliseconds + NotebooksModifiedAfter *int64 +} + +type ListResponse struct { + // List of objects. + Objects []ObjectInfo +} + +type MkdirsRequest struct { + // The absolute path of the directory. If the parent directories do not exist, + // it will also create them. If the directory already exists, this command will + // do nothing and succeed. + Path *string +} + +type MkdirsResponse struct { +} + +// The information of the object in workspace. It will be returned by “list“ +// and “get-status“.. +type ObjectInfo struct { + // The type of the object in workspace. + // + // - `NOTEBOOK`: document that contains runnable code, visualizations, and + // explanatory text. - `DIRECTORY`: directory - `LIBRARY`: library - `FILE`: + // file - `REPO`: repository - `DASHBOARD`: Lakeview dashboard + ObjectType ObjectType + // The absolute path of the object. + Path *string + // The language of the object. This value is set only if the object type is + // ``NOTEBOOK``. For Jupyter (.ipynb) notebooks, this is always ``PYTHON``. + Language Language + // Only applicable to files. The creation UTC timestamp. + CreatedAt *int64 + // Only applicable to files, the last modified UTC timestamp. + ModifiedAt *int64 + // Unique identifier for the object. + ObjectId *int64 + // Only applicable to files. The file size in bytes can be returned. + Size *int64 + // A unique identifier for the object that is consistent across all Databricks + // APIs. + ResourceId *string + // Additional metadata about the directory. Only set for objects of type + // ``DIRECTORY``. + DirectoryInfo *DirectoryInfo +} diff --git a/workspacefiles/v1/wire.go b/workspacefiles/v1/wire.go new file mode 100644 index 00000000..d8922a9b --- /dev/null +++ b/workspacefiles/v1/wire.go @@ -0,0 +1,260 @@ +// Code generated by Databricks SDK Generator. DO NOT EDIT. + +package workspacefiles + +import ( + "bytes" + "encoding/json" + "fmt" + "strconv" +) + +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + +type deleteRequestWire struct { + Path *string `json:"path,omitempty"` + Recursive *bool `json:"recursive,omitempty"` +} + +func deleteRequestToWire(v *DeleteRequest) (*deleteRequestWire, error) { + if v == nil { + return nil, nil + } + return &deleteRequestWire{ + Path: v.Path, + Recursive: v.Recursive, + }, nil +} + +type directoryInfoWire struct { + IsGitFolder *bool `json:"is_git_folder,omitempty"` +} + +func directoryInfoFromWire(w *directoryInfoWire) (*DirectoryInfo, error) { + if w == nil { + return nil, nil + } + return &DirectoryInfo{ + IsGitFolder: w.IsGitFolder, + }, nil +} + +type exportRequestWire struct { + Path *string `json:"path,omitempty"` + Format ExportFormat `json:"format,omitempty"` + DirectDownload *bool `json:"direct_download,omitempty"` +} + +func exportRequestToWire(v *ExportRequest) (*exportRequestWire, error) { + if v == nil { + return nil, nil + } + return &exportRequestWire{ + Path: v.Path, + Format: v.Format, + DirectDownload: v.DirectDownload, + }, nil +} + +type exportResponseWire struct { + Content []byte `json:"content,omitempty"` + FileType *string `json:"file_type,omitempty"` +} + +func exportResponseFromWire(w *exportResponseWire) (*ExportResponse, error) { + if w == nil { + return nil, nil + } + return &ExportResponse{ + Content: w.Content, + FileType: w.FileType, + }, nil +} + +type getStatusRequestWire struct { + Path *string `json:"path,omitempty"` +} + +func getStatusRequestToWire(v *GetStatusRequest) (*getStatusRequestWire, error) { + if v == nil { + return nil, nil + } + return &getStatusRequestWire{ + Path: v.Path, + }, nil +} + +type importRequestWire struct { + Path *string `json:"path,omitempty"` + Format ExportFormat `json:"format,omitempty"` + Language Language `json:"language,omitempty"` + Content []byte `json:"content,omitempty"` + Overwrite *bool `json:"overwrite,omitempty"` +} + +func importRequestToWire(v *ImportRequest) (*importRequestWire, error) { + if v == nil { + return nil, nil + } + return &importRequestWire{ + Path: v.Path, + Format: v.Format, + Language: v.Language, + Content: v.Content, + Overwrite: v.Overwrite, + }, nil +} + +type listRequestWire struct { + Path *string `json:"path,omitempty"` + NotebooksModifiedAfter *wireInt64 `json:"notebooks_modified_after,omitempty"` +} + +func listRequestToWire(v *ListRequest) (*listRequestWire, error) { + if v == nil { + return nil, nil + } + notebooksModifiedAfterWireValue, err := int64ToWire(v.NotebooksModifiedAfter) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListRequest.NotebooksModifiedAfter", err) + } + return &listRequestWire{ + Path: v.Path, + NotebooksModifiedAfter: notebooksModifiedAfterWireValue, + }, nil +} + +type listResponseWire struct { + Objects []objectInfoWire `json:"objects,omitempty"` +} + +func listResponseFromWire(w *listResponseWire) (*ListResponse, error) { + if w == nil { + return nil, nil + } + objectsPublicValue, err := convertSlice(w.Objects, objectInfoFromWire) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListResponse.Objects", err) + } + return &ListResponse{ + Objects: objectsPublicValue, + }, nil +} + +type mkdirsRequestWire struct { + Path *string `json:"path,omitempty"` +} + +func mkdirsRequestToWire(v *MkdirsRequest) (*mkdirsRequestWire, error) { + if v == nil { + return nil, nil + } + return &mkdirsRequestWire{ + Path: v.Path, + }, nil +} + +type objectInfoWire struct { + ObjectType ObjectType `json:"object_type,omitempty"` + Path *string `json:"path,omitempty"` + Language Language `json:"language,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` + ModifiedAt *wireInt64 `json:"modified_at,omitempty"` + ObjectId *wireInt64 `json:"object_id,omitempty"` + Size *wireInt64 `json:"size,omitempty"` + ResourceId *string `json:"resource_id,omitempty"` + DirectoryInfo *directoryInfoWire `json:"directory_info,omitempty"` +} + +func objectInfoFromWire(w *objectInfoWire) (*ObjectInfo, error) { + if w == nil { + return nil, nil + } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ObjectInfo.CreatedAt", err) + } + modifiedAtPublicValue, err := int64FromWire(w.ModifiedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ObjectInfo.ModifiedAt", err) + } + objectIdPublicValue, err := int64FromWire(w.ObjectId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ObjectInfo.ObjectId", err) + } + sizePublicValue, err := int64FromWire(w.Size) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ObjectInfo.Size", err) + } + directoryInfoPublicValue, err := directoryInfoFromWire(w.DirectoryInfo) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ObjectInfo.DirectoryInfo", err) + } + return &ObjectInfo{ + ObjectType: w.ObjectType, + Path: w.Path, + Language: w.Language, + CreatedAt: createdAtPublicValue, + ModifiedAt: modifiedAtPublicValue, + ObjectId: objectIdPublicValue, + Size: sizePublicValue, + ResourceId: w.ResourceId, + DirectoryInfo: directoryInfoPublicValue, + }, nil +} + +func convertSlice[T, W any](s []T, conv func(*T) (*W, error)) ([]W, error) { + if s == nil { + return nil, nil + } + out := make([]W, len(s)) + for i := range s { + converted, err := conv(&s[i]) + if err != nil { + return nil, fmt.Errorf("element %d: %w", i, err) + } + out[i] = *converted + } + return out, nil +}