Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b5d047e
feat(spog): add SPOG (Single Point of Gateway) host support
sd-db May 20, 2026
b616ffb
test(spog): fix unit tests broken by SPOG workspace_id plumbing
sd-db May 25, 2026
6e18d14
refactor(spog): tighten contract per review
sd-db May 26, 2026
17945ab
refactor(spog): collapse to a single integration workflow path
sd-db May 26, 2026
9bfc5d1
refactor(spog): drop narrating comment in workflow env block
sd-db May 26, 2026
19b5f56
refactor(spog): two-secret workflow (host + workspace_id)
sd-db May 26, 2026
4f67c68
ci(spog): run on Databricks hardened runners with JFrog proxy
sd-db May 26, 2026
642f0f0
ci(spog): fire workflow on push to spog dev branch + drop docs/plans
sd-db May 26, 2026
6c92b6b
ci(spog): align with integration.yml auth + env layout
sd-db May 26, 2026
acec6bb
ci(spog): use the live TEST_PECO_WAREHOUSE_HTTP_PATH warehouse
sd-db May 26, 2026
c5f48f4
fix(spog tests): functional tests for the live workflow shape
sd-db May 26, 2026
4119b0a
ci(spog): rename secrets to TEST_PECO_SPOG_* convention
sd-db May 26, 2026
4890a86
ci(spog): run the full functional suite weekly against SPOG
sd-db May 26, 2026
300605d
ci(spog): mirror integration.yml's full matrix on SPOG routing
sd-db May 26, 2026
7944fa6
fix(spog tests): make functional tests profile-agnostic
sd-db May 26, 2026
03b3d21
chore: self-review
sd-db May 27, 2026
1648652
Merge branch 'main' into sd-db/spog-impl
sd-db May 27, 2026
a726045
Merge branch 'main' into sd-db/spog-impl
sd-db May 27, 2026
a317f48
fix(spog ci): wire TEST_PECO_UC_CLUSTER_ID into cluster job; drop tem…
sd-db May 27, 2026
f2e1e23
test(spog): require explicit SPOG envs to prevent false-positive runs
sd-db May 27, 2026
bfb7cf2
spog: lower documented SDK floor to 0.76.0 after end-to-end validation
sd-db May 27, 2026
3754cb9
test(spog): skip SPOG functional tests on pre-SPOG deps
sd-db May 27, 2026
a64def2
ci: test fixes
sd-db May 28, 2026
473fcb2
chore: fix test smells
sd-db May 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions .github/workflows/build_cluster_http_path.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
import os
import re

workspace_re = re.compile(r"^.*-(\d+)\..*$")
hostname = os.getenv("DBT_DATABRICKS_HOST_NAME", "")
matches = workspace_re.match(hostname)
if matches:
workspace_id = matches.group(1)
print(workspace_id)
spog_native = os.getenv("TEST_PECO_SPOG_NATIVE") == "1"
spog_workspace_id = os.getenv("TEST_PECO_SPOG_WORKSPACE_ID")

if spog_native:
if not spog_workspace_id:
raise RuntimeError("TEST_PECO_SPOG_NATIVE requires TEST_PECO_SPOG_WORKSPACE_ID.")
workspace_id = spog_workspace_id
else:
workspace_re = re.compile(r"^.*-(\d+)\..*$")
hostname = os.getenv("DBT_DATABRICKS_HOST_NAME", "")
matches = workspace_re.match(hostname)
workspace_id = matches.group(1) if matches else ""

cluster_id = os.getenv("TEST_PECO_CLUSTER_ID")
uc_cluster_id = os.getenv("TEST_PECO_UC_CLUSTER_ID")
http_path = f"sql/protocolv1/o/{workspace_id}/{cluster_id}"
uc_http_path = f"sql/protocolv1/o/{workspace_id}/{uc_cluster_id}"
suffix = f"?o={workspace_id}" if spog_native else ""
http_path = f"sql/protocolv1/o/{workspace_id}/{cluster_id}{suffix}"
uc_http_path = f"sql/protocolv1/o/{workspace_id}/{uc_cluster_id}{suffix}"

