Skip to content

Tier 3 — Release validation #4

Tier 3 — Release validation

Tier 3 — Release validation #4

Workflow file for this run

# Tier 3 — Release validation.
#
# Runs the full warehouse × dbt-version matrix. This is the gate on cutting
# a release tag: if Tier 3 is green on a `release-candidate/X.Y.Z` branch,
# the maintainer tags `X.Y.Z` from that branch's HEAD.
#
# Triggers:
# - push to `release-candidate/**` branches (the standard maintainer flow:
# create the branch, push a version bump, watch Tier 3 run, tag)
# - `workflow_dispatch` for manual re-runs or one-off validation
# - `schedule` weekly — regression run against `main` to detect drift
# from upstream dbt adapter releases. Same matrix, same secrets, same
# guarantees as a release-candidate run; just on a different cadence.
# Scheduled runs always execute against the default branch (`main`),
# so this validates the current state of `main` regardless of any
# in-flight release branches.
#
# Trust model: same as Tier 2 (`main.yml`). Branch protection on `main`
# ensures `release-candidate/**` branches can only be created or updated by
# a maintainer pushing trusted code. Secrets are accessible because the code
# has already cleared the human-review bar via PR-to-main + branch creation.
#
# Scope (per specs/ci-rework/README.md §5.3 / Tier 3):
# - Lint (same as Tier 2)
# - Full version matrix: every supported (warehouse, dbt_version) pair,
# including the unversioned "latest" env per warehouse (early warning
# for upcoming adapter releases)
# - Databricks: stub job, intentionally skipped. See specs §12.3.
name: Tier 3 — Release validation
on:
push:
branches:
- "release-candidate/**"
workflow_dispatch:
schedule:
# Weekly regression: Mondays at 06:00 UTC. Aligned with the start of
# the workweek so failures get attention promptly. If this becomes too
# expensive, drop to monthly or trim `max-parallel` in the matrix job.
- cron: "0 6 * * 1"
permissions:
contents: read
# Release validations should not cancel each other — a maintainer pushing
# follow-up commits to the same release branch wants every intermediate
# state validated.
concurrency:
group: tier3-${{ github.ref }}
cancel-in-progress: false
env:
# Temporary: keep Node 20 as the actions runtime so the currently
# SHA-pinned action versions (which are Node 20-based) keep working
# after the June 2, 2026 default flip to Node 24. HARD DEADLINE:
# September 16, 2026, when Node 20 is removed from the runner entirely.
# Remove this once the pinned actions are bumped to Node 24-compatible
# versions. Tracked in specs/ci-rework/README.md §12.5.
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: "true"
# Non-secret env vars consumed by the invocations test model (see
# integration_test_project/profiles.yml).
DBT_CLOUD_PROJECT_ID: 123
DBT_CLOUD_JOB_ID: ABC
DBT_CLOUD_RUN_REASON: "String with 'quotes' !"
TEST_ENV_VAR_1: TEST_VALUE
TEST_ENV_VAR_NUMBER: 3
TEST_ENV_VAR_EMPTY: ""
TEST_ENV_VAR_WITH_QUOTE: "Triggered via Apache Airflow by task 'trigger_dbt_cloud_job_run' in the airtable_ingest DAG."
DBT_ENV_CUSTOM_ENV_FAVOURITE_DBT_PACKAGE: dbt_artifacts
jobs:
# -------- Lint -----------------------------------------------------------
lint:
name: lint (sqlfluff)
runs-on: ubuntu-latest
timeout-minutes: 15
env:
DBT_ENV_SECRET_SNOWFLAKE_TEST_ACCOUNT: ${{ secrets.SNOWFLAKE_TEST_ACCOUNT }}
DBT_ENV_SECRET_SNOWFLAKE_TEST_USER: ${{ secrets.SNOWFLAKE_TEST_USER }}
DBT_ENV_SECRET_SNOWFLAKE_TEST_PASSWORD: ${{ secrets.SNOWFLAKE_TEST_PASSWORD }}
DBT_ENV_SECRET_SNOWFLAKE_TEST_ROLE: ${{ secrets.SNOWFLAKE_TEST_ROLE }}
DBT_ENV_SECRET_SNOWFLAKE_TEST_DATABASE: ${{ secrets.SNOWFLAKE_TEST_DATABASE }}
DBT_ENV_SECRET_SNOWFLAKE_TEST_WAREHOUSE: ${{ secrets.SNOWFLAKE_TEST_WAREHOUSE }}
steps:
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
- name: Set up uv
uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39
with:
enable-cache: true
- name: Install Python dependencies
run: ./scripts/ci/setup.sh
- name: Run sqlfluff lint
run: ./scripts/ci/lint.sh
# -------- Full version matrix -------------------------------------------
# Single matrix that enumerates every supported (warehouse, dbt_version)
# combination. Includes an unversioned "latest" entry per warehouse to
# catch breakage from newly-released adapter minors before we add them to
# `tox.ini`. Empty `dbt_version` → `test.sh` uses the unversioned env.
#
# `id-token: write` is granted at the job level so the conditional WIF
# auth step works for bigquery slots. Other slots don't call the auth
# action, so they never mint an OIDC token.
version-matrix:
name: integration (${{ matrix.warehouse }}, ${{ matrix.dbt_version || 'latest' }})
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
id-token: write
env:
DBT_ENV_SECRET_SNOWFLAKE_TEST_ACCOUNT: ${{ secrets.SNOWFLAKE_TEST_ACCOUNT }}
DBT_ENV_SECRET_SNOWFLAKE_TEST_USER: ${{ secrets.SNOWFLAKE_TEST_USER }}
DBT_ENV_SECRET_SNOWFLAKE_TEST_PASSWORD: ${{ secrets.SNOWFLAKE_TEST_PASSWORD }}
DBT_ENV_SECRET_SNOWFLAKE_TEST_ROLE: ${{ secrets.SNOWFLAKE_TEST_ROLE }}
DBT_ENV_SECRET_SNOWFLAKE_TEST_DATABASE: ${{ secrets.SNOWFLAKE_TEST_DATABASE }}
DBT_ENV_SECRET_SNOWFLAKE_TEST_WAREHOUSE: ${{ secrets.SNOWFLAKE_TEST_WAREHOUSE }}
DBT_ENV_SECRET_GCP_PROJECT: ${{ secrets.GCP_PROJECT }}
strategy:
fail-fast: false
# Throttle parallelism to be a good neighbour to the shared cloud
# warehouses and to bound runner billing. With the EOL versions
# dropped (see comment below) the matrix is ~15 slots, so 8 in flight
# completes a release validation quickly.
max-parallel: 8
matrix:
# dbt versions 1.3–1.8 were dropped from CI on 2026-05-26. They
# cannot run on the runner's Python 3.12 (`distutils`, removed in
# 3.12, is imported by dbt-core ≤1.7) and predate the `microbatch`
# incremental strategy (a 1.9 feature) that the test fixture uses.
# Keeping them green would require a legacy Python 3.11 lane plus
# per-version gates — pure tech debt for versions dbt Labs has
# already EOL'd.
#
# This is a CI-COVERAGE change only, not a support drop:
# - `require-dbt-version` in dbt_project.yml still allows ≥1.3.0,
# so consumers on older dbt can still install the package — it's
# simply no longer verified each release.
# - The `tox.ini` envs for 1.3–1.8 are intentionally KEPT so a
# maintainer can still run e.g. `tox -e integration_snowflake_
# 1_5_0` on a local Python 3.11 to debug a consumer report.
# - The formal support-floor bump (require-dbt-version → ≥1.9,
# removing the tox envs) is a separate 3.0.0 decision.
# See specs/ci-rework/README.md §12.3.
include:
# "Latest" (unversioned env per warehouse) — picks up the
# highest adapter release at the time the workflow runs.
- warehouse: snowflake
dbt_version: ""
- warehouse: bigquery
dbt_version: ""
- warehouse: postgres
dbt_version: ""
- warehouse: trino
dbt_version: ""
- warehouse: sqlserver
dbt_version: ""
# Snowflake — pinned versions, newest first.
- { warehouse: snowflake, dbt_version: "1_11_0" }
- { warehouse: snowflake, dbt_version: "1_10_0" }
- { warehouse: snowflake, dbt_version: "1_9_0" }
# BigQuery
- { warehouse: bigquery, dbt_version: "1_11_0" }
- { warehouse: bigquery, dbt_version: "1_10_0" }
- { warehouse: bigquery, dbt_version: "1_9_0" }
# Postgres — no upstream 1.11 release as of 2026-05-12.
- { warehouse: postgres, dbt_version: "1_10_0" }
- { warehouse: postgres, dbt_version: "1_9_0" }
# Trino — no upstream 1.11 / 1.9 / 1.8 releases; 1.10 is latest.
- { warehouse: trino, dbt_version: "1_10_0" }
# SQL Server — adapter lags; 1.9 is the latest published.
- { warehouse: sqlserver, dbt_version: "1_9_0" }
steps:
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
- name: Install Microsoft ODBC Driver 18 (sqlserver only)
if: matrix.warehouse == 'sqlserver'
run: |
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install -y msodbcsql18
- name: Authenticate to GCP via Workload Identity Federation (bigquery only)
if: matrix.warehouse == 'bigquery'
uses: google-github-actions/auth@c200f3691d83b41bf9bbd8638997a462592937ed
with:
workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }}
- name: Set up uv
uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39
with:
enable-cache: true
- name: Install Python dependencies
run: ./scripts/ci/setup.sh
- name: Run integration tests
run: ./scripts/ci/test.sh ${{ matrix.warehouse }} ${{ matrix.dbt_version }}
# -------- Databricks stub -----------------------------------------------
# Visible in the workflow run so reviewers see Databricks has been
# *considered* and *skipped on purpose*, not forgotten. When Databricks
# is reactivated (specs/ci-rework/README.md §12.3), replace this with a real
# matrix job following the same shape as `version-matrix`.
integration-databricks-stub:
name: integration (databricks) [STUB — skipped]
runs-on: ubuntu-latest
timeout-minutes: 1
steps:
- name: Announce skip
run: |
echo "::warning title=Databricks tests skipped::Databricks integration is stubbed pending reactivation. See specs/ci-rework/README.md §12.3."
echo "This job exists so the Tier 3 release matrix visibly accounts for Databricks rather than silently omitting it."