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
2 changes: 1 addition & 1 deletion NEXT_CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
* Increase the SSH server startup timeout from 10 to 45 minutes when a GPU accelerator is requested via `databricks ssh connect --accelerator` ([#5569](https://github.com/databricks/cli/pull/5569)).
* Fix authentication falling back to the default profile in `.databrickscfg` when a host is already configured via the environment (e.g. `DATABRICKS_HOST` with `DATABRICKS_TOKEN`) ([#5616](https://github.com/databricks/cli/pull/5616)).
* ssh: fix opening remote environment in Cursor, which previously hung on default-extension install and never opened the editor ([#5619](https://github.com/databricks/cli/pull/5619)).

* `databricks labs list` now only shows projects that can be installed ([#5560](https://github.com/databricks/cli/pull/5560)).

### Bundles
* Remove API enum values and types that are still in development from the `databricks-bundles` Python package; these were never accepted by the backend ([#5484](https://github.com/databricks/cli/pull/5484)).
Expand Down
43 changes: 34 additions & 9 deletions cmd/labs/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,23 @@ package labs

import (
"context"
"slices"

"github.com/databricks/cli/cmd/labs/github"
"github.com/databricks/cli/cmd/labs/project"
"github.com/databricks/cli/libs/cmdio"
"github.com/spf13/cobra"
)

const (
labsOrg = "databrickslabs"

// installableTopic is the GitHub repository topic that labs maintainers add to
// projects installable via `databricks labs install`. The repositories API
// returns topics inline, so filtering on it costs no extra requests.
installableTopic = "databricks-cli-installable"
)

type labsMeta struct {
Name string `json:"name"`
Description string `json:"description"`
Expand All @@ -20,14 +30,35 @@ func allRepos(ctx context.Context) (github.Repositories, error) {
if err != nil {
return nil, err
}
cache := github.NewRepositoryCache("databrickslabs", cacheDir)
cache := github.NewRepositoryCache(labsOrg, cacheDir)
return cache.Load(ctx)
}

// installableRepos returns the org repositories that `databricks labs install` can
// install. Most repositories don't ship a labs.yml manifest (e.g. libraries
// published to package indexes); maintainers tag the installable ones with
// installableTopic so the listing doesn't advertise projects that fail to install.
func installableRepos(ctx context.Context) (github.Repositories, error) {
repos, err := allRepos(ctx)
if err != nil {
return nil, err
}
var out github.Repositories
for _, repo := range repos {
if repo.IsArchived || repo.IsFork {
continue
}
if slices.Contains(repo.Topics, installableTopic) {
out = append(out, repo)
}
}
return out, nil
}

func newListCommand() *cobra.Command {
return &cobra.Command{
Use: "list",
Short: "List all labs",
Short: "List labs that can be installed",
Annotations: map[string]string{
"template": cmdio.Heredoc(`
Name Description
Expand All @@ -37,18 +68,12 @@ func newListCommand() *cobra.Command {
},
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
repositories, err := allRepos(ctx)
repositories, err := installableRepos(ctx)
if err != nil {
return err
}
var info []labsMeta
for _, v := range repositories {
if v.IsArchived {
continue
}
if v.IsFork {
continue
}
description := v.Description
if len(description) > 50 {
description = description[:50] + "..."
Expand Down
28 changes: 28 additions & 0 deletions cmd/labs/list_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package labs_test

import (
"net/http"
"net/http/httptest"
"testing"

"github.com/databricks/cli/cmd/labs/github"
"github.com/databricks/cli/internal/testcli"
"github.com/databricks/cli/libs/env"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

Expand All @@ -15,4 +19,28 @@ func TestListingWorks(t *testing.T) {
stdout, _, err := c.Run()
require.NoError(t, err)
require.Contains(t, stdout.String(), "ucx")
// blueprint is in the repositories cache fixture but lacks the
// databricks-cli-installable topic, proving the topic filter is applied.
require.NotContains(t, stdout.String(), "blueprint")
}

func TestListingFiltersReposWithoutTopic(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "/users/databrickslabs/repos", r.URL.Path)
_, err := w.Write([]byte(`[
{"name": "ucx", "description": "Unity Catalog Migrations", "topics": ["databricks-cli-installable"]},
{"name": "brickster", "description": "R interface to Databricks", "topics": []}
]`))
assert.NoError(t, err)
}))
defer server.Close()
ctx := t.Context()
ctx = github.WithApiOverride(ctx, server.URL)
ctx = env.WithUserHomeDir(ctx, t.TempDir())

c := testcli.NewRunner(t, ctx, "labs", "list")
stdout, _, err := c.Run()
require.NoError(t, err)
require.Contains(t, stdout.String(), "ucx")
require.NotContains(t, stdout.String(), "brickster")
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
"stargazers_count": 100500,
"fork": false,
"archived": false,
"topics": [],
"topics": [
"databricks-cli-installable"
],
"html_url": "https://github.com/databrickslabs/ucx",
"clone_url": "https://github.com/databrickslabs/ucx.git",
"ssh_url": "git@github.com:databrickslabs/ucx.git",
Expand Down
Loading