Skip to content

Support file selectors in pipelines run - #7184

Open
chenyuem-db wants to merge 4 commits into
mainfrom
chenyuem-db/pipeline-refresh-by-file
Open

chenyuem-db wants to merge 4 commits into
mainfrom
chenyuem-db/pipeline-refresh-by-file

Conversation

@chenyuem-db

@chenyuem-db chenyuem-db commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Changes

Support source files in pipelines run --refresh and --full-refresh, so users can refresh the tables defined in a file without listing their names; pipeline bundle run uses the same resolver.

databricks pipelines deploy
databricks pipelines run my_pipeline --refresh ./src/pipeline.py
databricks pipelines run my_pipeline --full-refresh ./src/pipeline.py
databricks bundle run my_pipeline --refresh ./src/pipeline.py

Local paths are relative to the current directory and follow bundle sync rules, including notebook names and exclusions. Immutable deployments resolve the deployed snapshot path from state. Absolute /Workspace/ paths are also accepted.

Each flag accepts either table names or files because the API gives table selections precedence within a refresh mode. The two flags can use different selector types. Existing local files take precedence over bare names; backticks select ambiguous table identifiers. Invalid selectors are rejected before a restart stops the active update.

Completion summaries fetch paginated events and filter progress events locally because the public events API rejects event_type filters.

Why

Implements file-based selective refresh from the SDP Turbo CLI PRD, bringing the UI “Run file” capability to the CLI. Local changes use the existing deploy-then-run workflow. Output shows selected source paths; displaying resolved table names remains a follow-up.

Tests

  • Unit tests cover selector parsing, notebook mapping, sync exclusions, deployment modes, deployed snapshot paths, incompatible options, and paginated event summaries.
  • Passed 149 local acceptance variants across pipeline/bundle runs, immutable deployment, file-change triggers, and sync modes, plus the updated refresh-flags case.
  • Enabled Cloud = true on the existing refresh-flags test and passed it against a real staging workspace, covering table and file refreshes, notebooks, absolute paths, subdirectory runs, and bundle run; invalid restart inputs sent no pipeline mutations.
  • Passed affected Go package tests and ./task fmt, ./task checks, and ./task lint.

@github-actions github-actions Bot added the DABs DABs related issues label Oct 26, 2026
@eng-dev-ecosystem-bot

eng-dev-ecosystem-bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Collaborator

✅ Integration test report

Commit: d2509d2

Run: 42576197638

Env ✅​pass 🙈​skip Time
✅​ aws linux-2core-8gb 272 16 5:05
✅​ aws-windows-latest-4core-16gb 274 14 6:03
✅​ azure linux-2core-8gb 271 16 5:23
✅​ azure-windows-latest-4core-16gb 273 14 6:35
✅​ gcp linux-2core-8gb 272 16 5:08
✅​ gcp-windows-latest-4core-16gb 274 14 5:56
Top 9 slowest tests (at least 2 minutes):
duration env testname
3:25 azure-windows-latest-4core-16gb TestAccept/pipelines/run/refresh-flags
3:21 azure linux-2core-8gb TestAccept/pipelines/run/refresh-flags
3:04 aws-windows-latest-4core-16gb TestAccept/pipelines/run/refresh-flags
3:02 azure-windows-latest-4core-16gb TestAccept
2:57 gcp-windows-latest-4core-16gb TestAccept/pipelines/run/refresh-flags
2:56 aws-windows-latest-4core-16gb TestAccept
2:55 gcp-windows-latest-4core-16gb TestAccept
2:44 aws linux-2core-8gb TestAccept/pipelines/run/refresh-flags
2:42 gcp linux-2core-8gb TestAccept/pipelines/run/refresh-flags

@chenyuem-db
chenyuem-db force-pushed the chenyuem-db/pipeline-refresh-by-file branch 2 times, most recently from 0824056 to 652cd9e Compare October 28, 2026 17:02
@github-actions

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Commit: d2509d27f | Workflow run

Regression test report

