Skip to content

Commit 1beb5c1

Browse files
feat: Add integration test trigger workflow (#188)
## Summary This PR adds a workflow to trigger integration tests in the internal `databricks/databricks-driver-test` repository when PRs are ready to merge. ## How It Works ### PR Phase (Flexible) - Add `integration-test` label to trigger tests on any PR - Tests auto re-run on new commits if label exists - No path restrictions - can manually test any PR ### Merge Queue Phase (Efficient) - Only runs tests if relevant files changed: - `.github/workflows/trigger-integration-tests.yml` - `ci/scripts/**` - `csharp/src/**` - `csharp/test/**` - Skips duplicate runs if tests already passed on PR head - Auto-approves if no relevant files changed ## Benefits ✅ **Cost-efficient**: Only runs tests when needed ✅ **Flexible**: Can manually test any PR via label ✅ **Smart**: Avoids duplicate test runs ✅ **Guards merging**: Blocks merge if tests fail ## Setup Required This workflow requires GitHub App setup: 1. Create GitHub App with permissions: - `checks: write` (to report status on PRs) - `contents: read` (to dispatch events) - `metadata: read` 2. Install app on both repos: - `adbc-drivers/databricks` (this repo) - `databricks/databricks-driver-test` (internal test repo) 3. Add secrets to both repos: - `INTEGRATION_TEST_APP_ID` - `INTEGRATION_TEST_PRIVATE_KEY` 4. Internal repo needs matching workflow: `databricks/databricks-driver-test/.github/workflows/adbc-integration-tests.yml` (already created) 5. Enable merge queue in branch protection rules (optional but recommended) ## Testing After setup, test by: 1. Opening a test PR with C# changes 2. Add `integration-test` label 3. Verify tests trigger and report back 🤖 Generated with Claude Code --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 9319573 commit 1beb5c1

File tree

1 file changed

+290
-0
lines changed

1 file changed

+290
-0
lines changed
Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
# Copyright (c) 2025 ADBC Drivers Contributors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
name: Trigger Integration Tests
15+
on:
16+
pull_request:
17+
types: [labeled, synchronize] # Trigger on label add or new commits
18+
merge_group: # Trigger when added to merge queue
19+
jobs:
20+
# =============================================================================
21+
# For PRs: Only run if "integration-test" label exists
22+
# =============================================================================
23+
check-should-run-pr:
24+
if: github.event_name == 'pull_request'
25+
runs-on: [self-hosted, Linux, X64, peco-driver]
26+
outputs:
27+
run: ${{ steps.check.outputs.run }}
28+
steps:
29+
- name: Check for integration-test label
30+
id: check
31+
run: |
32+
if [[ "${{ contains(github.event.pull_request.labels.*.name, 'integration-test') }}" == "true" ]]; then
33+
echo "✅ integration-test label found - will trigger tests"
34+
echo "run=true" >> $GITHUB_OUTPUT
35+
else
36+
echo "⏭️ integration-test label not found - skipping tests"
37+
echo "run=false" >> $GITHUB_OUTPUT
38+
fi
39+
trigger-tests-pr:
40+
needs: check-should-run-pr
41+
if: needs.check-should-run-pr.outputs.run == 'true'
42+
runs-on: [self-hosted, Linux, X64, peco-driver]
43+
permissions:
44+
issues: write
45+
pull-requests: write
46+
steps:
47+
- name: Generate GitHub App Token
48+
id: app-token
49+
uses: actions/create-github-app-token@v1
50+
with:
51+
app-id: ${{ secrets.INTEGRATION_TEST_APP_ID }}
52+
private-key: ${{ secrets.INTEGRATION_TEST_PRIVATE_KEY }}
53+
owner: databricks
54+
repositories: databricks-driver-test
55+
- name: Dispatch tests to internal repo
56+
uses: peter-evans/repository-dispatch@v3
57+
with:
58+
token: ${{ steps.app-token.outputs.token }}
59+
repository: databricks/databricks-driver-test
60+
event-type: adbc-pr-test
61+
client-payload: |
62+
{
63+
"pr_number": "${{ github.event.pull_request.number }}",
64+
"commit_sha": "${{ github.event.pull_request.head.sha }}",
65+
"pr_repo": "${{ github.repository }}",
66+
"pr_url": "${{ github.event.pull_request.html_url }}",
67+
"pr_title": "${{ github.event.pull_request.title }}",
68+
"pr_author": "${{ github.event.pull_request.user.login }}"
69+
}
70+
- name: Comment on PR
71+
uses: actions/github-script@v7
72+
with:
73+
script: |
74+
await github.rest.issues.createComment({
75+
owner: context.repo.owner,
76+
repo: context.repo.repo,
77+
issue_number: context.issue.number,
78+
body: '🚀 Integration tests triggered! [View workflow run](https://github.com/databricks/databricks-driver-test/actions)'
79+
});
80+
# =============================================================================
81+
# For Merge Queue: Check if relevant files changed
82+
# =============================================================================
83+
check-merge-queue-paths:
84+
if: github.event_name == 'merge_group'
85+
runs-on: [self-hosted, Linux, X64, peco-driver]
86+
outputs:
87+
should-test: ${{ steps.check-paths.outputs.should_test }}
88+
steps:
89+
- name: Checkout code
90+
uses: actions/checkout@v4
91+
with:
92+
fetch-depth: 0
93+
- name: Check if relevant files changed
94+
id: check-paths
95+
run: |
96+
# Get the base and head commits for the merge queue
97+
BASE_SHA="${{ github.event.merge_group.base_sha }}"
98+
HEAD_SHA="${{ github.event.merge_group.head_sha }}"
99+
echo "Checking files changed between $BASE_SHA and $HEAD_SHA"
100+
# Define paths to check
101+
PATHS=(
102+
".github/workflows/trigger-integration-tests.yml"
103+
"ci/scripts/"
104+
"csharp/src/"
105+
"csharp/test/"
106+
)
107+
# Check if any relevant files changed
108+
CHANGED=false
109+
for path in "${PATHS[@]}"; do
110+
if git diff --name-only "$BASE_SHA" "$HEAD_SHA" | grep -q "^${path}"; then
111+
echo "✅ Found changes in: $path"
112+
CHANGED=true
113+
break
114+
fi
115+
done
116+
if [ "$CHANGED" = true ]; then
117+
echo "should_test=true" >> $GITHUB_OUTPUT
118+
echo "✅ Relevant files changed - will run tests"
119+
else
120+
echo "should_test=false" >> $GITHUB_OUTPUT
121+
echo "⏭️ No relevant files changed - skipping tests"
122+
fi
123+
# =============================================================================
124+
# For Merge Queue: Check if tests already passed on PR
125+
# =============================================================================
126+
check-previous-run:
127+
needs: check-merge-queue-paths
128+
if: github.event_name == 'merge_group' && needs.check-merge-queue-paths.outputs.should-test == 'true'
129+
runs-on: [self-hosted, Linux, X64, peco-driver]
130+
outputs:
131+
already-passed: ${{ steps.check-pr.outputs.passed }}
132+
pr-number: ${{ steps.extract-pr.outputs.pr_number }}
133+
steps:
134+
- name: Extract PR number from merge queue ref
135+
id: extract-pr
136+
run: |
137+
# Merge queue ref format: refs/heads/gh-readonly-queue/{base_branch}/pr-{pr_number}-{sha}
138+
REF="${{ github.event.merge_group.head_ref }}"
139+
echo "Full ref: $REF"
140+
# Extract PR number
141+
if [[ $REF =~ pr-([0-9]+) ]]; then
142+
PR_NUMBER="${BASH_REMATCH[1]}"
143+
echo "Extracted PR number: $PR_NUMBER"
144+
echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT
145+
else
146+
echo "❌ Could not extract PR number from ref"
147+
echo "pr_number=" >> $GITHUB_OUTPUT
148+
fi
149+
- name: Generate GitHub App Token
150+
if: steps.extract-pr.outputs.pr_number != ''
151+
id: app-token
152+
uses: actions/create-github-app-token@v1
153+
with:
154+
app-id: ${{ secrets.INTEGRATION_TEST_APP_ID }}
155+
private-key: ${{ secrets.INTEGRATION_TEST_PRIVATE_KEY }}
156+
owner: adbc-drivers
157+
repositories: databricks
158+
- name: Check if tests passed on current PR head
159+
if: steps.extract-pr.outputs.pr_number != ''
160+
id: check-pr
161+
uses: actions/github-script@v7
162+
with:
163+
github-token: ${{ steps.app-token.outputs.token }}
164+
script: |
165+
const prNumber = '${{ steps.extract-pr.outputs.pr_number }}';
166+
if (!prNumber) {
167+
console.log('No PR number found');
168+
return false;
169+
}
170+
// Get PR details
171+
const { data: pr } = await github.rest.pulls.get({
172+
owner: context.repo.owner,
173+
repo: context.repo.repo,
174+
pull_number: prNumber
175+
});
176+
console.log(`PR #${prNumber} head SHA: ${pr.head.sha}`);
177+
// Get checks for current PR head SHA
178+
const { data: checks } = await github.rest.checks.listForRef({
179+
owner: context.repo.owner,
180+
repo: context.repo.repo,
181+
ref: pr.head.sha,
182+
check_name: 'Integration Tests'
183+
});
184+
console.log(`Found ${checks.total_count} check runs for "Integration Tests"`);
185+
// Find the most recent passing check
186+
const passingChecks = checks.check_runs
187+
.filter(run => run.conclusion === 'success')
188+
.sort((a, b) => new Date(b.completed_at) - new Date(a.completed_at));
189+
if (passingChecks.length === 0) {
190+
console.log('❌ No passing checks found');
191+
return false;
192+
}
193+
const latestPassing = passingChecks[0];
194+
// CRITICAL: Check if the passing test ran on the CURRENT head SHA
195+
if (latestPassing.head_sha !== pr.head.sha) {
196+
console.log(`⚠️ Tests passed on ${latestPassing.head_sha}, but PR head is now ${pr.head.sha}`);
197+
return false;
198+
}
199+
console.log(`✅ Tests passed on current head ${pr.head.sha}`);
200+
return true;
201+
trigger-tests-merge:
202+
needs: check-previous-run
203+
if: needs.check-previous-run.outputs.already-passed != 'true'
204+
runs-on: [self-hosted, Linux, X64, peco-driver]
205+
steps:
206+
- name: Generate GitHub App Token
207+
id: app-token
208+
uses: actions/create-github-app-token@v1
209+
with:
210+
app-id: ${{ secrets.INTEGRATION_TEST_APP_ID }}
211+
private-key: ${{ secrets.INTEGRATION_TEST_PRIVATE_KEY }}
212+
owner: databricks
213+
repositories: databricks-driver-test
214+
- name: Dispatch tests to internal repo
215+
uses: peter-evans/repository-dispatch@v3
216+
with:
217+
token: ${{ steps.app-token.outputs.token }}
218+
repository: databricks/databricks-driver-test
219+
event-type: adbc-pr-test
220+
client-payload: |
221+
{
222+
"pr_number": "${{ needs.check-previous-run.outputs.pr-number }}",
223+
"commit_sha": "${{ github.event.merge_group.head_sha }}",
224+
"pr_repo": "${{ github.repository }}",
225+
"pr_url": "https://github.com/${{ github.repository }}/pull/${{ needs.check-previous-run.outputs.pr-number }}",
226+
"pr_title": "Merge queue validation",
227+
"pr_author": "merge-queue"
228+
}
229+
auto-approve-no-relevant-changes:
230+
needs: check-merge-queue-paths
231+
if: github.event_name == 'merge_group' && needs.check-merge-queue-paths.outputs.should-test == 'false'
232+
runs-on: [self-hosted, Linux, X64, peco-driver]
233+
steps:
234+
- name: Generate GitHub App Token
235+
id: app-token
236+
uses: actions/create-github-app-token@v1
237+
with:
238+
app-id: ${{ secrets.INTEGRATION_TEST_APP_ID }}
239+
private-key: ${{ secrets.INTEGRATION_TEST_PRIVATE_KEY }}
240+
owner: adbc-drivers
241+
repositories: databricks
242+
- name: Create passing check (no relevant changes)
243+
uses: actions/github-script@v7
244+
with:
245+
github-token: ${{ steps.app-token.outputs.token }}
246+
script: |
247+
await github.rest.checks.create({
248+
owner: context.repo.owner,
249+
repo: context.repo.repo,
250+
name: 'Integration Tests',
251+
head_sha: '${{ github.event.merge_group.head_sha }}',
252+
status: 'completed',
253+
conclusion: 'success',
254+
completed_at: new Date().toISOString(),
255+
output: {
256+
title: 'Auto-approved - no relevant changes',
257+
summary: '✅ No integration test files changed. Skipping tests.'
258+
}
259+
});
260+
auto-approve-already-passed:
261+
needs: check-previous-run
262+
if: needs.check-previous-run.outputs.already-passed == 'true'
263+
runs-on: [self-hosted, Linux, X64, peco-driver]
264+
steps:
265+
- name: Generate GitHub App Token
266+
id: app-token
267+
uses: actions/create-github-app-token@v1
268+
with:
269+
app-id: ${{ secrets.INTEGRATION_TEST_APP_ID }}
270+
private-key: ${{ secrets.INTEGRATION_TEST_PRIVATE_KEY }}
271+
owner: adbc-drivers
272+
repositories: databricks
273+
- name: Create passing check (auto-approve)
274+
uses: actions/github-script@v7
275+
with:
276+
github-token: ${{ steps.app-token.outputs.token }}
277+
script: |
278+
await github.rest.checks.create({
279+
owner: context.repo.owner,
280+
repo: context.repo.repo,
281+
name: 'Integration Tests',
282+
head_sha: '${{ github.event.merge_group.head_sha }}',
283+
status: 'completed',
284+
conclusion: 'success',
285+
completed_at: new Date().toISOString(),
286+
output: {
287+
title: 'Auto-approved for merge queue',
288+
summary: '✅ Tests already passed on PR head commit. Skipping duplicate test run.'
289+
}
290+
});

0 commit comments

Comments
 (0)