Skip to content

Commit 6a23382

Browse files
Gate Databricks CPU and GPU tests independently
## Summary Classify changed paths against the actual Databricks CPU and GPU runtime surfaces, emit separate fail-open decisions, and gate each matrix leg independently. ## Prompting Intent The engineer asked to determine exactly when Databricks tests should run, lock down the path rules, and deliver the work as a stacked pull request above PR #2581. ## Linked Sources - Base CI hardening PR: #2581 - GitHub stacked PR documentation: https://docs.github.com/en/pull-requests/how-tos/create-pull-requests/creating-stacked-pull-requests - ADO timing audit: build 229176406 ## Rationale CPU and GPU decisions are separated because most module changes cannot affect the expensive GPU notebooks. Unknown paths and shared build or test infrastructure remain fail-open, while explicit test-only and unrelated tooling paths skip safely. This preserves coverage while avoiding unrelated GPU capacity waits. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent b495cac commit 6a23382

6 files changed

Lines changed: 342 additions & 109 deletions

File tree

pipeline.yaml

Lines changed: 53 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ jobs:
106106
fetchDepth: 1
107107
- bash: |
108108
set -uo pipefail
109-
run_databricks=true
109+
run_databricks_cpu=true
110+
run_databricks_gpu=true
110111
111112
if [ "$(Build.Reason)" = "PullRequest" ]; then
112113
target_ref="${SYSTEM_PULLREQUEST_TARGETBRANCH:-}"
@@ -119,15 +120,27 @@ jobs:
119120
# effective PR diff. A source-only checkout can only over-report
120121
# target changes, which safely keeps Databricks enabled.
121122
echo "Changed paths used for Databricks E2E impact detection:"
122-
git diff --name-only --diff-filter=ACMRD "$target_commit" HEAD | sed 's/^/ /'
123-
decision="$(
124-
git diff --name-only -z --diff-filter=ACMRD "$target_commit" HEAD |
125-
python3 tools/ci/databricks_impact.py --null
123+
changed_paths_file="$(mktemp)"
124+
trap 'rm -f "$changed_paths_file"' EXIT
125+
git diff --name-only -z --diff-filter=ACMRD "$target_commit" HEAD > "$changed_paths_file"
126+
tr '\0' '\n' < "$changed_paths_file" | sed 's/^/ /'
127+
128+
cpu_decision="$(
129+
python3 tools/ci/databricks_impact.py --null --suite cpu < "$changed_paths_file"
130+
)"
131+
gpu_decision="$(
132+
python3 tools/ci/databricks_impact.py --null --suite gpu < "$changed_paths_file"
126133
)"
127-
case "$decision" in
128-
true|false) run_databricks="$decision" ;;
134+
case "$cpu_decision" in
135+
true|false) run_databricks_cpu="$cpu_decision" ;;
136+
*)
137+
echo "##vso[task.logissue type=warning]Invalid Databricks CPU impact result; running CPU E2E"
138+
;;
139+
esac
140+
case "$gpu_decision" in
141+
true|false) run_databricks_gpu="$gpu_decision" ;;
129142
*)
130-
echo "##vso[task.logissue type=warning]Invalid Databricks impact result; running E2E"
143+
echo "##vso[task.logissue type=warning]Invalid Databricks GPU impact result; running GPU E2E"
131144
;;
132145
esac
133146
else
@@ -137,8 +150,10 @@ jobs:
137150
echo "Non-PR build; Databricks E2E remains enabled"
138151
fi
139152
140-
echo "Databricks E2E enabled: $run_databricks"
141-
echo "##vso[task.setvariable variable=runDatabricksE2E;isOutput=true]$run_databricks"
153+
echo "Databricks CPU E2E enabled: $run_databricks_cpu"
154+
echo "Databricks GPU E2E enabled: $run_databricks_gpu"
155+
echo "##vso[task.setvariable variable=runDatabricksCpuE2E;isOutput=true]$run_databricks_cpu"
156+
echo "##vso[task.setvariable variable=runDatabricksGpuE2E;isOutput=true]$run_databricks_gpu"
142157
name: detectDatabricksImpact
143158
displayName: 'Detect Databricks E2E impact'
144159
- template: templates/update_cli.yml
@@ -226,14 +241,15 @@ jobs:
226241
condition: and(succeeded(), eq(variables.isMaster, true))
227242
displayName: Publish Badges
228243

