Skip to content

Demonstrate migrating databricks_repo to the Go SDK (follow-up to #5877) - #5883

Draft
GrantIsEaton wants to merge 1 commit into
databricks:mainfrom
GrantIsEaton:feature/migrate-repo-to-go-sdk
Draft

Demonstrate migrating databricks_repo to the Go SDK (follow-up to #5877)#5883
GrantIsEaton wants to merge 1 commit into
databricks:mainfrom
GrantIsEaton:feature/migrate-repo-to-go-sdk

Conversation

@GrantIsEaton

@GrantIsEaton GrantIsEaton commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

What this is

A demonstration PR responding to review feedback on #5877, where @alexott suggested switching databricks_repo to the Go SDK structs:

ideally we should just switch to Go SDK structs here

we have a way of customizing aliases for Go SDK structs as well [...] but this may require wrapping the Go SDK struct into TF-bound struct

This branch does exactly that, using the Aliases() mechanism Alex pointed at. It's scoped purely to the migration — it does not include the git_credential_id field from #5877, so the diff is the migration and nothing else.

Approach

Rather than keeping a parallel, hand-maintained schema struct, the schema is generated directly from the Go SDK workspace.RepoInfo via a thin wrapper:

type repoInfo struct {
	workspace.RepoInfo
	common.Namespace
}

func (repoInfo) Aliases() map[string]map[string]string {
	return map[string]map[string]string{
		"repos.repoInfo": {
			"provider":       "git_provider",
			"head_commit_id": "commit_hash",
		},
	}
}

CustomizeSchema() re-applies the force-new/computed/validation attributes that the old tf: tags carried. CRUD then calls w.Repos.* with the SDK request structs (CreateRepoRequest, UpdateRepoRequest) and w.Workspace.MkdirsByPath for parent-directory creation.

Net: +178 / −301 across 5 files (removes the whole hand-rolled ReposAPI).

What changed

  • Removed ReposAPI, NewReposAPI, reposCreateRequest, ReposListResponse, and the raw-HTTP Create/Read/Update/Delete/List/ListAll methods.
  • Added the repoInfo wrapper + Aliases()/CustomizeSchema().
  • Updated unit tests, exporter tests, and the unified-host acceptance-test comment.

Challenges / things to know

  1. The alias mechanism resolves the main obstacle. Generating the schema from an SDK struct normally loses the TF attribute names (git_provider, commit_hash), because workspace.RepoInfo has no tf: alias tags. The ResourceProviderWithAlias interface (Aliases()) supplies those renames and — verified here — round-trips correctly through schema generation, StructToData, and DataToStruct. This is exactly what Alex referenced.

  2. It still requires a wrapper type + boilerplate. As Alex noted, you wrap the SDK struct in a TF-bound struct and re-declare per-field customizations (force_new/computed/validators) in CustomizeSchema(), since those no longer come from struct tags. It's mechanical, but it's real code, and it has to stay in sync with the SDK struct.

  3. Read returns a different SDK type. w.Repos.GetByRepoId returns *GetRepoResponse, not *RepoInfo (the schema struct). They're structurally identical, so Read copies field-by-field into repoInfo.

  4. SDK URL encoding differs, breaking every fixture. The SDK appends a ? query suffix to GET/DELETE URLs (e.g. /api/2.0/repos/123?). The old client did not. Every unit-test and exporter HTTP fixture stubbing a GET/DELETE by id had to be updated, or tests fail with "missing stub". Invisible until you run the tests.

  5. Second-order test breakage in the exporter. ReposInformation/ReposListResponse were used as fixture bodies in exporter/exporter_test.go; those moved to workspace.RepoInfo/workspace.ListReposResponse and the now-unused repos import was dropped. No production exporter code changed (it already lists repos via the SDK).

  6. Dropped provider-local list helpers. ReposAPI.List/ListAll + ReposListResponse were provider-only and used solely by unit tests; production listing already goes through the SDK iterator in the exporter. Those two unit tests were removed rather than rewritten.

  7. Acceptance-test intent drifted. internal/acceptance/unified_host_acc_test.go contrasted a raw-HTTP resource (repo) against a Go SDK resource (jobs) on a unified host. Post-migration that contrast no longer holds, so the comment was rewritten.

Risks of rolling this out

  • All databricks_repo users are affected. This rewrites the entire CRUD path, so the risk/reward differs sharply from a small additive field — it deserves its own review and real acceptance-test runs against a workspace.
  • CustomizeSchema() must exactly reproduce the current schema. A missed SetComputed()/SetForceNew() would silently change plan behavior. Unit tests cover the happy paths but not every diff scenario.
  • ForceSendFields semantics. The SDK structs use omitempty + ForceSendFields to distinguish unset from zero. Not needed here, but any future need to send an explicit zero would require handling it — something the map-based client sidestepped.

Recommendation

With the Aliases() approach this is cleaner than a parallel struct and is clearly the idiomatic direction — but it's still a wrapper + full CRUD rewrite touching all repo users, not a drop-in. Reasonable as a standalone follow-up; bundling it into #5877 would turn a small, low-risk feature into a full-path rewrite.

Tests

  • go build ./..., go vet ./... clean.
  • go test ./repos/... ./exporter/... pass.
  • Acceptance tests (internal/acceptance) not run here — they require a live workspace / unified host.

This pull request and its description were written by Isaac.

Rewire databricks_repo off the hand-rolled ReposAPI/reposCreateRequest HTTP
client onto the Go SDK workspace.Repos service and request/response structs.

Following review feedback, the schema is generated directly from the Go SDK
workspace.RepoInfo struct: the Terraform-specific attribute names (git_provider,
commit_hash) are supplied through an Aliases() map on a thin wrapper type rather
than a parallel hand-maintained ReposInformation struct.

- Remove ReposAPI, NewReposAPI, reposCreateRequest, ReposListResponse and the
  raw-HTTP Create/Read/Update/Delete/List/ListAll methods.
- Add repoInfo wrapper (embeds workspace.RepoInfo + common.Namespace) with
  Aliases()/CustomizeSchema() to reproduce the existing schema.
- CRUD now calls w.Repos.* with the SDK request structs and
  w.Workspace.MkdirsByPath for parent-directory creation.
- Update unit tests: SDK request/response fixtures, the trailing "?" the SDK
  appends to GET/DELETE URLs, and drop the List/ListAll tests (listing is the
  SDK's job and is covered by the exporter).
- Update exporter tests to use workspace.RepoInfo/ListReposResponse fixtures.
- Refresh the unified-host acceptance-test comment now that repo routes through
  the SDK routing-header path.

Co-authored-by: Isaac
@GrantIsEaton
GrantIsEaton force-pushed the feature/migrate-repo-to-go-sdk branch from 8a9cf47 to 6d3b03d Compare July 14, 2026 19:02
@github-actions

Copy link
Copy Markdown
Contributor

Unit tests

If this PR is from a fork, the tests check runs offline against a pre-warmed Go module cache because fork PRs cannot authenticate to the internal Go module proxy.

If this PR changes go.mod or go.sum, the tests check will fail until a maintainer warms the cache for it:

Actions -> Warm Go Cache -> Run workflow -> pr_number = 5883

Re-run the failed check once the cache warming completes.

Integration tests

Integration tests don't run automatically for external contributors; an authorized user can run them manually by following the instructions below:

Trigger:
go/deco-tests-run/terraform

Inputs:

  • PR number: 5883
  • Commit SHA: 6d3b03d448dceb2b570d2122e6ebdd831643382f

Checks will be approved automatically on success.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant