Trigger Integration Tests #146
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Trigger Integration Tests | |
| # Dispatches the JDBC proxy suite in databricks/databricks-driver-test to run | |
| # against THIS PR's driver commit, and reports the result back as the "JDBC | |
| # Integration Tests" check. | |
| # | |
| # REPLAY ONLY — deliberately. A dispatched run always uses proxy_mode=replay: | |
| # driver-test builds the driver at the PR commit and serves committed recordings | |
| # (no credentials, no live warehouse). We never trigger a passthrough / live E2E | |
| # run from a PR — those are slow and flaky and would block PRs from landing; | |
| # passthrough remains a manual/nightly-only path in driver-test. | |
| # | |
| # Pattern mirrors the databricks-sql-go / adbc-csharp senders: ordinary PR events | |
| # get an immediate green stub for the required "JDBC Integration Tests" check; | |
| # maintainers preview on demand with a label; the merge queue runs the real | |
| # required replay gate. | |
| # | |
| # ONE request per PR: the sender does NOT pick a backend. driver-test's receiver | |
| # (jdbc-integration-tests.yml) decides which backends to run (thrift + sea) from | |
| # its recordings and fans them out into one "JDBC Integration Tests" check. A | |
| # single `integration-test` label previews the full replay run. | |
| # | |
| # Required external setup: | |
| # 1. `INTEGRATION_TEST_APP_ID` / `INTEGRATION_TEST_PRIVATE_KEY` repo secrets for | |
| # the dispatcher GitHub App are installed in this repo. | |
| # 2. The App is installed on databricks-driver-test (actions: write, to send | |
| # repository_dispatch) and on databricks-jdbc (checks: write, so driver-test | |
| # can report the "JDBC Integration Tests" check back here). | |
| # 3. The `integration-test` trigger label exists. | |
| # 4. Merge-queue branch protection lists `JDBC Integration Tests` as required. | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, reopened, labeled, closed] | |
| merge_group: # the required gate runs here | |
| permissions: {} | |
| jobs: | |
| # Drop the trigger labels when new commits are pushed, forcing a maintainer to | |
| # re-review before re-running (security: a labeled PR that gets new commits | |
| # must be re-approved). | |
| remove-label-on-new-commit: | |
| if: github.event_name == 'pull_request' && github.event.action == 'synchronize' | |
| runs-on: | |
| group: databricks-protected-runner-group | |
| labels: linux-ubuntu-latest | |
| permissions: | |
| issues: write | |
| pull-requests: write | |
| steps: | |
| - name: Remove integration-test labels | |
| uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | |
| with: | |
| script: | | |
| const present = context.payload.pull_request.labels.map((l) => l.name); | |
| const triggerLabels = ['integration-test']; | |
| const removed = []; | |
| for (const name of triggerLabels) { | |
| if (!present.includes(name)) continue; | |
| try { | |
| await github.rest.issues.removeLabel({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| name, | |
| }); | |
| removed.push(name); | |
| } catch (error) { | |
| if (error.status !== 404) throw error; | |
| } | |
| } | |
| if (removed.length) { | |
| const pr = context.payload.pull_request; | |
| const isFromFork = pr.head.repo?.full_name !== pr.base.repo.full_name; | |
| const repoType = isFromFork ? '**fork PR**' : 'PR'; | |
| const body = [ | |
| 'Integration test approval reset.', | |
| '', | |
| `New commits were pushed to this ${repoType}. Label(s) \`${removed.join('`, `')}\` were removed for security.`, | |
| '', | |
| '**A maintainer must re-review and re-add a label to preview tests again.** (The real gate runs in the merge queue.)', | |
| '', | |
| `Latest commit: ${pr.head.sha.substring(0, 7)}`, | |
| ].join('\n'); | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body, | |
| }); | |
| } | |
| # Ordinary PR (not a label event): the green stub for the required "JDBC | |
| # Integration Tests" check is posted by skip-checks-reporter.yml, which runs on | |
| # `workflow_run` in the base-repo context (with secret access) so it can post the | |
| # check AS THE App — required because branch protection pins the check to the App, | |
| # and a fork PR's `pull_request` run has no secrets to mint the App token itself. | |
| # See skip-checks-reporter.yml. The real run happens in the merge queue; a label | |
| # previews it on the PR. | |
| # Labeled PR: preview on demand. One `integration-test` label → full replay | |
| # (driver-test runs both thrift + sea). No per-backend label — the receiver | |
| # owns backend selection. | |
| trigger-tests-pr: | |
| if: | | |
| github.event_name == 'pull_request' && | |
| github.event.action == 'labeled' && | |
| github.event.label.name == 'integration-test' | |
| runs-on: | |
| group: databricks-protected-runner-group | |
| labels: linux-ubuntu-latest | |
| permissions: | |
| # Commenting on a PR needs pull-requests:write; checks:write for the failure | |
| # check. The dispatch itself uses the App token, not GITHUB_TOKEN. | |
| issues: write | |
| pull-requests: write | |
| checks: write | |
| steps: | |
| - name: Generate GitHub App token (driver-test repo) | |
| id: app-token | |
| uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1.12.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 jdbc-pr-test (replay) to driver-test | |
| uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | |
| with: | |
| github-token: ${{ steps.app-token.outputs.token }} | |
| script: | | |
| const pr = context.payload.pull_request; | |
| await github.rest.repos.createDispatchEvent({ | |
| owner: 'databricks', | |
| repo: 'databricks-driver-test', | |
| event_type: 'jdbc-pr-test', | |
| client_payload: { | |
| pr_number: `${pr.number}`, | |
| commit_sha: pr.head.sha, | |
| pr_repo: context.repo.owner + '/' + context.repo.repo, | |
| pr_url: pr.html_url, | |
| proxy_mode: 'replay', | |
| }, | |
| }); | |
| core.info(`Dispatched jdbc-pr-test (replay, all backends) for PR #${pr.number} @ ${pr.head.sha}`); | |
| - name: Fail check on dispatch error | |
| if: failure() | |
| uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | |
| with: | |
| github-token: ${{ github.token }} | |
| script: | | |
| await github.rest.checks.create({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| name: 'JDBC Integration Tests', | |
| head_sha: context.payload.pull_request.head.sha, | |
| status: 'completed', | |
| conclusion: 'failure', | |
| completed_at: new Date().toISOString(), | |
| output: { | |
| title: 'Failed - error dispatching tests', | |
| summary: 'An error occurred while dispatching JDBC integration tests. Check this workflow run for details.', | |
| }, | |
| }); | |
| - name: Comment on PR | |
| uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | |
| with: | |
| script: | | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: `JDBC integration tests triggered (\`replay\`, thrift + sea). [View workflow runs](https://github.com/databricks/databricks-driver-test/actions).`, | |
| }); | |
| # Merge queue: the required gate. Runs the full replay matrix (thrift + sea). | |
| merge-queue-jdbc: | |
| if: github.event_name == 'merge_group' | |
| runs-on: | |
| group: databricks-protected-runner-group | |
| labels: linux-ubuntu-latest | |
| permissions: | |
| contents: read | |
| checks: write | |
| steps: | |
| - name: Extract PR number from merge queue ref | |
| id: extract-pr | |
| env: | |
| MERGE_QUEUE_REF: ${{ github.event.merge_group.head_ref }} | |
| run: | | |
| # Merge-queue refs are refs/heads/gh-readonly-queue/<base>/pr-<n>-<sha>. Anchor | |
| # to the trailing pr-<n>-<sha> so a base branch name that itself contains a | |
| # "pr-<digits>" segment can't be matched instead of the real, last PR number. | |
| if [[ "$MERGE_QUEUE_REF" =~ /pr-([0-9]+)-[0-9a-f]+$ ]]; then | |
| echo "pr_number=${BASH_REMATCH[1]}" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "Error: failed to extract PR number from merge group ref: '$MERGE_QUEUE_REF'" >&2 | |
| exit 1 | |
| fi | |
| - name: Generate GitHub App token (driver-test repo) | |
| id: app-token | |
| uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1.12.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 jdbc-pr-test (thrift replay) for merge queue | |
| uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | |
| env: | |
| PR_NUMBER: ${{ steps.extract-pr.outputs.pr_number }} | |
| HEAD_SHA: ${{ github.event.merge_group.head_sha }} | |
| with: | |
| github-token: ${{ steps.app-token.outputs.token }} | |
| script: | | |
| const prNumber = process.env.PR_NUMBER; | |
| await github.rest.repos.createDispatchEvent({ | |
| owner: 'databricks', | |
| repo: 'databricks-driver-test', | |
| event_type: 'jdbc-pr-test', | |
| client_payload: { | |
| pr_number: prNumber, | |
| commit_sha: process.env.HEAD_SHA, | |
| pr_repo: context.repo.owner + '/' + context.repo.repo, | |
| pr_url: `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/pull/${prNumber}`, | |
| proxy_mode: 'replay', | |
| // No backend field — the receiver runs the full replay matrix | |
| // (thrift + sea), both required at merge. | |
| }, | |
| }); | |
| core.info(`Merge-queue dispatch jdbc-pr-test (replay, all backends) for PR #${prNumber} @ ${process.env.HEAD_SHA}`); | |
| - name: Fail check on dispatch error | |
| if: failure() | |
| uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | |
| env: | |
| HEAD_SHA: ${{ github.event.merge_group.head_sha }} | |
| with: | |
| github-token: ${{ github.token }} | |
| script: | | |
| await github.rest.checks.create({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| name: 'JDBC Integration Tests', | |
| head_sha: process.env.HEAD_SHA, | |
| status: 'completed', | |
| conclusion: 'failure', | |
| completed_at: new Date().toISOString(), | |
| output: { | |
| title: 'Failed - error dispatching tests', | |
| summary: 'An error occurred while dispatching JDBC integration tests. Check this workflow run for details.', | |
| }, | |
| }); | |
| # ============================================================================= | |
| # After merge: trigger the multi-language coverage fan-out. | |
| # Fires when a PR lands on main and touched JDBC driver source (src/main/). | |
| # 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 | |
| # 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 && | |
| 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 JDBC driver source changed | |
| id: changed | |
| uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | |
| 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 JDBC driver. Count a merge as source-affecting | |
| // when it changes a main (non-test) Java/resources source file under | |
| // src/main/. Docs/CI/test-only merges (src/test/, docs/, .github/, poms) | |
| // do not warrant a full multi-language fan-out. | |
| const isSource = (f) => f.startsWith('src/main/'); | |
| const srcChanged = files.some((f) => isSource(f.filename)); | |
| console.log(`JDBC 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@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1.12.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' | |
| 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 }}"}' |