Compare commits

...

4 Commits

Author SHA1 Message Date
shreyas-goenka f9d65f315f
Add comment for why we test two files for `bundle_uuid` (#1949)
## Changes
Addresses feedback from this thread
https://github.com/databricks/cli/pull/1947#discussion_r1865692479
2024-12-02 14:40:57 +00:00
Pieter Noordhuis 94b221b8ba
Build snapshot releases for bugbash branches (#1948)
## Changes

To be used with
https://github.com/databricks/cli/tree/main/internal/bugbash.

## Tests

n/a
2024-12-02 14:04:08 +00:00
shreyas-goenka e86a949d99
Add the `bundle_uuid` helper function for templates (#1947)
## Changes
This PR adds the `bundle_uuid` helper function that'll return a stable
identifier for the bundle for the duration of the `bundle init` command.

This is also the UUID that'll be set in the telemetry event sent during
`databricks bundle init` and would be used to correlate revenue from
bundle init with resource deployments.

Template authors should add the uuid field to their `databricks.yml`
file they generate:
```
bundle:
  # A stable identified for your DAB project. We use this UUID in the Databricks backend 
  # to correlate and identify multiple deployments of the same DAB project. 
  uuid: {{ bundle_uuid }}
```

## Tests
Unit test
2024-12-02 10:29:29 +00:00
Denis Bilenko 00bd98f898
Move loadGitDetails mutator to Initialize phase (#1944)
This will require API call when run inside a workspace, which will
require workspace client (we don't have one at the current point). We
want to keep Load phase quick, since it's common across all commands.
2024-12-02 09:49:32 +00:00
11 changed files with 49 additions and 1 deletions

View File

@ -5,6 +5,7 @@ on:
branches: branches:
- "main" - "main"
- "demo-*" - "demo-*"
- "bugbash-*"
# Confirm that snapshot builds work if this file is modified. # Confirm that snapshot builds work if this file is modified.
pull_request: pull_request:

View File

@ -49,4 +49,8 @@ type Bundle struct {
// Databricks CLI version constraints required to run the bundle. // Databricks CLI version constraints required to run the bundle.
DatabricksCliVersion string `json:"databricks_cli_version,omitempty"` DatabricksCliVersion string `json:"databricks_cli_version,omitempty"`
// A stable generated UUID for the bundle. This is normally serialized by
// Databricks first party template when a user runs bundle init.
Uuid string `json:"uuid,omitempty"`
} }

View File

@ -26,7 +26,6 @@ func DefaultMutators() []bundle.Mutator {
ComputeIdToClusterId(), ComputeIdToClusterId(),
InitializeVariables(), InitializeVariables(),
DefineDefaultTarget(), DefineDefaultTarget(),
LoadGitDetails(),
pythonmutator.PythonMutator(pythonmutator.PythonMutatorPhaseLoad), pythonmutator.PythonMutator(pythonmutator.PythonMutatorPhaseLoad),
// Note: This mutator must run before the target overrides are merged. // Note: This mutator must run before the target overrides are merged.

View File

@ -39,6 +39,7 @@ func Initialize() bundle.Mutator {
mutator.MergePipelineClusters(), mutator.MergePipelineClusters(),
mutator.InitializeWorkspaceClient(), mutator.InitializeWorkspaceClient(),
mutator.PopulateCurrentUser(), mutator.PopulateCurrentUser(),
mutator.LoadGitDetails(),
mutator.DefineDefaultWorkspaceRoot(), mutator.DefineDefaultWorkspaceRoot(),
mutator.ExpandWorkspaceRoot(), mutator.ExpandWorkspaceRoot(),

View File

@ -1,15 +1,19 @@
package config_tests package config_tests
import ( import (
"context"
"fmt" "fmt"
"strings" "strings"
"testing" "testing"
"github.com/databricks/cli/bundle"
"github.com/databricks/cli/bundle/config/mutator"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestGitAutoLoadWithEnvironment(t *testing.T) { func TestGitAutoLoadWithEnvironment(t *testing.T) {
b := load(t, "./environments_autoload_git") b := load(t, "./environments_autoload_git")
bundle.Apply(context.Background(), b, mutator.LoadGitDetails())
assert.True(t, b.Config.Bundle.Git.Inferred) assert.True(t, b.Config.Bundle.Git.Inferred)
validUrl := strings.Contains(b.Config.Bundle.Git.OriginURL, "/cli") || strings.Contains(b.Config.Bundle.Git.OriginURL, "/bricks") validUrl := strings.Contains(b.Config.Bundle.Git.OriginURL, "/cli") || strings.Contains(b.Config.Bundle.Git.OriginURL, "/bricks")
assert.True(t, validUrl, fmt.Sprintf("Expected URL to contain '/cli' or '/bricks', got %s", b.Config.Bundle.Git.OriginURL)) assert.True(t, validUrl, fmt.Sprintf("Expected URL to contain '/cli' or '/bricks', got %s", b.Config.Bundle.Git.OriginURL))
@ -17,6 +21,7 @@ func TestGitAutoLoadWithEnvironment(t *testing.T) {
func TestGitManuallySetBranchWithEnvironment(t *testing.T) { func TestGitManuallySetBranchWithEnvironment(t *testing.T) {
b := loadTarget(t, "./environments_autoload_git", "production") b := loadTarget(t, "./environments_autoload_git", "production")
bundle.Apply(context.Background(), b, mutator.LoadGitDetails())
assert.False(t, b.Config.Bundle.Git.Inferred) assert.False(t, b.Config.Bundle.Git.Inferred)
assert.Equal(t, "main", b.Config.Bundle.Git.Branch) assert.Equal(t, "main", b.Config.Bundle.Git.Branch)
validUrl := strings.Contains(b.Config.Bundle.Git.OriginURL, "/cli") || strings.Contains(b.Config.Bundle.Git.OriginURL, "/bricks") validUrl := strings.Contains(b.Config.Bundle.Git.OriginURL, "/cli") || strings.Contains(b.Config.Bundle.Git.OriginURL, "/bricks")

View File

@ -14,6 +14,7 @@ import (
func TestGitAutoLoad(t *testing.T) { func TestGitAutoLoad(t *testing.T) {
b := load(t, "./autoload_git") b := load(t, "./autoload_git")
bundle.Apply(context.Background(), b, mutator.LoadGitDetails())
assert.True(t, b.Config.Bundle.Git.Inferred) assert.True(t, b.Config.Bundle.Git.Inferred)
validUrl := strings.Contains(b.Config.Bundle.Git.OriginURL, "/cli") || strings.Contains(b.Config.Bundle.Git.OriginURL, "/bricks") validUrl := strings.Contains(b.Config.Bundle.Git.OriginURL, "/cli") || strings.Contains(b.Config.Bundle.Git.OriginURL, "/bricks")
assert.True(t, validUrl, fmt.Sprintf("Expected URL to contain '/cli' or '/bricks', got %s", b.Config.Bundle.Git.OriginURL)) assert.True(t, validUrl, fmt.Sprintf("Expected URL to contain '/cli' or '/bricks', got %s", b.Config.Bundle.Git.OriginURL))
@ -21,6 +22,7 @@ func TestGitAutoLoad(t *testing.T) {
func TestGitManuallySetBranch(t *testing.T) { func TestGitManuallySetBranch(t *testing.T) {
b := loadTarget(t, "./autoload_git", "production") b := loadTarget(t, "./autoload_git", "production")
bundle.Apply(context.Background(), b, mutator.LoadGitDetails())
assert.False(t, b.Config.Bundle.Git.Inferred) assert.False(t, b.Config.Bundle.Git.Inferred)
assert.Equal(t, "main", b.Config.Bundle.Git.Branch) assert.Equal(t, "main", b.Config.Bundle.Git.Branch)
validUrl := strings.Contains(b.Config.Bundle.Git.OriginURL, "/cli") || strings.Contains(b.Config.Bundle.Git.OriginURL, "/bricks") validUrl := strings.Contains(b.Config.Bundle.Git.OriginURL, "/cli") || strings.Contains(b.Config.Bundle.Git.OriginURL, "/bricks")
@ -34,6 +36,7 @@ func TestGitBundleBranchValidation(t *testing.T) {
}) })
b := load(t, "./git_branch_validation") b := load(t, "./git_branch_validation")
bundle.Apply(context.Background(), b, mutator.LoadGitDetails())
assert.False(t, b.Config.Bundle.Git.Inferred) assert.False(t, b.Config.Bundle.Git.Inferred)
assert.Equal(t, "feature-a", b.Config.Bundle.Git.Branch) assert.Equal(t, "feature-a", b.Config.Bundle.Git.Branch)
assert.Equal(t, "feature-b", b.Config.Bundle.Git.ActualBranch) assert.Equal(t, "feature-b", b.Config.Bundle.Git.ActualBranch)

View File

@ -35,6 +35,13 @@ var cachedUser *iam.User
var cachedIsServicePrincipal *bool var cachedIsServicePrincipal *bool
var cachedCatalog *string var cachedCatalog *string
// UUID that is stable for the duration of the template execution. This can be used
// to populate the `bundle.uuid` field in databricks.yml by template authors.
//
// It's automatically logged in our telemetry logs when `databricks bundle init`
// is run and can be used to attribute DBU revenue to bundle templates.
var bundleUuid = uuid.New().String()
func loadHelpers(ctx context.Context) template.FuncMap { func loadHelpers(ctx context.Context) template.FuncMap {
w := root.WorkspaceClient(ctx) w := root.WorkspaceClient(ctx)
return template.FuncMap{ return template.FuncMap{
@ -57,6 +64,9 @@ func loadHelpers(ctx context.Context) template.FuncMap {
"uuid": func() string { "uuid": func() string {
return uuid.New().String() return uuid.New().String()
}, },
"bundle_uuid": func() string {
return bundleUuid
},
// A key value pair. This is used with the map function to generate maps // A key value pair. This is used with the map function to generate maps
// to use inside a template // to use inside a template
"pair": func(k string, v any) pair { "pair": func(k string, v any) pair {

View File

@ -32,6 +32,29 @@ func TestTemplatePrintStringWithoutProcessing(t *testing.T) {
assert.Equal(t, `{{ fail "abc" }}`, cleanContent) assert.Equal(t, `{{ fail "abc" }}`, cleanContent)
} }
func TestTemplateBundleUuidFunction(t *testing.T) {
ctx := context.Background()
ctx = root.SetWorkspaceClient(ctx, nil)
helpers := loadHelpers(ctx)
r, err := newRenderer(ctx, nil, helpers, os.DirFS("."), "./testdata/bundle-uuid/template", "./testdata/bundle-uuid/library")
require.NoError(t, err)
err = r.walk()
assert.NoError(t, err)
// We test the content of two generated files to ensure that the same UUID
// is used across all files generated by the template. Each file content is
// generated by a separate (*template.Template).Execute call, so testing different
// files ensures that the UUID is stable across all template execution calls.
copy := strings.Clone(bundleUuid)
assert.Len(t, r.files, 2)
c1 := strings.Trim(string(r.files[0].(*inMemoryFile).content), "\n\r")
assert.Equal(t, strings.Repeat(copy, 3), c1)
c2 := strings.Trim(string(r.files[1].(*inMemoryFile).content), "\n\r")
assert.Equal(t, strings.Repeat(copy, 5), c2)
}
func TestTemplateRegexpCompileFunction(t *testing.T) { func TestTemplateRegexpCompileFunction(t *testing.T) {
ctx := context.Background() ctx := context.Background()

View File

View File

@ -0,0 +1 @@
{{bundle_uuid}}{{bundle_uuid}}{{bundle_uuid}}

View File

@ -0,0 +1 @@
{{bundle_uuid}}{{bundle_uuid}}{{bundle_uuid}}{{bundle_uuid}}{{bundle_uuid}}