job_runs: add lifecycle.triggers.on_file_change - #6309
Open
radakam wants to merge 34 commits into
Open
Conversation
Collaborator
Integration test reportCommit: 0850022
Top 3 slowest tests (at least 2 minutes):
|
radakam
marked this pull request as ready for review
August 19, 2026 08:04
Contributor
Approval status: pending
|
Base automatically changed from
deco-job-runs-lifecycle-on-bundle-deploy
to
main
August 19, 2026 09:41
radakam
force-pushed
the
deco-job-runs-lifecycle-on-file-change
branch
from
August 19, 2026 09:47
b8c20f6 to
8744e5e
Compare
radakam
force-pushed
the
deco-job-runs-lifecycle-on-file-change
branch
from
August 19, 2026 11:39
8744e5e to
47994d8
Compare
denik
reviewed
Aug 19, 2026
denik
reviewed
Aug 19, 2026
denik
reviewed
Aug 20, 2026
denik
reviewed
Aug 20, 2026
denik
reviewed
Aug 21, 2026
denik
reviewed
Aug 21, 2026
radakam
force-pushed
the
deco-job-runs-lifecycle-on-file-change
branch
from
August 24, 2026 13:24
0756969 to
4e7b960
Compare
denik
reviewed
Aug 24, 2026
radakam
force-pushed
the
deco-job-runs-lifecycle-on-file-change
branch
from
August 25, 2026 08:12
17857f9 to
45c4ccd
Compare
radakam
changed the base branch from
main
to
job-runs-drop-unit-tests-covered-by-acc
August 25, 2026 08:13
Base automatically changed from
job-runs-drop-unit-tests-covered-by-acc
to
main
August 25, 2026 10:05
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.
radakam
force-pushed
the
deco-job-runs-lifecycle-on-file-change
branch
from
August 25, 2026 10:12
d65e640 to
b0437a3
Compare
jariaspdev-lab
pushed a commit
to jariaspdev-lab/cli
that referenced
this pull request
Aug 25, 2026
## 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)
… duplicate plan entry Iterate the sync file list with path.Match instead of filepath.Glob so on_file_change honors .gitignore and sync.exclude directly, and drop the whole-map diff when per-file entries already report the change.
denik
reviewed
Aug 27, 2026
Keep resolved hashes off user config, omit empty lifecycle from state, and fold include/sync-root path coverage into one acceptance test.
Match the INPUT type so refschema reports one INPUT STATE row instead of splitting pointer and value.
update_file.py uses text mode, so Windows rewrites committed LF files as CRLF and later plans still see those files as changed.
Group resolved hashes as pattern -> file -> hash so the planner can tell a removed trigger from a file dropping out of a glob, replacing the flat map and the empty-hash placeholder. PrepareState now copies the resolved trigger state instead of rebuilding it.
Store one deterministic fingerprint per pattern so plan paths remain concise while file additions, removals, and content changes still re-fire the run.
…triggers Resolve on_file_change fingerprints after the build/predeploy scripts have run and hash matched files through the SyncRoot VFS, so build outputs and WSFS notebooks are captured. Persist a cleared trigger's state without invoking the Jobs API, so removing then re-adding a trigger re-fires the run.
ValidateJobRunTriggers already runs during initialize, and acceptance covers the pattern cases that duplicated the mutator unit tests.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Changes
Add
lifecycle.triggers.on_file_changeforresources.job_runs(direct engine).bundle plan/bundle validate) and after predeploy (forbundle deploy). Hash through the sameSyncRootVFS used by sync, so WSFS notebooks and generated overlays are included. An mtime-onlytouchdoes not re-fire.libs/sync.FileList+path.Match), including sync's generated include patterns..gitignoreandsync.excludeare honored. Directories never appear in that list, somigrations/*hashes only regular files.lifecycle.triggers_stateas normalized-pattern → aggregate-hash entries, plus a UUID foron_bundle_deploy. Each aggregate hashes the sorted matched paths and their content hashes. Unarmed runs omitlifecyclefrom state. A no-match pattern stores the empty-set hash under the same pattern key used once files appear.**(path.Matchtreats it as two ordinary stars, not recursive), and combining a trigger withprevent_destroy. Warn when no synced files match; the empty-set fingerprint still re-arms once a matching file appears. Pattern errors are reported at validate time; hashing runs only when planning or deploying.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.
Fingerprints must be computed after build and predeploy scripts, otherwise a trigger on a generated file fires one deploy late. Hashing through
SyncRootkeeps notebook and overlay content consistent with what sync uploads.A pattern that hashes nothing used to look like an unarmed trigger. Recording an empty-set fingerprint under a stable pattern key makes those cases re-arm later, so they are warnings rather than deploy failures.
Fingerprints live on
triggers_state, not on the YAMLtriggerslist, so user config and planner state stay distinct. Clearing a trigger must persist that omission; otherwise re-adding it looks unchanged and never fires.Tests
SyncRootoverlay reads, absolute-pattern rejection, and sync-root-relative missing-pattern keys; trigger validation for empty and invalid entries andprevent_destroyconflicts; state-only classification when a trigger is removed; omission of emptylifecyclefrom serialized state.on_file_change— first deploy fires; unchanged redeploy andtouchplan nothing; an edit recreates (including READPLAN); deleting and restoring the file each re-fire; removing the trigger performs norun-now, clears its state through both live and serialized plans, and re-adding it re-fires.on_file_change_build— a prebuild script rewriting a watched file re-fires the run in that same deploy.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 cases (warnings); unsupported**and an absolute pattern (errors).on_file_change_include_sync_root— patterns from included YAML resolve next to the include, at the bundle root (../), and at the sync root (../../); each edit recreates only the corresponding pattern entry.