From fdaa671418a54acf5e9f8a1119b1fc2fe150cbd6 Mon Sep 17 00:00:00 2001 From: Eric Wang Date: Thu, 23 Jul 2026 13:34:40 -0700 Subject: [PATCH 1/6] ci: dispatch coverage-fanout to databricks-driver-test on merged source PRs Wires databricks-sql-nodejs into the multi-language coverage fan-out. When a PR merges to main and touched driver source (a file under lib/), dispatch a `coverage-fanout` repository_dispatch to databricks/databricks-driver-test. Its coverage-fanout-tracker.yml then opens a tracking issue and runs the language-agnostic fan-out (a spec authored from this PR's diff, conformed across every driver). - Adds `closed` to the pull_request trigger types; the new trigger-coverage-fanout job gates on pull_request.merged == true. - Source-path filter (lib/): docs/CI/test-only merges don't warrant a full fan-out. - Reuses the existing INTEGRATION_TEST App token (scoped to driver-test) + the same peter-evans/repository-dispatch pin adbc-drivers/databricks uses. - Tightens skip-integration-tests-pr's guard to exclude `closed` so it doesn't re-stamp a check on merged PRs. Co-authored-by: Isaac Signed-off-by: Eric Wang --- .../workflows/trigger-integration-tests.yml | 58 ++++++++++++++++++- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/.github/workflows/trigger-integration-tests.yml b/.github/workflows/trigger-integration-tests.yml index 16fd1631..f6814971 100644 --- a/.github/workflows/trigger-integration-tests.yml +++ b/.github/workflows/trigger-integration-tests.yml @@ -22,7 +22,7 @@ name: Trigger Integration Tests on: pull_request: - types: [opened, synchronize, reopened, labeled] + types: [opened, synchronize, reopened, labeled, closed] merge_group: jobs: @@ -93,7 +93,7 @@ jobs: }); skip-integration-tests-pr: - if: github.event_name == 'pull_request' && github.event.action != 'labeled' + if: github.event_name == 'pull_request' && github.event.action != 'labeled' && github.event.action != 'closed' runs-on: group: databricks-protected-runner-group labels: linux-ubuntu-latest @@ -292,3 +292,57 @@ jobs: summary: 'An error occurred while dispatching Node.js integration tests. Check this workflow run for details.' } }); + + # ============================================================================= + # After merge: trigger the multi-language coverage fan-out. + # Fires when a PR lands on main (merge queue or direct merge) and touched + # driver source. Dispatches `coverage-fanout` to databricks-driver-test, whose + # coverage-fanout-tracker.yml opens a tracking issue and runs the + # language-agnostic fan-out (a spec authored from THIS PR's diff, conformed as + # tests across every driver) as peco-engineer-bot. + # ============================================================================= + trigger-coverage-fanout: + if: | + github.event_name == 'pull_request' && + github.event.action == 'closed' && + github.event.pull_request.merged == true + runs-on: + group: databricks-protected-runner-group + labels: linux-ubuntu-latest + steps: + - name: Check if driver source changed + id: changed + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # pinned + with: + script: | + const files = await github.paginate(github.rest.pulls.listFiles, { + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.payload.pull_request.number, + per_page: 100, + }); + // The whole repo IS the driver. Count a merge as source-affecting when it changes a file under lib/. + // Docs/CI/test-only merges do not warrant a full multi-language fan-out. + const isSource = (f) => f.startsWith('lib/'); + const srcChanged = files.some((f) => isSource(f.filename)); + console.log(`driver source changed: ${srcChanged}`); + core.setOutput('source', srcChanged.toString()); + + - name: Generate GitHub App token (databricks-driver-test) + if: steps.changed.outputs.source == 'true' + id: app-token + uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # pinned + with: + app-id: ${{ secrets.INTEGRATION_TEST_APP_ID }} + private-key: ${{ secrets.INTEGRATION_TEST_PRIVATE_KEY }} + owner: databricks + repositories: databricks-driver-test + + - name: Dispatch coverage-fanout + if: steps.changed.outputs.source == 'true' + uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # v3.0.0 + with: + token: ${{ steps.app-token.outputs.token }} + repository: databricks/databricks-driver-test + event-type: coverage-fanout + client-payload: '{"reference_repo": "${{ github.repository }}", "pr_number": "${{ github.event.pull_request.number }}", "pr_url": "${{ github.event.pull_request.html_url }}"}' From f53478f6b78b8d2e4042c93d34f0bbb99656bd72 Mon Sep 17 00:00:00 2001 From: Eric Wang Date: Thu, 23 Jul 2026 15:20:37 -0700 Subject: [PATCH 2/6] =?UTF-8?q?ci:=20address=20review=20=E2=80=94=20guard?= =?UTF-8?q?=20coverage-fanout=20to=20base=20main=20+=20scope=20job=20permi?= =?UTF-8?q?ssions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit peco-review-bot findings on the coverage-fanout sender (apply to all driver repos — the job is identical everywhere): - F1 (Medium): the merged-PR guard didn't constrain the base branch, so a PR merged into a release/feature branch that touched source would also dispatch a full fan-out authoring a spec from a diff that never reached main. Add `github.event.pull_request.base.ref == 'main'` to match the stated intent. - F2 (Low): the job declared no permissions block, relying on the default GITHUB_TOKEN read scope for github.rest.pulls.listFiles; if org defaults tighten to none it 403s silently. Scope it explicitly: contents: read + pull-requests: read. Co-authored-by: Isaac Signed-off-by: Eric Wang --- .github/workflows/trigger-integration-tests.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/trigger-integration-tests.yml b/.github/workflows/trigger-integration-tests.yml index f6814971..8724dffb 100644 --- a/.github/workflows/trigger-integration-tests.yml +++ b/.github/workflows/trigger-integration-tests.yml @@ -305,10 +305,14 @@ jobs: if: | github.event_name == 'pull_request' && github.event.action == 'closed' && - github.event.pull_request.merged == true + github.event.pull_request.merged == true && + github.event.pull_request.base.ref == 'main' runs-on: group: databricks-protected-runner-group labels: linux-ubuntu-latest + permissions: + contents: read + pull-requests: read steps: - name: Check if driver source changed id: changed From 61bfa0beaac80daa4c50960d9c430f14c2dd925b Mon Sep 17 00:00:00 2001 From: Eric Wang Date: Thu, 23 Jul 2026 15:37:45 -0700 Subject: [PATCH 3/6] =?UTF-8?q?ci:=20address=20review=20=E2=80=94=20narrow?= =?UTF-8?q?=20minted=20token=20+=20fix=20pin=20version=20comments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Further peco-review-bot findings on the coverage-fanout sender: - Narrow the minted App installation token with `permission-contents: write` (all coverage_fanout needs is repository_dispatch → contents:write), matching the defense-in-depth the other dispatch jobs in these repos already use — so a leaked token can only fire dispatches, not exercise the App's full scope. - Restore the version tag in two action-pin comments (`# pinned` → the exact `# vX.Y.Z` the SHA corresponds to, per repo convention) for auditability. Co-authored-by: Isaac Signed-off-by: Eric Wang --- .github/workflows/trigger-integration-tests.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/trigger-integration-tests.yml b/.github/workflows/trigger-integration-tests.yml index 8724dffb..0a6703dc 100644 --- a/.github/workflows/trigger-integration-tests.yml +++ b/.github/workflows/trigger-integration-tests.yml @@ -316,7 +316,7 @@ jobs: steps: - name: Check if driver source changed id: changed - uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # pinned + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0 with: script: | const files = await github.paginate(github.rest.pulls.listFiles, { @@ -335,12 +335,13 @@ jobs: - name: Generate GitHub App token (databricks-driver-test) if: steps.changed.outputs.source == 'true' id: app-token - uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # pinned + uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0 with: app-id: ${{ secrets.INTEGRATION_TEST_APP_ID }} private-key: ${{ secrets.INTEGRATION_TEST_PRIVATE_KEY }} owner: databricks repositories: databricks-driver-test + permission-contents: write - name: Dispatch coverage-fanout if: steps.changed.outputs.source == 'true' From ee38c1369d9569502be162ed8647fbce1a6a98b0 Mon Sep 17 00:00:00 2001 From: Eric Wang Date: Thu, 23 Jul 2026 19:04:46 -0700 Subject: [PATCH 4/6] ci: dispatch nodejs PR gate in replay mode (not live passthrough) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Send proxy_mode=replay in both dispatch payloads (the label preview and the merge-queue required gate) so the databricks-sql-nodejs PR gate runs the Node.js suite in REPLAY against the PR's driver commit — deterministic, credential-free, no live warehouse — instead of the live passthrough run it does today. Paired with the driver-test receiver change (databricks-driver-test#909) that adds proxy_mode=replay to databricks-sql-nodejs-integration-tests.yml and skips the recording-less reyden leg in replay. Both must merge for the gate to run replay; until #909 lands the receiver ignores proxy_mode (stays passthrough). Co-authored-by: Isaac Signed-off-by: Eric Wang --- .github/workflows/trigger-integration-tests.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/trigger-integration-tests.yml b/.github/workflows/trigger-integration-tests.yml index 0a6703dc..e7dbd680 100644 --- a/.github/workflows/trigger-integration-tests.yml +++ b/.github/workflows/trigger-integration-tests.yml @@ -175,7 +175,8 @@ jobs: "pr_repo": "${{ github.repository }}", "pr_url": "${{ github.event.pull_request.html_url }}", "pr_title": "${{ steps.sanitize.outputs.result }}", - "pr_author": "${{ github.event.pull_request.user.login }}" + "pr_author": "${{ github.event.pull_request.user.login }}", + "proxy_mode": "replay" } - name: Fail check on dispatch error @@ -270,7 +271,8 @@ jobs: "pr_repo": "${{ github.repository }}", "pr_url": "${{ github.server_url }}/${{ github.repository }}/pull/${{ steps.extract-pr.outputs.pr_number }}", "pr_title": "Merge queue validation", - "pr_author": "merge-queue" + "pr_author": "merge-queue", + "proxy_mode": "replay" } - name: Fail check on dispatch error From 15ab3eb0ac4f0b24ac072c700efb4e0aa4393680 Mon Sep 17 00:00:00 2001 From: eric-wang-1990 Date: Fri, 24 Jul 2026 00:04:55 -0700 Subject: [PATCH 5/6] ci: fix dead driver-test workflow link in dispatch comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "Node.js integration tests triggered" PR comment linked to databricks-nodejs-integration-tests.yml, which does not exist (404) — the receiver file is databricks-sql-nodejs-integration-tests.yml. Point to the correct workflow and note that the authoritative result is the "Node.js Integration Tests" check posted back on the PR. Co-authored-by: Isaac Signed-off-by: eric-wang-1990 --- .github/workflows/trigger-integration-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/trigger-integration-tests.yml b/.github/workflows/trigger-integration-tests.yml index e7dbd680..c59222bb 100644 --- a/.github/workflows/trigger-integration-tests.yml +++ b/.github/workflows/trigger-integration-tests.yml @@ -208,7 +208,7 @@ jobs: owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, - body: 'Node.js integration tests triggered. [View workflow run](https://github.com/databricks/databricks-driver-test/actions/workflows/databricks-nodejs-integration-tests.yml).' + body: 'Node.js integration tests triggered. [View workflow runs](https://github.com/databricks/databricks-driver-test/actions/workflows/databricks-sql-nodejs-integration-tests.yml). The result posts back here as the "Node.js Integration Tests" check.' }); merge-queue-nodejs: From 6fdff861a5229006ed10b4b95149fec99dc311c3 Mon Sep 17 00:00:00 2001 From: eric-wang-1990 Date: Fri, 24 Jul 2026 10:20:40 -0700 Subject: [PATCH 6/6] ci: broaden coverage-fanout source filter beyond lib/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The isSource predicate only matched lib/, but driver source also lives at native/ (kernel bindings), thrift/ (Thrift defs), and the KERNEL_REV pin. A merged PR that only bumped KERNEL_REV or edited native/ or thrift/ would report srcChanged=false and never dispatch coverage-fanout, even though it affects the Thrift/kernel backends — the same gap the "run on every change" comments in this workflow already document. Include those roots. Co-authored-by: Isaac Signed-off-by: eric-wang-1990 --- .github/workflows/trigger-integration-tests.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/trigger-integration-tests.yml b/.github/workflows/trigger-integration-tests.yml index c59222bb..80c7141f 100644 --- a/.github/workflows/trigger-integration-tests.yml +++ b/.github/workflows/trigger-integration-tests.yml @@ -327,9 +327,13 @@ jobs: pull_number: context.payload.pull_request.number, per_page: 100, }); - // The whole repo IS the driver. Count a merge as source-affecting when it changes a file under lib/. - // Docs/CI/test-only merges do not warrant a full multi-language fan-out. - const isSource = (f) => f.startsWith('lib/'); + // The whole repo IS the driver. Count a merge as source-affecting when it changes driver + // source: lib/ (JS/TS), native/ (kernel bindings), thrift/ (Thrift defs), or the KERNEL_REV + // pin. Docs/CI/test-only merges do not warrant a full multi-language fan-out. (Matches the + // source roots called out in the "run on every change" comments above — a merge that only + // bumps KERNEL_REV or edits native/ or thrift/ still affects the Thrift/kernel backends.) + const isSource = (f) => + f.startsWith('lib/') || f.startsWith('native/') || f.startsWith('thrift/') || f === 'KERNEL_REV'; const srcChanged = files.some((f) => isSource(f.filename)); console.log(`driver source changed: ${srcChanged}`); core.setOutput('source', srcChanged.toString());