Skip to content

Commit bcc0175

Browse files
authored
Trigger driver-test integration workflow (#402)
* Add driver-test integration workflow trigger Dispatch Node.js PR and merge-queue validations to databricks-driver-test so proxy-based integration tests can run with internal credentials. Signed-off-by: Madhavendra Rathore <madhavendra.rathore@databricks.com> * Document Node.js integration workflow setup Call out the GitHub App grants and required check configuration needed for driver-test dispatch and status reporting. Signed-off-by: Madhavendra Rathore <madhavendra.rathore@databricks.com> --------- Signed-off-by: Madhavendra Rathore <madhavendra.rathore@databricks.com>
1 parent 5413ff9 commit bcc0175

1 file changed

Lines changed: 363 additions & 0 deletions

File tree

Lines changed: 363 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,363 @@
1+
name: Trigger Integration Tests
2+
3+
# Dispatches the proxy-based Node.js integration suite in
4+
# databricks/databricks-driver-test to run against this PR's commit.
5+
#
6+
# Matches the label-gated / merge-queue pattern used by the Python connector:
7+
# normal PR events get an immediate green check, maintainers can preview with
8+
# the `integration-test` label, and merge queue runs the real required gate.
9+
#
10+
# Required external setup:
11+
#
12+
# 1. `integration-test` label exists in this repo.
13+
# 2. `INTEGRATION_TEST_APP_ID` / `INTEGRATION_TEST_PRIVATE_KEY` repo secrets
14+
# are installed in this repo for the dispatcher GitHub App.
15+
# 3. The app is installed/granted on `databricks-driver-test` so this workflow
16+
# can send `repository_dispatch`.
17+
# 4. The same app is installed/granted on `databricks-sql-nodejs` with
18+
# checks:write so driver-test can report the final `Node.js Integration
19+
# Tests` check back to this PR/merge-queue commit.
20+
# 5. Merge queue branch protection lists `Node.js Integration Tests` as a
21+
# required status check.
22+
23+
on:
24+
pull_request:
25+
types: [opened, synchronize, reopened, labeled]
26+
merge_group:
27+
28+
jobs:
29+
remove-label-on-new-commit:
30+
if: github.event_name == 'pull_request' && github.event.action == 'synchronize'
31+
runs-on:
32+
group: databricks-protected-runner-group
33+
labels: linux-ubuntu-latest
34+
permissions:
35+
pull-requests: write
36+
issues: write
37+
steps:
38+
- name: Check if integration-test label exists
39+
id: check-label
40+
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
41+
with:
42+
script: |
43+
const labels = context.payload.pull_request.labels.map((label) => label.name);
44+
const hasLabel = labels.includes('integration-test');
45+
console.log(`integration-test label exists: ${hasLabel}`);
46+
return hasLabel;
47+
48+
- name: Remove integration-test label
49+
if: steps.check-label.outputs.result == 'true'
50+
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
51+
with:
52+
script: |
53+
try {
54+
await github.rest.issues.removeLabel({
55+
owner: context.repo.owner,
56+
repo: context.repo.repo,
57+
issue_number: context.issue.number,
58+
name: 'integration-test'
59+
});
60+
console.log('Removed integration-test label');
61+
} catch (error) {
62+
if (error.status === 404) {
63+
console.log('Label already removed or does not exist');
64+
} else {
65+
throw error;
66+
}
67+
}
68+
69+
- name: Comment on PR about label removal
70+
if: steps.check-label.outputs.result == 'true'
71+
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
72+
with:
73+
script: |
74+
const pr = context.payload.pull_request;
75+
const isFromFork = pr.head.repo.full_name !== pr.base.repo.full_name;
76+
const repoType = isFromFork ? '**fork PR**' : 'PR';
77+
78+
const body = [
79+
'Integration test approval reset.',
80+
'',
81+
`New commits were pushed to this ${repoType}. The \`integration-test\` label has been automatically removed for security.`,
82+
'',
83+
'**A maintainer must re-review the changes and re-add the label to trigger tests again.**',
84+
'',
85+
`Latest commit: ${pr.head.sha.substring(0, 7)}`
86+
].join('\n');
87+
88+
await github.rest.issues.createComment({
89+
owner: context.repo.owner,
90+
repo: context.repo.repo,
91+
issue_number: context.issue.number,
92+
body
93+
});
94+
95+
skip-integration-tests-pr:
96+
if: github.event_name == 'pull_request' && github.event.action != 'labeled'
97+
runs-on:
98+
group: databricks-protected-runner-group
99+
labels: linux-ubuntu-latest
100+
permissions:
101+
checks: write
102+
steps:
103+
- name: Skip Node.js Integration Tests
104+
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
105+
with:
106+
github-token: ${{ github.token }}
107+
script: |
108+
await github.rest.checks.create({
109+
owner: context.repo.owner,
110+
repo: context.repo.repo,
111+
name: 'Node.js Integration Tests',
112+
head_sha: context.payload.pull_request.head.sha,
113+
status: 'completed',
114+
conclusion: 'success',
115+
completed_at: new Date().toISOString(),
116+
output: {
117+
title: 'Skipped on PR - runs in merge queue',
118+
summary: 'Node.js integration tests are skipped on ordinary PR events and run as a required gate in the merge queue. Add the `integration-test` label to preview them on this PR.'
119+
}
120+
});
121+
122+
trigger-tests-pr:
123+
if: |
124+
github.event_name == 'pull_request' &&
125+
github.event.action == 'labeled' &&
126+
contains(github.event.pull_request.labels.*.name, 'integration-test')
127+
runs-on:
128+
group: databricks-protected-runner-group
129+
labels: linux-ubuntu-latest
130+
permissions:
131+
issues: write
132+
pull-requests: write
133+
checks: write
134+
steps:
135+
- name: Detect changed driver paths
136+
id: changed
137+
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
138+
with:
139+
script: |
140+
const { data: files } = await github.rest.pulls.listFiles({
141+
owner: context.repo.owner,
142+
repo: context.repo.repo,
143+
pull_number: context.payload.pull_request.number,
144+
per_page: 100
145+
});
146+
147+
const names = files.map((file) => file.filename);
148+
const sourceChanged = names.some((file) =>
149+
file.startsWith('bin/') ||
150+
file.startsWith('lib/') ||
151+
file.startsWith('spec/') ||
152+
file.startsWith('thrift/') ||
153+
file.startsWith('tests/e2e/') ||
154+
file.startsWith('tests/integration/') ||
155+
file === 'package.json' ||
156+
file === 'package-lock.json' ||
157+
file === 'tsconfig.json' ||
158+
file === 'tsconfig.build.json'
159+
);
160+
const workflowChanged = names.some((file) => file.startsWith('.github/workflows/'));
161+
const runNode = sourceChanged || workflowChanged;
162+
163+
if (workflowChanged) console.log('Workflow files changed - triggering Node.js integration tests');
164+
if (sourceChanged) console.log('Driver source files changed - triggering Node.js integration tests');
165+
core.setOutput('nodejs', runNode.toString());
166+
167+
- name: Generate GitHub App Token (driver-test repo)
168+
id: app-token
169+
if: steps.changed.outputs.nodejs == 'true'
170+
uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0
171+
with:
172+
app-id: ${{ secrets.INTEGRATION_TEST_APP_ID }}
173+
private-key: ${{ secrets.INTEGRATION_TEST_PRIVATE_KEY }}
174+
owner: databricks
175+
repositories: databricks-driver-test
176+
177+
- name: Sanitize PR title
178+
id: sanitize
179+
if: steps.changed.outputs.nodejs == 'true'
180+
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
181+
with:
182+
result-encoding: string
183+
script: |
184+
const title = context.payload.pull_request.title || '';
185+
return title.replace(/[\\"\n\r\t]/g, ' ').substring(0, 200);
186+
187+
- name: Dispatch Node.js tests to driver-test
188+
if: steps.changed.outputs.nodejs == 'true'
189+
uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # v3.0.0
190+
with:
191+
token: ${{ steps.app-token.outputs.token }}
192+
repository: databricks/databricks-driver-test
193+
event-type: nodejs-pr-test
194+
client-payload: |
195+
{
196+
"pr_number": "${{ github.event.pull_request.number }}",
197+
"commit_sha": "${{ github.event.pull_request.head.sha }}",
198+
"pr_repo": "${{ github.repository }}",
199+
"pr_url": "${{ github.event.pull_request.html_url }}",
200+
"pr_title": "${{ steps.sanitize.outputs.result }}",
201+
"pr_author": "${{ github.event.pull_request.user.login }}"
202+
}
203+
204+
- name: Pass Node.js Integration Tests check (no driver changes)
205+
if: steps.changed.outputs.nodejs != 'true'
206+
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
207+
with:
208+
github-token: ${{ github.token }}
209+
script: |
210+
await github.rest.checks.create({
211+
owner: context.repo.owner,
212+
repo: context.repo.repo,
213+
name: 'Node.js Integration Tests',
214+
head_sha: context.payload.pull_request.head.sha,
215+
status: 'completed',
216+
conclusion: 'success',
217+
completed_at: new Date().toISOString(),
218+
output: {
219+
title: 'Skipped - no driver changes',
220+
summary: 'No Node.js driver source files changed; skipping integration tests.'
221+
}
222+
});
223+
224+
- name: Fail check on dispatch error
225+
if: failure() && steps.changed.outputs.nodejs == 'true'
226+
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
227+
with:
228+
github-token: ${{ github.token }}
229+
script: |
230+
await github.rest.checks.create({
231+
owner: context.repo.owner,
232+
repo: context.repo.repo,
233+
name: 'Node.js Integration Tests',
234+
head_sha: context.payload.pull_request.head.sha,
235+
status: 'completed',
236+
conclusion: 'failure',
237+
completed_at: new Date().toISOString(),
238+
output: {
239+
title: 'Failed - error dispatching tests',
240+
summary: 'An error occurred while dispatching Node.js integration tests. Check this workflow run for details.'
241+
}
242+
});
243+
244+
- name: Comment on PR
245+
if: steps.changed.outputs.nodejs == 'true'
246+
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
247+
with:
248+
script: |
249+
await github.rest.issues.createComment({
250+
owner: context.repo.owner,
251+
repo: context.repo.repo,
252+
issue_number: context.issue.number,
253+
body: 'Node.js integration tests triggered. [View workflow run](https://github.com/databricks/databricks-driver-test/actions/workflows/databricks-nodejs-integration-tests.yml).'
254+
});
255+
256+
merge-queue-nodejs:
257+
if: github.event_name == 'merge_group'
258+
runs-on:
259+
group: databricks-protected-runner-group
260+
labels: linux-ubuntu-latest
261+
permissions:
262+
contents: read
263+
checks: write
264+
steps:
265+
- name: Checkout code
266+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
267+
with:
268+
fetch-depth: 0
269+
270+
- name: Check if driver files changed
271+
id: changed
272+
env:
273+
BASE_SHA: ${{ github.event.merge_group.base_sha }}
274+
HEAD_SHA: ${{ github.event.merge_group.head_sha }}
275+
run: |
276+
CHANGED=$(git diff --name-only "$BASE_SHA" "$HEAD_SHA")
277+
if echo "$CHANGED" | grep -qE "^(bin/|lib/|spec/|thrift/|tests/e2e/|tests/integration/|package\.json|package-lock\.json|tsconfig(\.build)?\.json|\.github/workflows/)"; then
278+
echo "changed=true" >> "$GITHUB_OUTPUT"
279+
echo "Driver files changed - will dispatch Node.js integration tests"
280+
else
281+
echo "changed=false" >> "$GITHUB_OUTPUT"
282+
echo "No driver files changed - will auto-pass"
283+
fi
284+
285+
- name: Auto-pass (no driver changes)
286+
if: steps.changed.outputs.changed != 'true'
287+
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
288+
with:
289+
github-token: ${{ github.token }}
290+
script: |
291+
await github.rest.checks.create({
292+
owner: context.repo.owner,
293+
repo: context.repo.repo,
294+
name: 'Node.js Integration Tests',
295+
head_sha: '${{ github.event.merge_group.head_sha }}',
296+
status: 'completed',
297+
conclusion: 'success',
298+
completed_at: new Date().toISOString(),
299+
output: {
300+
title: 'Skipped - no driver changes',
301+
summary: 'No Node.js driver source files changed.'
302+
}
303+
});
304+
305+
- name: Extract PR number from merge queue ref
306+
if: steps.changed.outputs.changed == 'true'
307+
id: extract-pr
308+
env:
309+
MERGE_QUEUE_REF: ${{ github.event.merge_group.head_ref }}
310+
run: |
311+
if [[ "$MERGE_QUEUE_REF" =~ pr-([0-9]+) ]]; then
312+
echo "pr_number=${BASH_REMATCH[1]}" >> "$GITHUB_OUTPUT"
313+
else
314+
echo "Error: failed to extract PR number from merge group ref: '$MERGE_QUEUE_REF'" >&2
315+
exit 1
316+
fi
317+
318+
- name: Generate GitHub App Token (driver-test repo)
319+
if: steps.changed.outputs.changed == 'true'
320+
id: app-token
321+
uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0
322+
with:
323+
app-id: ${{ secrets.INTEGRATION_TEST_APP_ID }}
324+
private-key: ${{ secrets.INTEGRATION_TEST_PRIVATE_KEY }}
325+
owner: databricks
326+
repositories: databricks-driver-test
327+
328+
- name: Dispatch Node.js tests
329+
if: steps.changed.outputs.changed == 'true'
330+
uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # v3.0.0
331+
with:
332+
token: ${{ steps.app-token.outputs.token }}
333+
repository: databricks/databricks-driver-test
334+
event-type: nodejs-pr-test
335+
client-payload: |
336+
{
337+
"pr_number": "${{ steps.extract-pr.outputs.pr_number }}",
338+
"commit_sha": "${{ github.event.merge_group.head_sha }}",
339+
"pr_repo": "${{ github.repository }}",
340+
"pr_url": "${{ github.server_url }}/${{ github.repository }}/pull/${{ steps.extract-pr.outputs.pr_number }}",
341+
"pr_title": "Merge queue validation",
342+
"pr_author": "merge-queue"
343+
}
344+
345+
- name: Fail check on dispatch error
346+
if: failure() && steps.changed.outputs.changed == 'true'
347+
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
348+
with:
349+
github-token: ${{ github.token }}
350+
script: |
351+
await github.rest.checks.create({
352+
owner: context.repo.owner,
353+
repo: context.repo.repo,
354+
name: 'Node.js Integration Tests',
355+
head_sha: '${{ github.event.merge_group.head_sha }}',
356+
status: 'completed',
357+
conclusion: 'failure',
358+
completed_at: new Date().toISOString(),
359+
output: {
360+
title: 'Failed - error dispatching tests',
361+
summary: 'An error occurred while dispatching Node.js integration tests. Check this workflow run for details.'
362+
}
363+
});

0 commit comments

Comments
 (0)