Selected 2 changed tests (limit=20, 0 not selected)

3 tests: regression=3 unreleased=0 coverage=0 failing=0
test branch main (33bcce3) latest (v1.24.0)
TestAccept/bundle/help/bundle-run/DMS= ✅ ❌ ❌
TestAccept/bundle/help/bundle-run/DMS=true ✅ ❌ ❌
TestAccept/pipelines/run/refresh-flags ✅ ❌ ❌
TestAccept/bundle/help/bundle-run/DMS=: branch ✅ | main (33bcce3) ❌ | latest (v1.24.0) ❌

main (33bcce3):

acceptance_test.go:1345: Diff:
        --- bundle/help/bundle-run/output.txt
        +++ /tmp/TestAcceptbundlehelpbundle-runDMS=680233496/002/output.txt
        @@ -54,9 +54,9 @@
               --sql-params stringToString            A map from keys to values for jobs with SQL tasks. (default [])
         
         Pipeline Flags:
        -      --full-refresh strings   List of tables or source files to reset and recompute. Local paths are relative to the current directory.
        +      --full-refresh strings   List of tables to reset and recompute.
               --full-refresh-all       Perform a full graph reset and recompute.
        -      --refresh strings        List of tables or source files to update. Local paths are relative to the current directory.
        +      --refresh strings        List of tables to update.
               --refresh-all            Perform a full graph update.
               --validate-only          Perform an update to validate graph correctness.

latest (v1.24.0): same output as main (33bcce3)

TestAccept/bundle/help/bundle-run/DMS=true: branch ✅ | main (33bcce3) ❌ | latest (v1.24.0) ❌

main (33bcce3):

acceptance_test.go:1345: Diff:
        --- bundle/help/bundle-run/output.txt
        +++ /tmp/TestAcceptbundlehelpbundle-runDMS=true2554078822/002/output.txt
        @@ -54,9 +54,9 @@
               --sql-params stringToString            A map from keys to values for jobs with SQL tasks. (default [])
         
         Pipeline Flags:
        -      --full-refresh strings   List of tables or source files to reset and recompute. Local paths are relative to the current directory.
        +      --full-refresh strings   List of tables to reset and recompute.
               --full-refresh-all       Perform a full graph reset and recompute.
        -      --refresh strings        List of tables or source files to update. Local paths are relative to the current directory.
        +      --refresh strings        List of tables to update.
               --refresh-all            Perform a full graph update.
               --validate-only          Perform an update to validate graph correctness.

latest (v1.24.0): same output as main (33bcce3)

TestAccept/pipelines/run/refresh-flags: branch ✅ | main (33bcce3) ❌ | latest (v1.24.0) ❌

main (33bcce3):

