diff --git a/.nextchanges/bundles/skip-apply-mutators-without-mutators.md b/.nextchanges/bundles/skip-apply-mutators-without-mutators.md new file mode 100644 index 00000000000..c0f66ea18d0 --- /dev/null +++ b/.nextchanges/bundles/skip-apply-mutators-without-mutators.md @@ -0,0 +1 @@ +Skip the `apply_mutators` phase when no `python.mutators` are configured, so bundles that only load resources in Python no longer start a subprocess that loads every resource and returns it unchanged. diff --git a/bundle/config/mutator/python/python_mutator.go b/bundle/config/mutator/python/python_mutator.go index 9112aaa808d..269a611a9d2 100644 --- a/bundle/config/mutator/python/python_mutator.go +++ b/bundle/config/mutator/python/python_mutator.go @@ -124,6 +124,13 @@ func getOpts(b *bundle.Bundle, phase phase) (opts, error) { return opts{}, errors.New("experimental/pydabs is deprecated, use python instead (https://docs.databricks.com/dev-tools/bundles/python)") } + // Without mutator functions there is nothing to mutate, so skip the subprocess that would load + // every resource and return it unchanged. load_resources still reports configuration errors. + if phase == PythonMutatorPhaseApplyMutators && + len(b.Config.Python.Mutators) == 0 && len(experimental.Python.Mutators) == 0 { + return opts{}, nil + } + if experimentalPythonEnabled && pythonEnabled { if !reflect.DeepEqual(experimental.Python, b.Config.Python) { return opts{}, errors.New("'experimental/python' and 'python' configuration properties are mutually exclusive, use only 'python'") diff --git a/bundle/config/mutator/python/python_mutator_test.go b/bundle/config/mutator/python/python_mutator_test.go index 9b106f727bf..1600cb1fb0f 100644 --- a/bundle/config/mutator/python/python_mutator_test.go +++ b/bundle/config/mutator/python/python_mutator_test.go @@ -406,6 +406,56 @@ func TestGetOps_empty(t *testing.T) { assert.Equal(t, opts{enabled: false}, actual) } +func TestGetOps_ApplyMutatorsWithoutMutators(t *testing.T) { + actual, err := getOpts(&bundle.Bundle{ + Config: config.Root{ + Python: config.Python{ + VEnvPath: ".venv", + Resources: []string{ + "resources:load_resources", + }, + }, + }, + }, PythonMutatorPhaseApplyMutators) + + assert.NoError(t, err) + assert.Equal(t, opts{enabled: false}, actual) +} + +func TestGetOps_ApplyMutators(t *testing.T) { + actual, err := getOpts(&bundle.Bundle{ + Config: config.Root{ + Python: config.Python{ + VEnvPath: ".venv", + Mutators: []string{ + "mutators:add_email_notifications", + }, + }, + }, + }, PythonMutatorPhaseApplyMutators) + + assert.NoError(t, err) + assert.Equal(t, opts{venvPath: ".venv", enabled: true, loadLocations: true}, actual) +} + +func TestGetOps_ApplyMutatorsExperimental(t *testing.T) { + actual, err := getOpts(&bundle.Bundle{ + Config: config.Root{ + Experimental: &config.Experimental{ + Python: config.Python{ + VEnvPath: ".venv", + Mutators: []string{ + "mutators:add_email_notifications", + }, + }, + }, + }, + }, PythonMutatorPhaseApplyMutators) + + assert.NoError(t, err) + assert.Equal(t, opts{venvPath: ".venv", enabled: true, loadLocations: true}, actual) +} + func TestApplyBackwardCompatibilityFixes(t *testing.T) { b := &bundle.Bundle{ Config: config.Root{