Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
bundle:
name: config-remote-sync-not-in-config

resources:
jobs:
foo:
name: test job
tasks:
- task_key: main
notebook_task:
notebook_path: /Workspace/Users/tester@databricks.com/notebook
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Cloud = false
GOOS.windows = false
EnvMatrix.DMS = [""]
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/config-remote-sync-not-in-config/default/files...
Created jobs.foo
Files: 1 uploaded, 0 deleted
Resources: 1 created, 0 changed, 0 deleted, 0 unchanged

>>> [CLI] bundle config-remote-sync --select-ids jobs:[FOO_ID] -o json
{
"status": "failed",
"error": "deployed resources missing from the bundle configuration (renamed or removed since the last deploy): resources.jobs.foo",
"errorCode": "RESOURCE_NOT_IN_CONFIG",
"files": null,
"changes": {}
}

>>> cat [OUTPUT_DIR]/out.requests.txt
{
"error_message": "deployed resources missing from the bundle configuration (renamed or removed since the last deploy): resources.jobs.foo",
"error_category": "RESOURCE_NOT_IN_CONFIG"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
trace $CLI bundle deploy
job_id="$(read_id.py foo)"

# The deployed job's key is renamed locally, so the config no longer has it.
update_file.py databricks.yml " foo:" " bar:"

trace $CLI bundle config-remote-sync --select-ids "jobs:$job_id" -o json

trace cat "$OUT_REQUESTS" | jq 'select(has("path") and .path == "/telemetry-ext") | .body.protoLogs[] | fromjson | .entry.databricks_cli_log.bundle_config_remote_sync_event | select(. != null) | {error_message, error_category}'

rm "$OUT_REQUESTS"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# config-remote-sync is not supported on Windows.
GOOS.windows = false
12 changes: 8 additions & 4 deletions bundle/configsync/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@ const (

// DiffOutput represents the complete output of the config-remote-sync command
type DiffOutput struct {
Status SyncStatus `json:"status"`
Error string `json:"error,omitempty"`
Files []FileChange `json:"files"`
Changes Changes `json:"changes"`
Status SyncStatus `json:"status"`
Error string `json:"error,omitempty"`
ErrorCode protos.BundleConfigRemoteSyncErrorCategory `json:"errorCode,omitempty"`
Files []FileChange `json:"files"`
Changes Changes `json:"changes"`
}

// WriteResult renders the result and records the error payload on stats for
Expand All @@ -45,6 +46,8 @@ type DiffOutput struct {
// returns the error so the CLI still fails loudly for humans.
func WriteResult(out io.Writer, jsonOutput bool, stats *Stats, files []FileChange, changes Changes, err error) error {
status := StatusSuccess
// Read before the fallback below so unclassified errors carry no code.
errorCode := stats.ErrorCategory
if err != nil {
if stats.ErrorCategory == "" {
stats.ErrorCategory = protos.BundleConfigRemoteSyncErrorCategoryBundleLoadFailed
Expand Down Expand Up @@ -74,6 +77,7 @@ func WriteResult(out io.Writer, jsonOutput bool, stats *Stats, files []FileChang
}
if err != nil {
output.Error = err.Error()
output.ErrorCode = errorCode
}
result, marshalErr := json.MarshalIndent(output, "", " ")
if marshalErr != nil {
Expand Down
14 changes: 14 additions & 0 deletions cmd/bundle/config_remote_sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import (
"maps"
"runtime"
"slices"
"strings"

"github.com/databricks/cli/bundle"
"github.com/databricks/cli/bundle/configsync"
"github.com/databricks/cli/bundle/deployplan"
"github.com/databricks/cli/bundle/statemgmt"
"github.com/databricks/cli/cmd/bundle/utils"
"github.com/databricks/cli/cmd/root"
Expand Down Expand Up @@ -121,6 +123,18 @@ Examples:
if err != nil {
return err
}
// A selected resource planned as a delete was renamed or removed in the
// config, so its remote changes have nowhere to be written back.
var missing []string
for _, key := range selected {
if plan.Plan[key].Action == deployplan.Delete {
missing = append(missing, key)
}
}
if len(missing) > 0 {
stats.ErrorCategory = protos.BundleConfigRemoteSyncErrorCategoryResourceNotInConfig
return fmt.Errorf("deployed resources missing from the bundle configuration (renamed or removed since the last deploy): %s", strings.Join(missing, ", "))
}
detected = configsync.FilterChanges(detected, selected)
}

Expand Down
3 changes: 2 additions & 1 deletion libs/telemetry/protos/bundle_config_remote_sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ const (
BundleConfigRemoteSyncErrorCategoryYamlApplyFailed BundleConfigRemoteSyncErrorCategory = "YAML_APPLY_FAILED"
BundleConfigRemoteSyncErrorCategorySaveFailed BundleConfigRemoteSyncErrorCategory = "SAVE_FAILED"
BundleConfigRemoteSyncErrorCategoryOutputFailed BundleConfigRemoteSyncErrorCategory = "OUTPUT_FAILED"
BundleConfigRemoteSyncErrorCategoryResourceNotInConfig BundleConfigRemoteSyncErrorCategory = "RESOURCE_NOT_IN_CONFIG"
)

// BundleConfigRemoteSyncEvent is emitted on every execution of the
// `databricks bundle config-remote-sync` command.
//
// All fields are aggregate counts, booleans, or system-defined categories.
// No resource names, keys, field paths, file paths, or configuration values
// are logged.
// are logged outside ErrorMessage.
type BundleConfigRemoteSyncEvent struct {
// Whether the command was invoked with --save (config files written to
// disk) as opposed to diff-only mode.
Expand Down
Loading