Added same source validation and made thread safe

This commit is contained in:
Andrew Nester 2024-12-19 14:00:06 +01:00
parent db516b6e72
commit 2f8df81159
No known key found for this signature in database
GPG Key ID: 12BC628A44B7DA57
3 changed files with 54 additions and 9 deletions

View File

@ -6,6 +6,7 @@ import (
"fmt"
"path"
"strings"
"sync"
"github.com/databricks/cli/bundle"
"github.com/databricks/cli/bundle/config/resources"
@ -25,8 +26,7 @@ func (u *uploadConfig) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnos
var diags diag.Diagnostics
errGroup, ctx := errgroup.WithContext(ctx)
diagsPerApp := make(map[string]diag.Diagnostic)
mu := &sync.Mutex{}
for key, app := range b.Config.Resources.Apps {
// If the app has a config, we need to deploy it first.
// It means we need to write app.yml file with the content of the config field
@ -59,12 +59,14 @@ func (u *uploadConfig) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnos
errGroup.Go(func() error {
err = f.Write(ctx, path.Join(appPath, "app.yml"), buf, filer.OverwriteIfExists)
if err != nil {
diagsPerApp[key] = diag.Diagnostic{
mu.Lock()
diags = append(diags, diag.Diagnostic{
Severity: diag.Error,
Summary: "Failed to save config",
Detail: fmt.Sprintf("Failed to write %s file: %s", path.Join(app.SourceCodePath, "app.yml"), err),
Locations: b.Config.GetLocations(fmt.Sprintf("resources.apps.%s", key)),
}
})
mu.Unlock()
}
return nil
})
@ -75,10 +77,6 @@ func (u *uploadConfig) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnos
return diags.Extend(diag.FromErr(err))
}
for _, diag := range diagsPerApp {
diags = append(diags, diag)
}
return diags
}

View File

@ -14,8 +14,19 @@ type validate struct{}
func (v *validate) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnostics {
var diags diag.Diagnostics
possibleConfigFiles := []string{"app.yml", "app.yaml"}
usedSourceCodePaths := make(map[string]string)
for key, app := range b.Config.Resources.Apps {
if _, ok := usedSourceCodePaths[app.SourceCodePath]; ok {
diags = append(diags, diag.Diagnostic{
Severity: diag.Error,
Summary: "Duplicate app source code path",
Detail: fmt.Sprintf("app resource '%s' has the same source code path as app resource '%s'", key, usedSourceCodePaths[app.SourceCodePath]),
Locations: b.Config.GetLocations(fmt.Sprintf("resources.apps.%s.source_code_path", key)),
})
}
usedSourceCodePaths[app.SourceCodePath] = key
for _, app := range b.Config.Resources.Apps {
for _, configFile := range possibleConfigFiles {
cf := path.Join(app.SourceCodePath, configFile)
if _, err := b.SyncRoot.Stat(cf); err == nil {

View File

@ -53,3 +53,39 @@ func TestAppsValidate(t *testing.T) {
require.Equal(t, "app.yml detected", diags[0].Summary)
require.Contains(t, diags[0].Detail, "app.yml and use 'config' property for app resource")
}
func TestAppsValidateSameSourcePath(t *testing.T) {
tmpDir := t.TempDir()
testutil.Touch(t, tmpDir, "app1", "app.py")
b := &bundle.Bundle{
BundleRootPath: tmpDir,
SyncRootPath: tmpDir,
SyncRoot: vfs.MustNew(tmpDir),
Config: config.Root{
Resources: config.Resources{
Apps: map[string]*resources.App{
"app1": {
App: &apps.App{
Name: "app1",
},
SourceCodePath: "./app1",
},
"app2": {
App: &apps.App{
Name: "app2",
},
SourceCodePath: "./app1",
},
},
},
},
}
bundletest.SetLocation(b, ".", []dyn.Location{{File: filepath.Join(tmpDir, "databricks.yml")}})
diags := bundle.Apply(context.Background(), b, bundle.Seq(mutator.TranslatePaths(), Validate()))
require.Len(t, diags, 1)
require.Equal(t, "Duplicate app source code path", diags[0].Summary)
require.Contains(t, diags[0].Detail, "has the same source code path as app resource")
}