# https://stackoverflow.com/a/72225291/5093960
env_file = os.getenv("GITHUB_ENV", "")
Expand Down
14 changes: 0 additions & 14 deletions .github/workflows/integration-min-deps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -290,11 +290,6 @@ jobs:
run: |
mkdir -p logs
DBT_TEST_USER=notnecessaryformosttests@example.com \
DBT_DATABRICKS_LOCATION_ROOT="$DBT_DATABRICKS_LOCATION_ROOT" \
DBT_DATABRICKS_HOST_NAME="$DBT_DATABRICKS_HOST_NAME" \
DBT_DATABRICKS_UC_CLUSTER_HTTP_PATH="$DBT_DATABRICKS_UC_CLUSTER_HTTP_PATH" \
DBT_DATABRICKS_CLIENT_ID="$DBT_DATABRICKS_CLIENT_ID" \
DBT_DATABRICKS_CLIENT_SECRET="$DBT_DATABRICKS_CLIENT_SECRET" \
xargs -r hatch -v run min-deps:pytest \
--color=yes -v \
--profile databricks_uc_cluster \
Expand Down Expand Up @@ -389,11 +384,6 @@ jobs:
run: |
mkdir -p logs
DBT_TEST_USER=notnecessaryformosttests@example.com \
DBT_DATABRICKS_LOCATION_ROOT="$DBT_DATABRICKS_LOCATION_ROOT" \
DBT_DATABRICKS_HOST_NAME="$DBT_DATABRICKS_HOST_NAME" \
DBT_DATABRICKS_UC_CLUSTER_HTTP_PATH="$DBT_DATABRICKS_UC_CLUSTER_HTTP_PATH" \
DBT_DATABRICKS_CLIENT_ID="$DBT_DATABRICKS_CLIENT_ID" \
DBT_DATABRICKS_CLIENT_SECRET="$DBT_DATABRICKS_CLIENT_SECRET" \
xargs -r hatch -v run min-deps:pytest \
--color=yes -v \
--profile databricks_uc_sql_endpoint \
Expand Down Expand Up @@ -486,11 +476,7 @@ jobs:
run: |
mkdir -p logs
DBT_TEST_USER=notnecessaryformosttests@example.com \
DBT_DATABRICKS_LOCATION_ROOT="$DBT_DATABRICKS_LOCATION_ROOT" \
DBT_DATABRICKS_HOST_NAME="$DBT_DATABRICKS_HOST_NAME" \
DBT_DATABRICKS_HTTP_PATH="$DBT_DATABRICKS_CLUSTER_HTTP_PATH" \
DBT_DATABRICKS_CLIENT_ID="$DBT_DATABRICKS_CLIENT_ID" \
DBT_DATABRICKS_CLIENT_SECRET="$DBT_DATABRICKS_CLIENT_SECRET" \
xargs -r hatch -v run min-deps:pytest \
--color=yes -v \
--profile databricks_cluster \
Expand Down
325 changes: 325 additions & 0 deletions .github/workflows/integration-spog.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,325 @@
# SPOG Integration Tests for dbt-databricks.
#
# Mirrors integration.yml's matrix (prepare-shards + 3 sharded functional
# jobs) on a weekly Sunday schedule, but with the host name and http_path
# wired to the SPOG vanity host + ?o= so every test path exercises SPOG
# routing. PR-targeting / status-reporting logic is omitted — this is a
# scheduled smoke, not a PR gate.
name: SPOG Integration Tests
on:
workflow_dispatch:
schedule:
- cron: "30 21 * * 0" # Weekly: Sunday 21:30 UTC (Monday 03:00 IST).

permissions:
id-token: write
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
prepare-shards:
runs-on:
group: databricks-protected-runner-group
labels: linux-ubuntu-latest
env:
UV_FROZEN: "1"
steps:
- name: Check out the repository
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

- name: Setup JFrog PyPI Proxy
uses: ./.github/actions/setup-jfrog-pypi

- name: Set up Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.10"

- name: Install uv
uses: astral-sh/setup-uv@38f3f104447c67c051c4a08e39b64a148898af3a # v4
with:
cache-local-path: ~/.cache/uv

- name: Install Hatch
uses: pypa/hatch@257e27e51a6a5616ed08a39a408a21c35c9931bc # install

- name: Collect tests and assign to shards
run: |
set -euo pipefail
mkdir -p shard-assignments
declare -A NUM_SHARDS=(
[databricks_cluster]=2
[databricks_uc_cluster]=3
[databricks_uc_sql_endpoint]=3
)
for PROFILE in "${!NUM_SHARDS[@]}"; do
(
hatch run pytest --collect-only -q --profile "$PROFILE" tests/functional 2>&1 \
| grep "::" \
> "shard-assignments/${PROFILE}-collected.txt"
) &
done
wait
for PROFILE in "${!NUM_SHARDS[@]}"; do
python3 scripts/shard_assign.py \
--profile "$PROFILE" \
--num-shards "${NUM_SHARDS[$PROFILE]}" \
--input "shard-assignments/${PROFILE}-collected.txt" \
--output-dir shard-assignments \
--algo lpt_historical_time \
--timings .github/test_timings.json
done

- name: Upload shard assignments
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: shard-assignments-spog
path: shard-assignments/
retention-days: 5