acceptance_test.go:1345: Diff:
        --- pipelines/run/refresh-flags/output.txt
        +++ /tmp/TestAcceptpipelinesrunrefresh-flags1444074457/002/output.txt
        @@ -80,7 +80,7 @@
         
         === Refreshing tables defined in a source file
         >>> run_pipeline --refresh pipeline_file.py
        -• Refreshed tables defined in [/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/pipeline_file.py]
        +• Refreshed [pipeline_file.py]
         
         >>> print_requests.py //pipelines
         {
        @@ -88,15 +88,15 @@
           "path": "/api/2.0/pipelines/[UUID]/updates",
           "body": {
             "development": true,
        -    "refresh_selection_by_path": [
        -      "/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/pipeline_file.py"
        +    "refresh_selection": [
        +      "pipeline_file.py"
             ]
           }
         }
         
         === Fully refreshing tables defined in a source file
         >>> run_pipeline --full-refresh pipeline_file.py
        -• Full refreshed tables defined in [/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/pipeline_file.py]
        +• Full refreshed [pipeline_file.py]
         
         >>> print_requests.py //pipelines
         {
        @@ -104,15 +98,15 @@
           "path": "/api/2.0/pipelines/[UUID]/updates",
           "body": {
             "development": true,
        -    "full_refresh_selection_by_path": [
        -      "/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/pipeline_file.py"
        +    "full_refresh_selection": [
        +      "pipeline_file.py"
             ]
           }
         }
         
         === Refreshing a source notebook
         >>> run_pipeline --refresh src/pipeline_notebook.sql
        -• Refreshed tables defined in [/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/src/pipeline_notebook]
        +• Refreshed [src/pipeline_notebook.sql]
         
         >>> print_requests.py //pipelines
         {
        @@ -120,15 +108,15 @@
           "path": "/api/2.0/pipelines/[UUID]/updates",
           "body": {
             "development": true,
        -    "refresh_selection_by_path": [
        -      "/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/src/pipeline_notebook"
        +    "refresh_selection": [
        +      "src/pipeline_notebook.sql"
             ]
           }
         }
         
         === Refreshing an absolute workspace path
         >>> run_pipeline --refresh /Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/pipeline_file.py
        -• Refreshed tables defined in [/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/pipeline_file.py]
        +• Refreshed [/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/pipeline_file.py]
         
         >>> print_requests.py //pipelines
         {
        @@ -136,7 +118,7 @@
           "path": "/api/2.0/pipelines/[UUID]/updates",
           "body": {
             "development": true,
        -    "refresh_selection_by_path": [
        +    "refresh_selection": [
               "/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/pipeline_file.py"
             ]
           }
        @@ -144,7 +126,7 @@
         
         === Refreshing from a subdirectory
         >>> withdir src run_pipeline --refresh ../pipeline_file.py
        -• Refreshed tables defined in [/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/pipeline_file.py]
        +• Refreshed [../pipeline_file.py]
         
         >>> print_requests.py //pipelines
         {
        @@ -152,8 +134,8 @@
           "path": "/api/2.0/pipelines/[UUID]/updates",
           "body": {
             "development": true,
        -    "refresh_selection_by_path": [
        -      "/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/pipeline_file.py"
        +    "refresh_selection": [
        +      "../pipeline_file.py"
             ]
           }
         }
        @@ -165,37 +147,30 @@
           "path": "/api/2.0/pipelines/[UUID]/updates",
           "body": {
             "development": true,
        -    "full_refresh_selection_by_path": [
        -      "/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/src/pipeline_notebook"
        +    "full_refresh_selection": [
        +      "src/pipeline_notebook.sql"
             ],
        -    "refresh_selection_by_path": [
        -      "/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/pipeline_file.py"
        +    "refresh_selection": [
        +      "pipeline_file.py"
             ]
           }
         }
         
         === Rejecting missing sources and incompatible refresh modes
         >>> musterr [CLI] pipelines run --refresh ./missing.sql --no-wait
        -Error: invalid --refresh: source file "./missing.sql" not found; use a table name or an existing source file
        +Recommendation: This command runs the last deployed version of the code
         
        ->>> musterr [CLI] pipelines run --refresh pipeline_file.py --full-refresh-all --no-wait
        -Error: cannot use --refresh or --full-refresh together with --full-refresh-all, these flags are mutually exclusive
        +If you've made local changes, run 'databricks pipelines deploy' first to ensure they are included.
         
        ->>> musterr [CLI] pipelines run --full-refresh ./missing.sql --restart --no-wait
        -Error: invalid --full-refresh: source file "./missing.sql" not found; use a table name or an existing source file
        +Update URL: [DATABRICKS_URL]/#joblist/pipelines/[UUID]/updates/[UUID]
         
        ->>> print_requests.py //pipelines
        +Update ID: [UUID]
         
        -=== Rejecting mixed selectors before restarting the pipeline
        ->>> musterr [CLI] pipelines run --refresh table1,pipeline_file.py --restart --no-wait
        -Error: cannot mix table names and source files in --refresh; use only table names or only source files
        +Update for pipeline completed successfully.
         
        ->>> musterr [CLI] pipelines run --full-refresh table2,pipeline_file.py --restart --no-wait
        -Error: cannot mix table names and source files in --full-refresh; use only table names or only source files
        +Pipeline configurations for this update:
        +• Refreshed [./missing.sql]
         
        ->>> print_requests.py //pipelines
        +Unexpected success
         
        ->>> musterr [CLI] bundle run my_pipeline --refresh table1,pipeline_file.py --restart --no-wait
        -Error: cannot mix table names and source files in --refresh; use only table names or only source files
        -
        ->>> print_requests.py //pipelines
        +Exit code: 1
        
    acceptance_test.go:1123: 
        LOG.bundle: 
        LOG.bundle: >>> /tmp/TestAccept2109469877/001/databricks bundle run my_pipeline --refresh pipeline_file.py --full-refresh src/pipeline_notebook.sql
        LOG.bundle: Update URL: http://127.0.0.1:35725/#joblist/pipelines/7a0b4d6b-abef-4ccd-7a0b-4d6babef4dcc/updates/7a0b4d6b-faad-bf9c-7a0b-4d6bfaadc0ee
        LOG.bundle: 
        LOG.bundle: Update ID: 7a0b4d6b-faad-bf9c-7a0b-4d6bfaadc0ee
    acceptance_test.go:1123: 
        LOG.cleanup: The following resources will be deleted:
        LOG.cleanup:   delete resources.pipelines.my_pipeline
        LOG.cleanup:   delete resources.schemas.test_schema
        LOG.cleanup: 
        LOG.cleanup: This action will result in the deletion of the following UC schemas. Any underlying data may be lost:
        LOG.cleanup:   delete resources.schemas.test_schema
        LOG.cleanup: 
        LOG.cleanup: This action will result in the deletion of the following Lakeflow Spark Declarative Pipelines along with the
        LOG.cleanup: Streaming Tables (STs) and Materialized Views (MVs) managed by them. Set 'cascade_on_destroy: false' on a pipeline to retain datasets on pipeline deletion:
        LOG.cleanup:   delete resources.pipelines.my_pipeline
        LOG.cleanup: 
        LOG.cleanup: All files and directories at the following location will be deleted: /Workspace/Users/tester@databricks.com/.bundle/test-pipeline-run-flags/eseuu6akyjgwvkf5dby32vksme
        LOG.cleanup: 
        LOG.cleanup: Destroy: 2 deleted
    acceptance_test.go:1123: 
        LOG.run: Recommendation: This command runs the last deployed version of the code
        LOG.run: 
        LOG.run: If you've made local changes, run 'databricks pipelines deploy' first to ensure they are included.
        LOG.run: 
        LOG.run: Update URL: http://127.0.0.1:35725/#joblist/pipelines/7a0b4d6b-abef-4ccd-7a0b-4d6babef4dcc/updates/7a0b4d6b-f2f7-6d33-7a0b-4d6bf2f76e52
        LOG.run: 
        LOG.run: Update ID: 7a0b4d6b-f2f7-6d33-7a0b-4d6bf2f76e52
        LOG.run: 
        LOG.run: Update for pipeline completed successfully.
        LOG.run: 
        LOG.run: Pipeline configurations for this update:
        LOG.run: • Refreshed [../pipeline_file.py]
    acceptance_test.go:1123: 
        LOG.run.checked: Recommendation: This command runs the last deployed version of the code
        LOG.run.checked: 
        LOG.run.checked: If you've made local changes, run 'databricks pipelines deploy' first to ensure they are included.
        LOG.run.checked: 
        LOG.run.checked: Update URL: http://127.0.0.1:35725/#joblist/pipelines/7a0b4d6b-abef-4ccd-7a0b-4d6babef4dcc/updates/7a0b4d6b-f2f7-6d33-7a0b-4d6bf2f76e52
        LOG.run.checked: 
        LOG.run.checked: Update ID: 7a0b4d6b-f2f7-6d33-7a0b-4d6bf2f76e52
        LOG.run.checked: 
        LOG.run.checked: Update for pipeline completed successfully.
        LOG.run.checked: 
        LOG.run.checked: Pipeline configurations for this update:
        LOG.run.checked: • Refreshed [../pipeline_file.py]
FAIL

latest (v1.24.0):

acceptance_test.go:1345: Diff:
        --- pipelines/run/refresh-flags/output.txt
        +++ /tmp/TestAcceptpipelinesrunrefresh-flags1663893326/002/output.txt
        @@ -80,7 +80,7 @@
         
         === Refreshing tables defined in a source file
         >>> run_pipeline --refresh pipeline_file.py
        -• Refreshed tables defined in [/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/pipeline_file.py]
        +• Refreshed [pipeline_file.py]
         
         >>> print_requests.py //pipelines
         {
        @@ -88,15 +88,15 @@
           "path": "/api/2.0/pipelines/[UUID]/updates",
           "body": {
             "development": true,
        -    "refresh_selection_by_path": [
        -      "/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/pipeline_file.py"
        +    "refresh_selection": [
        +      "pipeline_file.py"
             ]
           }
         }
         
         === Fully refreshing tables defined in a source file
         >>> run_pipeline --full-refresh pipeline_file.py
        -• Full refreshed tables defined in [/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/pipeline_file.py]
        +• Full refreshed [pipeline_file.py]
         
         >>> print_requests.py //pipelines
         {
        @@ -104,15 +98,15 @@
           "path": "/api/2.0/pipelines/[UUID]/updates",
           "body": {
             "development": true,
        -    "full_refresh_selection_by_path": [
        -      "/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/pipeline_file.py"
        +    "full_refresh_selection": [
        +      "pipeline_file.py"
             ]
           }
         }
         
         === Refreshing a source notebook
         >>> run_pipeline --refresh src/pipeline_notebook.sql
        -• Refreshed tables defined in [/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/src/pipeline_notebook]
        +• Refreshed [src/pipeline_notebook.sql]
         
         >>> print_requests.py //pipelines
         {
        @@ -120,15 +108,15 @@
           "path": "/api/2.0/pipelines/[UUID]/updates",
           "body": {
             "development": true,
        -    "refresh_selection_by_path": [
        -      "/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/src/pipeline_notebook"
        +    "refresh_selection": [
        +      "src/pipeline_notebook.sql"
             ]
           }
         }
         
         === Refreshing an absolute workspace path
         >>> run_pipeline --refresh /Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/pipeline_file.py
        -• Refreshed tables defined in [/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/pipeline_file.py]
        +• Refreshed [/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/pipeline_file.py]
         
         >>> print_requests.py //pipelines
         {
        @@ -136,7 +118,7 @@
           "path": "/api/2.0/pipelines/[UUID]/updates",
           "body": {
             "development": true,
        -    "refresh_selection_by_path": [
        +    "refresh_selection": [
               "/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/pipeline_file.py"
             ]
           }
        @@ -144,7 +126,7 @@
         
         === Refreshing from a subdirectory
         >>> withdir src run_pipeline --refresh ../pipeline_file.py
        -• Refreshed tables defined in [/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/pipeline_file.py]
        +• Refreshed [../pipeline_file.py]
         
         >>> print_requests.py //pipelines
         {
        @@ -152,8 +134,8 @@
           "path": "/api/2.0/pipelines/[UUID]/updates",
           "body": {
             "development": true,
        -    "refresh_selection_by_path": [
        -      "/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/pipeline_file.py"
        +    "refresh_selection": [
        +      "../pipeline_file.py"
             ]
           }
         }
        @@ -165,37 +147,30 @@
           "path": "/api/2.0/pipelines/[UUID]/updates",
           "body": {
             "development": true,
        -    "full_refresh_selection_by_path": [
        -      "/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/src/pipeline_notebook"
        +    "full_refresh_selection": [
        +      "src/pipeline_notebook.sql"
             ],
        -    "refresh_selection_by_path": [
        -      "/Workspace/Users/[USERNAME]/.bundle/test-pipeline-run-flags/[UNIQUE_NAME]/files/pipeline_file.py"
        +    "refresh_selection": [
        +      "pipeline_file.py"
             ]
           }
         }
         
         === Rejecting missing sources and incompatible refresh modes
         >>> musterr [CLI] pipelines run --refresh ./missing.sql --no-wait
        -Error: invalid --refresh: source file "./missing.sql" not found; use a table name or an existing source file
        +Recommendation: This command runs the last deployed version of the code
         
        ->>> musterr [CLI] pipelines run --refresh pipeline_file.py --full-refresh-all --no-wait
        -Error: cannot use --refresh or --full-refresh together with --full-refresh-all, these flags are mutually exclusive
        +If you've made local changes, run 'databricks pipelines deploy' first to ensure they are included.
         
        ->>> musterr [CLI] pipelines run --full-refresh ./missing.sql --restart --no-wait
        -Error: invalid --full-refresh: source file "./missing.sql" not found; use a table name or an existing source file
        +Update URL: [DATABRICKS_URL]/#joblist/pipelines/[UUID]/updates/[UUID]
         
        ->>> print_requests.py //pipelines
        +Update ID: [UUID]
         
        -=== Rejecting mixed selectors before restarting the pipeline
        ->>> musterr [CLI] pipelines run --refresh table1,pipeline_file.py --restart --no-wait
        -Error: cannot mix table names and source files in --refresh; use only table names or only source files
        +Update for pipeline completed successfully.
         
        ->>> musterr [CLI] pipelines run --full-refresh table2,pipeline_file.py --restart --no-wait
        -Error: cannot mix table names and source files in --full-refresh; use only table names or only source files
        +Pipeline configurations for this update:
        +• Refreshed [./missing.sql]
         
        ->>> print_requests.py //pipelines
        +Unexpected success
         
        ->>> musterr [CLI] bundle run my_pipeline --refresh table1,pipeline_file.py --restart --no-wait
        -Error: cannot mix table names and source files in --refresh; use only table names or only source files
        -
        ->>> print_requests.py //pipelines
        +Exit code: 1
        
    acceptance_test.go:1123: 
        LOG.bundle: 
        LOG.bundle: >>> /home/runner/work/cli/cli/acceptance/build/linux_amd64/1.24.0/databricks bundle run my_pipeline --refresh pipeline_file.py --full-refresh src/pipeline_notebook.sql
        LOG.bundle: Update URL: http://127.0.0.1:45749/#joblist/pipelines/7a0b4d6c-b470-94df-7a0b-4d6cb470968a/updates/7a0b4d6d-10a0-8b80-7a0b-4d6d10a08cc5
        LOG.bundle: 
        LOG.bundle: Update ID: 7a0b4d6d-10a0-8b80-7a0b-4d6d10a08cc5
    acceptance_test.go:1123: 
        LOG.cleanup: The following resources will be deleted:
        LOG.cleanup:   delete resources.pipelines.my_pipeline
        LOG.cleanup:   delete resources.schemas.test_schema
        LOG.cleanup: 
        LOG.cleanup: This action will result in the deletion of the following UC schemas. Any underlying data may be lost:
        LOG.cleanup:   delete resources.schemas.test_schema
        LOG.cleanup: 
        LOG.cleanup: This action will result in the deletion of the following Lakeflow Spark Declarative Pipelines along with the
        LOG.cleanup: Streaming Tables (STs) and Materialized Views (MVs) managed by them. Set 'cascade_on_destroy: false' on a pipeline to retain datasets on pipeline deletion:
        LOG.cleanup:   delete resources.pipelines.my_pipeline
        LOG.cleanup: 
        LOG.cleanup: All files and directories at the following location will be deleted: /Workspace/Users/tester@databricks.com/.bundle/test-pipeline-run-flags/z6sinoqerfcvzfetwa444sy5zu
        LOG.cleanup: 
        LOG.cleanup: Destroy: 2 deleted
    acceptance_test.go:1123: 
        LOG.run: Recommendation: This command runs the last deployed version of the code
        LOG.run: 
        LOG.run: If you've made local changes, run 'databricks pipelines deploy' first to ensure they are included.
        LOG.run: 
        LOG.run: Update URL: http://127.0.0.1:45749/#joblist/pipelines/7a0b4d6c-b470-94df-7a0b-4d6cb470968a/updates/7a0b4d6d-03a6-cf60-7a0b-4d6d03a6d094
        LOG.run: 
        LOG.run: Update ID: 7a0b4d6d-03a6-cf60-7a0b-4d6d03a6d094
        LOG.run: 
        LOG.run: Update for pipeline completed successfully.
        LOG.run: 
        LOG.run: Pipeline configurations for this update:
        LOG.run: • Refreshed [../pipeline_file.py]
    acceptance_test.go:1123: 
        LOG.run.checked: Recommendation: This command runs the last deployed version of the code
        LOG.run.checked: 
        LOG.run.checked: If you've made local changes, run 'databricks pipelines deploy' first to ensure they are included.
        LOG.run.checked: 
        LOG.run.checked: Update URL: http://127.0.0.1:45749/#joblist/pipelines/7a0b4d6c-b470-94df-7a0b-4d6cb470968a/updates/7a0b4d6d-03a6-cf60-7a0b-4d6d03a6d094
        LOG.run.checked: 
        LOG.run.checked: Update ID: 7a0b4d6d-03a6-cf60-7a0b-4d6d03a6d094
        LOG.run.checked: 
        LOG.run.checked: Update for pipeline completed successfully.
        LOG.run.checked: 
        LOG.run.checked: Pipeline configurations for this update:
        LOG.run.checked: • Refreshed [../pipeline_file.py]
FAIL

@chenyuem-db
chenyuem-db force-pushed the chenyuem-db/pipeline-refresh-by-file branch from ae8800b to 9fd46d5 Compare October 28, 2026 22:30
@chenyuem-db
chenyuem-db marked this pull request as ready for review October 29, 2026 22:08
@chenyuem-db
chenyuem-db force-pushed the chenyuem-db/pipeline-refresh-by-file branch from 9fd46d5 to e092a9c Compare November 1, 2026 22:44
@chenyuem-db
chenyuem-db force-pushed the chenyuem-db/pipeline-refresh-by-file branch from e092a9c to 9d78b59 Compare November 1, 2026 22:53
trace print_requests.py //pipelines

title "Refreshing tables defined in a source file"
trace $CLI pipelines run --refresh pipeline_file.py

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to double check: did you run this against a real workspace? The description says no live refresh was performed and the fake server only echoes the request back, so nothing here confirms the API accepts paths in this form (/Workspace/... prefix, notebook extension stripped). Could you try --refresh pipeline_file.py and a notebook manually and share the result, or make this test Cloud = true?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ran this on staging with both a Python file and a SQL notebook, and both worked. I also enabled Cloud = true for this test.


This comment was generated with GitHub MCP.

return fmt.Errorf("cannot use --refresh or --full-refresh together with %s, these flags are mutually exclusive", strings.Join(mutuallyExclusiveFlags, ""))
}

// The API ignores file selections when table names are supplied for the same refresh mode.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it documented somewhere that the API ignores the by-path selection when table names are present? The SDK docs for refresh_selection_by_path don't mention it. If it's a real API limitation let's link it here, otherwise I'd rather not restrict mixing in the CLI.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked the backend, and it uses the table selection when both are set for the same refresh mode. I kept the check so we don’t silently ignore the files.


This comment was generated with GitHub MCP.

// List of tables to update.
Refresh []string

RefreshByPath []string

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These fields are only ever set from cmd/pipelines/run.go; bundle run --refresh (see Define below) still only takes table names. Do we want bundle run to support files too? The header of cmd/pipelines/run.go asks to keep both in sync.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, bundle run should support files too. Both commands now use the same resolver in bundle/run.


This comment was generated with GitHub MCP.

trace print_requests.py //pipelines

title "Fully refreshing tables defined in a source file"
trace $CLI pipelines run --full-refresh pipeline_file.py

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also cover a notebook (extension stripped), an absolute /Workspace/ path and running from a subdirectory here? Only pipeline_file.py from the bundle root is exercised end-to-end, the rest is unit tests only.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added all three cases to this test: a notebook, an absolute /Workspace/ path, and running from a subdirectory.


This comment was generated with GitHub MCP.

Comment thread cmd/pipelines/run.go Outdated
if err != nil {
return fmt.Errorf("invalid --full-refresh: %w", err)
}
if err := runOptions.Pipeline.Validate(nil); err != nil {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toPayload already calls Validate, so this runs twice; I assume it's here so --restart fails before stopping the pipeline. Worth a comment, or move it into Restart so bundle run --restart gets the same behaviour?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is to catch invalid input before stopping the pipeline. I added a short comment and made sure bundle run --restart does the same.


This comment was generated with GitHub MCP.

remoteRoot = filepath.ToSlash(b.SyncRootPath)
}
if strings.Contains(remoteRoot, "${") {
return nil, nil, fmt.Errorf("cannot resolve the deployed path for %q; use its absolute /Workspace/ path", selector)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In immutable mode this means every local file selector fails and the user has to find the snapshot path by hand, and we don't print it anywhere. The snapshot's full_path is in the deployment state, can we resolve it from there instead of erroring? Or is this fine for the first version?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This now reads the deployed snapshot path from state using the existing ResolveConfigAgainstState helper. I added a test for both refresh flags.


This comment was generated with GitHub MCP.

Comment thread cmd/pipelines/refresh.go Outdated
}
return nil, nil, fmt.Errorf("source file %q is excluded from bundle sync; include it and run 'databricks pipelines deploy' first", selector)
}
remoteRoot := b.Config.Workspace.FilePath

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the third copy of the "which remote root" rule: applyTranslations in bundle/config/mutator/translate_paths.go:323-340 and lookup in bundle/config/mutator/resolve_variable_references.go:114-119 do the same switch. Can we extract a helper on *bundle.Bundle and use it in all three places?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved this into Bundle.RemoteFilePath() and updated all three call sites to use it.


This comment was generated with GitHub MCP.

}

// refreshSourcePaths uses the sync mapping so notebook names and sync exclusions match deployment.
func refreshSourcePaths(ctx context.Context, b *bundle.Bundle) (map[string]string, error) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

listSyncableRelPaths in bundle/config/mutator/resolve_job_run_file_triggers.go:80 builds the same file list from the same inputs. Could you reuse it (or share one helper) instead of a second copy?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both now use Bundle.GetSyncFiles() to build the file list.


This comment was generated with GitHub MCP.

func resolveRefreshSelectors(ctx context.Context, b *bundle.Bundle, selectors []string) (tables, paths []string, err error) {
var remoteNames map[string]string
for _, selector := range selectors {
if strings.HasPrefix(selector, "/Workspace/") {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have libraries.IsWorkspacePath (bundle/libraries/path.go:24) which also accepts /Users/ and /Shared/. Is accepting only /Workspace/ here intentional (because /Users/... is a real local path on macOS)? If so, worth a comment.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that’s intentional because /Users/... can be a local path on macOS. I added a comment here.


This comment was generated with GitHub MCP.

Comment thread cmd/pipelines/refresh.go Outdated
return nil, nil, fmt.Errorf("source file %q is outside the bundle sync root", selector)
}
if remoteNames == nil {
remoteNames, err = refreshSourcePaths(ctx, b)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: resolveRefreshSelectors is called once per flag, so with files in both --refresh and --full-refresh we walk the sync tree twice. Could the mapping be computed once and passed in?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The two flags now reuse the same mapping, so we only scan the files once.


This comment was generated with GitHub MCP.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-assisted DABs DABs related issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants