Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .nextchanges/cli/repos-git-cli-folders.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed `databricks repos get/update/delete` failing with `object at path "..." is not a repo` for Git-CLI-enabled folders, which the workspace API reports as directories rather than repos. Git CLI is a preview feature; as an alternative mitigation it can be turned off in the workspace admin previews settings.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think we need this in the changelog

Suggested change
Fixed `databricks repos get/update/delete` failing with `object at path "..." is not a repo` for Git-CLI-enabled folders, which the workspace API reports as directories rather than repos. Git CLI is a preview feature; as an alternative mitigation it can be turned off in the workspace admin previews settings.
Fixed `databricks repos get/update/delete` failing with `object at path "..." is not a repo` for Git-CLI-enabled folders, which the workspace API reports as directories rather than repos.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a given user who reads this may not know what git cli is is my main thing

14 changes: 0 additions & 14 deletions acceptance/workspace/repos/get_errors/out.requests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,3 @@
"path": "/Repos/me@databricks.com/doesnotexist"
}
}
{
"method": "POST",
"path": "/api/2.0/workspace/mkdirs",
"body": {
"path": "/not-a-repo"
}
}
{
"method": "GET",
"path": "/api/2.0/workspace/get-status",
"q": {
"path": "/not-a-repo"
}
}
3 changes: 0 additions & 3 deletions acceptance/workspace/repos/get_errors/output.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@

>>> [CLI] repos get /Repos/me@databricks.com/doesnotexist -o json
Error: failed to look up repo by path: Path (/Repos/me@databricks.com/doesnotexist) doesn't exist.

>>> [CLI] repos get /not-a-repo -o json
Error: object at path "/not-a-repo" is not a repo
3 changes: 0 additions & 3 deletions acceptance/workspace/repos/get_errors/script
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
musterr trace $CLI repos get /Repos/me@databricks.com/doesnotexist -o json

$CLI workspace mkdirs /not-a-repo
musterr trace $CLI repos get /not-a-repo -o json
49 changes: 49 additions & 0 deletions acceptance/workspace/repos/git_cli_folder/out.requests.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"method": "GET",
"path": "/.well-known/databricks-config"
}
Comment on lines +1 to +4

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this request?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed it's not needed for the test — nothing here asserts on it, and it's unrelated to the repos behavior under test. But it can't be excluded today.

It's the SDK's host-metadata discovery during config init, so it fires before any command logic runs (the testserver registers a default handler for it at libs/testserver/server.go:314 precisely because otherwise any SDK client against the test server fails with "No handler for URL"). More to the point, request recording is unconditional: recordRequestsCallback in acceptance/internal/prepare_server.go:165 appends every request that hits the server to out.requests.txt, and there's no per-endpoint filter anywhere in that path. The only knob is the RecordRequests boolean in test.toml, which is all-or-nothing for the whole test.

So the choices are keep it, turn off RecordRequests for this test (which loses the request assertions that are the point of the test — proving get-statusrepos/{id} still resolves correctly for Git CLI folders), or add filtering to the shared harness. All five existing acceptance/workspace/repos/* snapshots carry the same line, as do ~57 others across the tree, so this file matches the established pattern.

If you'd like the harness to skip discovery/boilerplate endpoints from recordings, that seems worth doing on its own — it'd clean up all ~62 snapshots at once, and the change would be localized to recordRequestsCallback plus a test.toml option. Happy to file or take that separately if you want it; just felt out of scope to bundle into this bugfix.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

feel free to use print_requests.py in the script

{
"method": "POST",
"path": "/api/2.0/repos",
"body": {
"path": "/Workspace/Users/me@databricks.com/test-repo",
"provider": "gitHub",
"url": "https://github.com/databricks/databricks-empty-ide-project.git"
}
}
{
"method": "GET",
"path": "/api/2.0/workspace/get-status",
"q": {
"path": "/Workspace/Users/me@databricks.com/test-repo"
}
}
{
"method": "GET",
"path": "/api/2.0/repos/[NUMID]"
}
{
"method": "GET",
"path": "/api/2.0/workspace/get-status",
"q": {
"path": "/Workspace/Users/me@databricks.com/test-repo"
}
}
{
"method": "PATCH",
"path": "/api/2.0/repos/[NUMID]",
"body": {
"branch": "update-by-path"
}
}
{
"method": "GET",
"path": "/api/2.0/workspace/get-status",
"q": {
"path": "/Workspace/Users/me@databricks.com/test-repo"
}
}
{
"method": "DELETE",
"path": "/api/2.0/repos/[NUMID]"
}
3 changes: 3 additions & 0 deletions acceptance/workspace/repos/git_cli_folder/out.test.toml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions acceptance/workspace/repos/git_cli_folder/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@

>>> [CLI] repos create https://github.com/databricks/databricks-empty-ide-project.git gitHub --path /Workspace/Users/me@databricks.com/test-repo
[NUMID]

=== Get by path resolves a Git CLI folder
>>> [CLI] repos get /Workspace/Users/me@databricks.com/test-repo -o json
{
"branch": "main",
"id": [NUMID],
"path": "/Workspace/Users/me@databricks.com/test-repo",
"provider": "gitHub",
"url": "https://github.com/databricks/databricks-empty-ide-project.git"
}

=== Update by path resolves a Git CLI folder
>>> [CLI] repos update /Workspace/Users/me@databricks.com/test-repo --branch update-by-path

=== Delete by path resolves a Git CLI folder
>>> [CLI] repos delete /Workspace/Users/me@databricks.com/test-repo
16 changes: 16 additions & 0 deletions acceptance/workspace/repos/git_cli_folder/script
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
url=https://github.com/databricks/databricks-empty-ide-project.git
provider=gitHub
# A Git-CLI-enabled folder lives outside /Repos and get-status reports it as a
# DIRECTORY, not a REPO. Path-based commands must still resolve it to a repo ID.
path=/Workspace/Users/me@databricks.com/test-repo

trace $CLI repos create $url $provider --path $path | jq .id -r

title "Get by path resolves a Git CLI folder"
trace $CLI repos get $path -o json

title "Update by path resolves a Git CLI folder"
trace $CLI repos update $path --branch update-by-path

title "Delete by path resolves a Git CLI folder"
trace $CLI repos delete $path
7 changes: 3 additions & 4 deletions cmd/workspace/repos/overrides.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,14 +166,13 @@ func repoArgumentToRepoID(ctx context.Context, w *databricks.WorkspaceClient, ar
return id, nil
}

// If the argument cannot be parsed as a repo ID, try to look it up by name.
// Look up the path via get-status. We don't gate on the object type: Git-CLI
// folders report DIRECTORY rather than REPO, and the repos API is the
// authority on whether the ID resolves to a repo.
oi, err := w.Workspace.GetStatusByPath(ctx, arg)
if err != nil {
return 0, fmt.Errorf("failed to look up repo by path: %w", err)
}
if oi.ObjectType != workspace.ObjectTypeRepo {
return 0, fmt.Errorf("object at path %q is not a repo", arg)
}
return oi.ObjectId, nil
}

Expand Down
9 changes: 8 additions & 1 deletion libs/testserver/fake_workspace.go
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,14 @@ func (s *FakeWorkspace) WorkspaceGetStatus(requestPath string) Response {
} else if entry, ok := s.files[cleaned]; ok {
info = entry.Info
} else if repoId, ok := s.repoIdByPath[cleaned]; ok {
info = workspace.ObjectInfo{ObjectType: "REPO", Path: cleaned, ObjectId: repoId}
// Control-plane repos (under /Repos) report the REPO object type, while
// Git-CLI-enabled folders elsewhere are materialized as plain DIRECTORY
// nodes. Both resolve to a valid repo ID via the repos API.
Comment on lines +421 to +423

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why determine the object type based on path? Not a big deal really I guess because but maybe a little misleading

@GrantIsEaton GrantIsEaton Aug 4, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a recommendation for how else is best to distinguish between CP or DP in the fake? (i need to test both behaviors from the fake). The path is my only input parameter.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems fine for a testserver as it mimics the backend

objectType := workspace.ObjectTypeRepo
if !strings.HasPrefix(cleaned, "/Repos/") {
objectType = workspace.ObjectTypeDirectory
}
Comment on lines +421 to +427

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a weird fake.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i wasnt entirely sure how else to fake a CP git folder vs DP so i told it just to fake the CP git folder in /Repos/ paths.

info = workspace.ObjectInfo{ObjectType: objectType, Path: cleaned, ObjectId: repoId}
} else {
// Match the real Workspace API wording, which echoes the requested path.
return Response{
Expand Down
Loading