uc-cluster:
needs: prepare-shards
strategy:
fail-fast: false
matrix:
shard: [0, 1, 2]
runs-on:
group: databricks-protected-runner-group
labels: linux-ubuntu-latest
environment: azure-prod
env:
DBT_DATABRICKS_HOST_NAME: ${{ secrets.TEST_PECO_SPOG_HOST }}
DBT_DATABRICKS_CLIENT_ID: ${{ secrets.TEST_PECO_SP_ID }}
DBT_DATABRICKS_CLIENT_SECRET: ${{ secrets.TEST_PECO_SP_SECRET }}
DBT_DATABRICKS_UC_INITIAL_CATALOG: peco
DBT_DATABRICKS_LOCATION_ROOT: ${{ secrets.TEST_PECO_EXTERNAL_LOCATION }}test
TEST_PECO_SPOG_WORKSPACE_ID: ${{ secrets.TEST_PECO_SPOG_WORKSPACE_ID }}
TEST_PECO_UC_CLUSTER_ID: ${{ secrets.TEST_PECO_UC_CLUSTER_ID }}
TEST_PECO_SPOG_NATIVE: "1"
UV_FROZEN: "1"
steps:
- name: Check out repository
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

- name: Setup JFrog PyPI Proxy
uses: ./.github/actions/setup-jfrog-pypi

- name: Set up python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.10"

- name: Get http path from environment
run: python .github/workflows/build_cluster_http_path.py
shell: sh

- name: Install uv
uses: astral-sh/setup-uv@38f3f104447c67c051c4a08e39b64a148898af3a # v4
with:
cache-local-path: ~/.cache/uv

- name: Install Hatch
uses: pypa/hatch@257e27e51a6a5616ed08a39a408a21c35c9931bc # install

- name: Download shard assignments
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
with:
name: shard-assignments-spog
path: shard-assignments/

- name: Resolve test list for this shard
run: |
set -euo pipefail
SHARD_FILE="shard-assignments/databricks_uc_cluster-shard-${{ matrix.shard }}.txt"
if [ ! -s "$SHARD_FILE" ]; then
echo "::error::Shard file missing or empty: $SHARD_FILE"
exit 1
fi
echo "SHARD_TESTS_FILE=$SHARD_FILE" >> "$GITHUB_ENV"
echo "Files in shard ${{ matrix.shard }}: $(wc -l < "$SHARD_FILE")"

- name: Run UC Cluster Functional Tests (shard ${{ matrix.shard }})
run: |
mkdir -p logs
DBT_TEST_USER=notnecessaryformosttests@example.com \
xargs -r hatch -v run pytest \
--color=yes -v \
--profile databricks_uc_cluster \
-n 10 --dist=loadfile \
--reruns 1 --reruns-delay 120 \
--junitxml=logs/junit-uc-cluster-shard-${{ matrix.shard }}.xml \
< "$SHARD_TESTS_FILE"

- name: Upload UC Cluster Test Logs
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: spog-uc-cluster-logs-shard-${{ matrix.shard }}
path: logs/
retention-days: 14

uc-sql-endpoint:
needs: prepare-shards
strategy:
fail-fast: false
matrix:
shard: [0, 1, 2]
runs-on:
group: databricks-protected-runner-group
labels: linux-ubuntu-latest
environment: azure-prod
env:
DBT_DATABRICKS_HOST_NAME: ${{ secrets.TEST_PECO_SPOG_HOST }}
DBT_DATABRICKS_CLIENT_ID: ${{ secrets.TEST_PECO_SP_ID }}
DBT_DATABRICKS_CLIENT_SECRET: ${{ secrets.TEST_PECO_SP_SECRET }}
DBT_DATABRICKS_HTTP_PATH: ${{ secrets.TEST_PECO_WAREHOUSE_HTTP_PATH }}?o=${{ secrets.TEST_PECO_SPOG_WORKSPACE_ID }}
DBT_DATABRICKS_UC_INITIAL_CATALOG: peco
DBT_DATABRICKS_LOCATION_ROOT: ${{ secrets.TEST_PECO_EXTERNAL_LOCATION }}test
TEST_PECO_SPOG_WORKSPACE_ID: ${{ secrets.TEST_PECO_SPOG_WORKSPACE_ID }}
TEST_PECO_UC_CLUSTER_ID: ${{ secrets.TEST_PECO_UC_CLUSTER_ID }}
TEST_PECO_SPOG_NATIVE: "1"
UV_FROZEN: "1"
steps:
- name: Check out repository
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

- name: Setup JFrog PyPI Proxy
uses: ./.github/actions/setup-jfrog-pypi

- name: Set up python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.10"

- name: Get http path from environment
run: python .github/workflows/build_cluster_http_path.py
shell: sh

