job_runs: add lifecycle.triggers.on_file_change - #6309
Conversation
Integration test reportCommit: b0437a3
Top 9 slowest tests (at least 2 minutes):
|
Approval status: pending
|
b8c20f6 to
8744e5e
Compare
8744e5e to
47994d8
Compare
0756969 to
4e7b960
Compare
| "seed.txt": "" | ||
| } | ||
| }, | ||
| "lifecycle.triggers.on_file_change['seed.txt']": { |
There was a problem hiding this comment.
Non blocking but still a bit weird that have both "lifecycle.triggers.on_file_change['seed.txt']" and "lifecycle.triggers.on_file_change" here.
| // lifecycle.triggers, or the leaf. | ||
| if change.New == nil || change.New == "" { | ||
| pathString := path.String() | ||
| if isJobRunTriggerPath(pathString) { |
There was a problem hiding this comment.
can we use HasPrefix + Path objects instead of string matching? String matching will miss child and parent paths.
var TriggersPath = MustParsePath("lifecycle.triggers")
...
if path.HasPrefix(TriggersPath) {
There was a problem hiding this comment.
I reverted this -- it seems that prefix matching is too broad and would skip on_file_change['seed.txt'], while removed files need to be recreated.
17857f9 to
45c4ccd
Compare
Re-fire a run when matched file contents change, using stable hash fingerprints so mtime-only updates (touch) do not recreate.
Satisfy the linter on PrepareState literals after adding OnFileChange, and refresh out.fields.txt so validate-generated stays green.
Reject patterns outside the sync root and directory-only matches so the trigger cannot fingerprint escaped paths or silently disarm.
Drop size/mtime fingerprints and the resolve fast path so content identity alone drives recreate, and touch no longer needs a planner exception.
The modernize linter rejects the manual m[k]=v copy loop, failing CI lint.
Honor .gitignore and sync.exclude when hashing matches. Cover mysubdir globs, READPLAN, and keep LF on Windows so restored files hash cleanly.
The glob test edits migrations/ignored.txt, but the test .gitignore excluded it from the commit so CI clones would miss the file.
Plan serialization is already covered by on_file_change; the glob cases only assert the hash map.
Cover deploying glob hashes from a saved plan, not only from a live re-plan.
Keep the gitignore fixture as dot_gitignore so it does not affect the repo while developing, drop unit tests that duplicate acceptance coverage, and allocate trigger state once when a trigger is armed.
The previous simplification omitted OnBundleDeploy from the struct literal, which the linter rejects.
Always persist the same lifecycle.triggers shape so trigger fingerprints compare at the same paths. Wrap on_file_change hashes in files so dropping the trigger updates instead of recreating.
Nest lifecycle by value so structdiff descends to the leaf that changed instead of reporting the whole subtree, and let RemapState supply the empty shape. GetRun never returns the fingerprints, so the remote type no longer advertises a lifecycle it cannot fill.
Drop the files wrapper so plan diffs land on lifecycle.triggers.on_file_change, matching the config path without an extra state-only level.
Flattening on_file_change to a map made an unarmed trigger drop out of the serialized state, so the three plans that print an unarmed job_run now report an empty triggers object.
Directory-only and sync-excluded matches silently disarmed the trigger. Treat them as errors, warn that ** is not recursive, and cover both in acc.
The goldens were captured against a one-line-taller databricks.yml, so CI failed after the source settled on line 24.
Clearing a trigger is now a skip, so the plan reports the run as unchanged and the deploy makes no API call.
Patterns must still land under the sync root. Reject **, warn when a glob matches directories, and skip only when the trigger itself is cleared.
filepath.Join rebases an absolute glob under the bundle root, so reject those up front. Key missing-file placeholders to the sync root, and skip a cleared trigger from path.String() instead of prefix matching.
Every "nothing to hash" case re-arms once a matching file appears, now that the placeholder is always recorded, so none of them justify failing the deploy. Directories matched alongside real files are skipped silently: a glob like migrations/* routinely matches a subdirectory, and warning about it on every command was noise the user cannot act on. Also drop the unreachable "lifecycle.triggers" branch in OverrideChangeDesc (structdiff descends into the value struct and never reports a change at that path) and document the ** and sync-skipping rules in the schema.
Windows CI converted /tmp/seed.txt to %TEMP%/seed.txt, so the golden expecting the POSIX path failed. MSYS_NO_PATHCONV keeps the argument intact.
MSYS_NO_PATHCONV also stops Git Bash converting the path of a shebang helper, so update_file.py could not be found on Windows. Keep the leading-slash pattern out of argv entirely instead.
d65e640 to
b0437a3
Compare
## Changes Drop `job_run` unit tests that duplicate existing acceptance coverage, and add `destroy_unfinished_run` so cancel-before-delete is asserted through the same path a user destroy takes. Kept the wait/GetRun stubs that acceptance cannot reach without faking the Jobs API. ## Why Split from review on databricks#6309: if a unit test is already covered by acc, keep the acc test. ## Tests - New acc: `acceptance/bundle/resources/job_runs/destroy_unfinished_run` (faulted wait, then destroy cancel + delete order)
Changes
Add
lifecycle.triggers.on_file_changeforresources.job_runs(direct engine).touchdoes not re-fire.on_file_change['path'], not the map itself)..gitignoreandsync.exclude). Directories matched next to real files (typical formigrations/*) are skipped silently.lifecycle.triggers.on_file_changepath-to-hash map, nested by value so a plan diff lands on the file. Missing matches use the same sync-root-relative key as real files, so appear/disappear is a hash change rather than a key swap.filepath.Joincannot rebase/tmp/seed.txtunder the bundle root), patterns outside the sync root, empty patterns,**(filepath.Globtreats it as a single*), and combining a trigger withprevent_destroy. Warn when a pattern hashes nothing (no match, directory-only, or only sync-excluded files); the placeholder still re-arms once a matching file appears.Why
Users need to re-run a job when local inputs change (SQL migrations, notebooks, configs) without re-firing on every deploy. Content hashes keep the trigger stable under sync noise while still catching real edits.
A pattern that hashes nothing used to look like an unarmed trigger. Recording a placeholder under a stable key means those cases re-arm later, so they are warnings rather than deploy failures.
Tests
resolve_job_run_file_triggers; trigger validation for an empty pattern, both keys set, neither key set,on_bundle_deploy: false, and theprevent_destroyconflict (named by the trigger that is set);OverrideChangeDescskip on a cleared trigger vs recreate on a clearedon_file_change['path']child.on_file_change— first deploy fires; unchanged redeploy andtouchplan nothing; an edit recreates (including READPLAN); deleting the file warns and re-fires; restoring it re-fires again; removing the trigger is unchanged with norun-now.on_file_change_glob—migrations/*plusmysubdir/*.txt; matches appearing and disappearing re-fire; files below the glob and gitignored files do not;**is rejected; READPLAN.on_file_change_errors— pattern outside the sync root (error); directory-only, directory plus sync-excluded, only sync-excluded, and no-match (warnings); unsupported**and an absolute pattern (errors).on_file_change_include/on_file_change_sync_root/on_file_change_include_sync_root— YAML-relative globs, including whensync.pathsreaches above the bundle root.