229-
- job: DatabricksE2E
244+
- job: DatabricksCPUE2E
230245
dependsOn: BuildAndCacheSbt
231-
displayName: 'Databricks E2E'
246+
displayName: 'Databricks CPU E2E'
232247
condition: >-
233248
and(
234249
succeeded(),
250+
eq(variables.runTests, 'True'),
235251
eq('${{ parameters.testDatabricksE2E }}', true),
236-
eq(dependencies.BuildAndCacheSbt.outputs['detectDatabricksImpact.runDatabricksE2E'], 'true')
252+
eq(dependencies.BuildAndCacheSbt.outputs['detectDatabricksImpact.runDatabricksCpuE2E'], 'true')
237253
)
238254
timeoutInMinutes: 300
239255
cancelTimeoutInMinutes: 0
@@ -255,35 +271,31 @@ jobs:
255271
TEST-CLASS: "com.microsoft.azure.synapse.ml.nbtest.DatabricksCPUTests4"
256272
databricks-cpu-5:
257273
TEST-CLASS: "com.microsoft.azure.synapse.ml.nbtest.DatabricksCPUTests5"
258-
databricks-gpu:
259-
TEST-CLASS: "com.microsoft.azure.synapse.ml.nbtest.DatabricksGPUTests"
260-
# databricks-rapids tests have been disabled because these tests are failing.
261-
# This test will be re-enabled once the issue is fixed.
262-
# databricks-rapids:
263-
# TEST-CLASS: "com.microsoft.azure.synapse.ml.nbtest.DatabricksRapidsTests"
264274
steps:
265-
- template: templates/sbt_cache.yml
266-
- template: templates/update_cli.yml
267-
- template: templates/conda.yml
268-
- template: templates/kv.yml
269-
- template: templates/publish.yml
270-
- task: AzureCLI@2
271-
displayName: 'E2E'
272-
inputs:
273-
azureSubscription: 'SynapseML Build'
274-
scriptLocation: inlineScript
275-
scriptType: bash
276-
inlineScript: |
277-
set -e
278-
source activate synapseml
279-
sbt "testOnly $(TEST-CLASS)"
280-
condition: and(succeeded(), eq(variables.runTests, 'True'))
281-
- task: PublishTestResults@2
282-
displayName: 'Publish Test Results'
283-
inputs:
284-
testResultsFiles: '**/test-reports/TEST-*.xml'
285-
failTaskOnFailedTests: true
286-
condition: and(eq(variables.runTests, 'True'), succeededOrFailed())
275+
- template: templates/databricks_e2e_steps.yml
276+
277+
- job: DatabricksGPUE2E
278+
dependsOn: BuildAndCacheSbt
279+
displayName: 'Databricks GPU E2E'
280+
condition: >-
281+
and(
282+
succeeded(),
283+
eq(variables.runTests, 'True'),
284+
eq('${{ parameters.testDatabricksE2E }}', true),
285+
eq(dependencies.BuildAndCacheSbt.outputs['detectDatabricksImpact.runDatabricksGpuE2E'], 'true')
286+
)
287+
timeoutInMinutes: 300
288+
cancelTimeoutInMinutes: 0
289+
pool:
290+
vmImage: $(UBUNTU_VERSION)
291+
variables:
292+
TEST-CLASS: "com.microsoft.azure.synapse.ml.nbtest.DatabricksGPUTests"
293+
MML_ADB_AUTH_TYPE: "aad"
294+
MML_ADB_WORKSPACE_HOST: "adb-1885762835647850.10.azuredatabricks.net"
295+
MML_ADB_WORKSPACE_RESOURCE_ID: "/subscriptions/e342c2c0-f844-4b18-9208-52c8c234c30e/resourceGroups/marhamil-mmlspark/providers/Microsoft.Databricks/workspaces/synapseml-build-adb"
296+
# The DatabricksRapidsTests suite remains disabled until its existing failures are fixed.
297+
steps:
298+
- template: templates/databricks_e2e_steps.yml
287299

288300
- job: FabricE2E
289301
dependsOn: BuildAndCacheSbt

templates/databricks_e2e_steps.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
steps:
2+
- template: sbt_cache.yml
3+
- template: update_cli.yml
4+
- template: conda.yml
5+
- template: kv.yml
6+
- template: publish.yml
7+
- task: AzureCLI@2
8+
displayName: 'E2E'
9+
inputs:
10+
azureSubscription: 'SynapseML Build'
11+
scriptLocation: inlineScript
12+
scriptType: bash
13+
inlineScript: |
14+
set -e
15+
source activate synapseml
16+
sbt "testOnly $(TEST-CLASS)"
17+
condition: and(succeeded(), eq(variables.runTests, 'True'))
18+
- task: PublishTestResults@2
19+
displayName: 'Publish Test Results'
20+
inputs:
21+
testResultsFiles: '**/test-reports/TEST-*.xml'
22+
failTaskOnFailedTests: true
23+
condition: and(eq(variables.runTests, 'True'), succeededOrFailed())

tools/ci/README.md

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,19 +44,29 @@ sbt-running job is wired to the shared cache template + prewarm job.
4444
## `databricks_impact.py` — conservative PR E2E gating
4545

4646
The `BuildAndCacheSbt` job compares a pull request with its target branch and
47-
uses `databricks_impact.py` to decide whether the six Databricks matrix jobs can
48-
be skipped. Scheduled, master, tag, and manual builds always run Databricks.
47+
uses `databricks_impact.py` to decide independently whether the five CPU matrix
48+
jobs and the GPU matrix job can be skipped. Scheduled, master, tag, and manual
49+
builds always run both suites.
4950

50-
The detector is intentionally fail-open. It skips Databricks only when every
51-
changed path is clearly unrelated to runtime artifacts and notebook execution:
51+
The detector mirrors the enabled test suites:
52+
53+
- CPU runs for runtime changes in any module and non-GPU notebooks.
54+
- GPU runs for shared core/deep-learning runtime changes and the three
55+
`Fine-tune`/`Phi Model` notebooks selected by `DatabricksGPUTests`.
56+
- Databricks utility changes are assigned to CPU, GPU, or both according to
57+
which suite imports them.
58+
59+
The detector is fail-open. Unknown paths, build definitions, templates,
60+
environment files, shared test infrastructure, missing diffs, and detection
61+
errors run both suites. It skips both suites only for paths known not to affect
62+
runtime artifacts or notebook execution:
5263

5364
- GitHub metadata and workflows
65+
- unrelated pipelines and ACR/Docker/Helm tooling
5466
- CI helper code under `tools/ci/`
5567
- website files
5668
- Markdown/reStructuredText documentation
57-
- non-notebook files under `docs/`
5869
- module test source outside the Databricks notebook and shared test infrastructure
5970

60-
Runtime source, `.ipynb` notebooks, build definitions, pipeline/templates,
61-
Databricks test utilities, unknown paths, an empty diff, or a failed target
62-
branch fetch all keep Databricks E2E enabled.
71+
Unknown non-notebook assets under `docs/` remain fail-open because notebooks may
72+
load adjacent data or configuration files.

0 commit comments

Comments
 (0)