- name: Install uv
uses: astral-sh/setup-uv@38f3f104447c67c051c4a08e39b64a148898af3a # v4
with:
cache-local-path: ~/.cache/uv

- name: Install Hatch
uses: pypa/hatch@257e27e51a6a5616ed08a39a408a21c35c9931bc # install

- name: Download shard assignments
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
with:
name: shard-assignments-spog
path: shard-assignments/

- name: Resolve test list for this shard
run: |
set -euo pipefail
SHARD_FILE="shard-assignments/databricks_uc_sql_endpoint-shard-${{ matrix.shard }}.txt"
if [ ! -s "$SHARD_FILE" ]; then
echo "::error::Shard file missing or empty: $SHARD_FILE"
exit 1
fi
echo "SHARD_TESTS_FILE=$SHARD_FILE" >> "$GITHUB_ENV"
echo "Files in shard ${{ matrix.shard }}: $(wc -l < "$SHARD_FILE")"

- name: Run Sql Endpoint Functional Tests (shard ${{ matrix.shard }})
run: |
mkdir -p logs
DBT_TEST_USER=notnecessaryformosttests@example.com \
xargs -r hatch -v run pytest \
--color=yes -v \
--profile databricks_uc_sql_endpoint \
-n 10 --dist=loadfile \
--reruns 1 --reruns-delay 120 \
--junitxml=logs/junit-uc-sql-endpoint-shard-${{ matrix.shard }}.xml \
< "$SHARD_TESTS_FILE"

- name: Upload SQL Endpoint Test Logs
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: spog-uc-sql-endpoint-logs-shard-${{ matrix.shard }}
path: logs/
retention-days: 14

cluster:
needs: prepare-shards
strategy:
fail-fast: false
matrix:
shard: [0, 1]
runs-on:
group: databricks-protected-runner-group
labels: linux-ubuntu-latest
environment: azure-prod
env:
DBT_DATABRICKS_HOST_NAME: ${{ secrets.TEST_PECO_SPOG_HOST }}
DBT_DATABRICKS_CLIENT_ID: ${{ secrets.TEST_PECO_SP_ID }}
DBT_DATABRICKS_CLIENT_SECRET: ${{ secrets.TEST_PECO_SP_SECRET }}
DBT_DATABRICKS_LOCATION_ROOT: ${{ secrets.TEST_PECO_EXTERNAL_LOCATION }}test
TEST_PECO_SPOG_WORKSPACE_ID: ${{ secrets.TEST_PECO_SPOG_WORKSPACE_ID }}
TEST_PECO_CLUSTER_ID: ${{ secrets.TEST_PECO_CLUSTER_ID }}
TEST_PECO_SPOG_NATIVE: "1"
UV_FROZEN: "1"
steps:
- name: Check out repository
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

- name: Setup JFrog PyPI Proxy
uses: ./.github/actions/setup-jfrog-pypi

- name: Set up python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.10"

- name: Get http path from environment
run: python .github/workflows/build_cluster_http_path.py
shell: sh

- name: Install uv
uses: astral-sh/setup-uv@38f3f104447c67c051c4a08e39b64a148898af3a # v4
with:
cache-local-path: ~/.cache/uv

- name: Install Hatch
uses: pypa/hatch@257e27e51a6a5616ed08a39a408a21c35c9931bc # install

- name: Download shard assignments
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
with:
name: shard-assignments-spog
path: shard-assignments/

- name: Resolve test list for this shard
run: |
set -euo pipefail
SHARD_FILE="shard-assignments/databricks_cluster-shard-${{ matrix.shard }}.txt"
if [ ! -s "$SHARD_FILE" ]; then
echo "::error::Shard file missing or empty: $SHARD_FILE"
exit 1
fi
echo "SHARD_TESTS_FILE=$SHARD_FILE" >> "$GITHUB_ENV"
echo "Files in shard ${{ matrix.shard }}: $(wc -l < "$SHARD_FILE")"

- name: Run Cluster Functional Tests (shard ${{ matrix.shard }})
run: |
mkdir -p logs
DBT_TEST_USER=notnecessaryformosttests@example.com \
DBT_DATABRICKS_HTTP_PATH="$DBT_DATABRICKS_CLUSTER_HTTP_PATH" \
xargs -r hatch -v run pytest \
--color=yes -v \
--profile databricks_cluster \
-n 10 --dist=loadfile \
--reruns 1 --reruns-delay 120 \
--junitxml=logs/junit-cluster-shard-${{ matrix.shard }}.xml \
< "$SHARD_TESTS_FILE"

- name: Upload Cluster Test Logs
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: spog-cluster-logs-shard-${{ matrix.shard }}
path: logs/
retention-days: 14
Loading
Loading