diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 7a12d3c07d..0000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,115 +0,0 @@ -version: 2.1 - -setup: true - -on_main_or_tag_filter: &on_main_or_tag_filter - filters: - branches: - only: main - tags: - only: /^v\d+\.\d+\.\d+/ - -on_tag_filter: &on_tag_filter - filters: - branches: - ignore: /.*/ - tags: - only: /^v\d+\.\d+\.\d+/ - -orbs: - path-filtering: circleci/path-filtering@1.2.0 - -jobs: - publish: - docker: - - image: cimg/python:3.10 - resource_class: small - steps: - - checkout - - attach_workspace: - at: web/client - - run: - name: Publish Python package - command: make publish - - run: - name: Update pypirc - command: ./.circleci/update-pypirc.sh - - run: - name: Publish Python Tests package - command: unset TWINE_USERNAME TWINE_PASSWORD && make publish-tests - gh-release: - docker: - - image: cimg/node:20.19.0 - resource_class: small - steps: - - run: - name: Create release on GitHub - command: | - GITHUB_TOKEN="$GITHUB_TOKEN" \ - TARGET_TAG="$CIRCLE_TAG" \ - REPO_OWNER="$CIRCLE_PROJECT_USERNAME" \ - REPO_NAME="$CIRCLE_PROJECT_REPONAME" \ - CONTINUE_ON_ERROR="false" \ - npx https://github.com/TobikoData/circleci-gh-conventional-release - - ui-build: - docker: - - image: cimg/node:20.19.0 - resource_class: medium - steps: - - checkout - - run: - name: Install Dependencies - command: | - pnpm install - - run: - name: Build UI - command: pnpm --prefix web/client run build - - persist_to_workspace: - root: web/client - paths: - - dist - trigger_private_renovate: - docker: - - image: cimg/base:2021.11 - resource_class: small - steps: - - run: - name: Trigger private renovate - command: | - curl --request POST \ - --url $TOBIKO_PRIVATE_CIRCLECI_URL \ - --header "Circle-Token: $TOBIKO_PRIVATE_CIRCLECI_KEY" \ - --header "content-type: application/json" \ - --data '{ - "branch":"main", - "parameters":{ - "run_main_pr":false, - "run_sqlmesh_commit":false, - "run_renovate":true - } - }' - -workflows: - setup-workflow: - jobs: - - path-filtering/filter: - mapping: | - web/client/.* client true - (sqlmesh|tests|examples|web/server)/.* python true - pytest.ini|setup.cfg|setup.py|pyproject.toml python true - \.circleci/.*|Makefile|\.pre-commit-config\.yaml common true - vscode/extensions/.* vscode true - tag: "3.9" - - gh-release: - <<: *on_tag_filter - - ui-build: - <<: *on_main_or_tag_filter - - publish: - <<: *on_main_or_tag_filter - requires: - - ui-build - - trigger_private_renovate: - <<: *on_tag_filter - requires: - - publish diff --git a/.circleci/continue_config.yml b/.circleci/continue_config.yml deleted file mode 100644 index c549c0ae78..0000000000 --- a/.circleci/continue_config.yml +++ /dev/null @@ -1,323 +0,0 @@ -version: 2.1 - -parameters: - client: - type: boolean - default: false - common: - type: boolean - default: false - python: - type: boolean - default: false - -orbs: - windows: circleci/windows@5.0 - -commands: - halt_unless_core: - steps: - - unless: - condition: - or: - - << pipeline.parameters.common >> - - << pipeline.parameters.python >> - - equal: [main, << pipeline.git.branch >>] - steps: - - run: circleci-agent step halt - halt_unless_client: - steps: - - unless: - condition: - or: - - << pipeline.parameters.common >> - - << pipeline.parameters.client >> - - equal: [main, << pipeline.git.branch >>] - steps: - - run: circleci-agent step halt - -jobs: - vscode_test: - docker: - - image: cimg/node:20.19.1-browsers - resource_class: small - steps: - - checkout - - run: - name: Install Dependencies - command: | - pnpm install - - run: - name: Run VSCode extension CI - command: | - cd vscode/extension - pnpm run ci - doc_tests: - docker: - - image: cimg/python:3.10 - resource_class: small - steps: - - halt_unless_core - - checkout - - run: - name: Install dependencies - command: make install-dev install-doc - - run: - name: Run doc tests - command: make doc-test - - style_and_cicd_tests: - parameters: - python_version: - type: string - docker: - - image: cimg/python:<< parameters.python_version >> - resource_class: large - environment: - PYTEST_XDIST_AUTO_NUM_WORKERS: 8 - steps: - - halt_unless_core - - checkout - - run: - name: Install OpenJDK - command: sudo apt-get update && sudo apt-get install default-jdk - - run: - name: Install ODBC - command: sudo apt-get install unixodbc-dev - - run: - name: Install SQLMesh dev dependencies - command: make install-dev - - run: - name: Fix Git URL override - command: git config --global --unset url."ssh://git@github.com".insteadOf - - run: - name: Run linters and code style checks - command: make py-style - - run: - name: Exercise the benchmarks - command: make benchmark-ci - - run: - name: Run cicd tests - command: make cicd-test - - store_test_results: - path: test-results - - cicd_tests_windows: - executor: - name: windows/default - size: large - steps: - - halt_unless_core - - run: - name: Enable symlinks in git config - command: git config --global core.symlinks true - - checkout - - run: - name: Install System Dependencies - command: | - choco install make which -y - refreshenv - - run: - name: Install SQLMesh dev dependencies - command: | - python -m venv venv - . ./venv/Scripts/activate - python.exe -m pip install --upgrade pip - make install-dev - - run: - name: Run fast unit tests - command: | - . ./venv/Scripts/activate - which python - python --version - make fast-test - - store_test_results: - path: test-results - - migration_test: - docker: - - image: cimg/python:3.10 - resource_class: small - environment: - SQLMESH__DISABLE_ANONYMIZED_ANALYTICS: "1" - steps: - - halt_unless_core - - checkout - - run: - name: Run the migration test - sushi - command: ./.circleci/test_migration.sh sushi "--gateway duckdb_persistent" - - run: - name: Run the migration test - sushi_dbt - command: ./.circleci/test_migration.sh sushi_dbt "--config migration_test_config" - - ui_style: - docker: - - image: cimg/node:20.19.0 - resource_class: small - steps: - - checkout - - restore_cache: - name: Restore pnpm Package Cache - keys: - - pnpm-packages-{{ checksum "pnpm-lock.yaml" }} - - run: - name: Install Dependencies - command: | - pnpm install - - save_cache: - name: Save pnpm Package Cache - key: pnpm-packages-{{ checksum "pnpm-lock.yaml" }} - paths: - - .pnpm-store - - run: - name: Run linters and code style checks - command: pnpm run lint - - ui_test: - docker: - - image: mcr.microsoft.com/playwright:v1.54.1-jammy - resource_class: medium - steps: - - halt_unless_client - - checkout - - restore_cache: - name: Restore pnpm Package Cache - keys: - - pnpm-packages-{{ checksum "pnpm-lock.yaml" }} - - run: - name: Install pnpm package manager - command: | - npm install --global corepack@latest - corepack enable - corepack prepare pnpm@latest-10 --activate - pnpm config set store-dir .pnpm-store - - run: - name: Install Dependencies - command: | - pnpm install - - save_cache: - name: Save pnpm Package Cache - key: pnpm-packages-{{ checksum "pnpm-lock.yaml" }} - paths: - - .pnpm-store - - run: - name: Run tests - command: npm --prefix web/client run test - - engine_tests_docker: - parameters: - engine: - type: string - machine: - image: ubuntu-2404:2024.05.1 - docker_layer_caching: true - resource_class: large - environment: - SQLMESH__DISABLE_ANONYMIZED_ANALYTICS: "1" - steps: - - halt_unless_core - - checkout - - run: - name: Install OS-level dependencies - command: ./.circleci/install-prerequisites.sh "<< parameters.engine >>" - - run: - name: Run tests - command: make << parameters.engine >>-test - no_output_timeout: 20m - - store_test_results: - path: test-results - - engine_tests_cloud: - parameters: - engine: - type: string - docker: - - image: cimg/python:3.12 - resource_class: medium - environment: - PYTEST_XDIST_AUTO_NUM_WORKERS: 4 - SQLMESH__DISABLE_ANONYMIZED_ANALYTICS: "1" - steps: - - halt_unless_core - - checkout - - run: - name: Install OS-level dependencies - command: ./.circleci/install-prerequisites.sh "<< parameters.engine >>" - - run: - name: Generate database name - command: | - UUID=`cat /proc/sys/kernel/random/uuid` - TEST_DB_NAME="circleci_${UUID:0:8}" - echo "export TEST_DB_NAME='$TEST_DB_NAME'" >> "$BASH_ENV" - echo "export SNOWFLAKE_DATABASE='$TEST_DB_NAME'" >> "$BASH_ENV" - echo "export DATABRICKS_CATALOG='$TEST_DB_NAME'" >> "$BASH_ENV" - echo "export REDSHIFT_DATABASE='$TEST_DB_NAME'" >> "$BASH_ENV" - echo "export GCP_POSTGRES_DATABASE='$TEST_DB_NAME'" >> "$BASH_ENV" - echo "export FABRIC_DATABASE='$TEST_DB_NAME'" >> "$BASH_ENV" - - run: - name: Create test database - command: ./.circleci/manage-test-db.sh << parameters.engine >> "$TEST_DB_NAME" up - - run: - name: Run tests - command: | - make << parameters.engine >>-test - no_output_timeout: 20m - - run: - name: Tear down test database - command: ./.circleci/manage-test-db.sh << parameters.engine >> "$TEST_DB_NAME" down - when: always - - store_test_results: - path: test-results - -workflows: - main_pr: - jobs: - - doc_tests - - style_and_cicd_tests: - matrix: - parameters: - python_version: - - "3.9" - - "3.10" - - "3.11" - - "3.12" - - "3.13" - - cicd_tests_windows - - engine_tests_docker: - name: engine_<< matrix.engine >> - matrix: - parameters: - engine: - - duckdb - - postgres - - mysql - - mssql - - trino - - spark - - clickhouse - - risingwave - - engine_tests_cloud: - name: cloud_engine_<< matrix.engine >> - context: - - sqlmesh_cloud_database_integration - requires: - - engine_tests_docker - matrix: - parameters: - engine: - - snowflake - - databricks - - redshift - - bigquery - - clickhouse-cloud - - athena - - fabric - - gcp-postgres - filters: - branches: - only: - - main - - ui_style - - ui_test - - vscode_test - - migration_test diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000..7585f0ce10 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,16 @@ +## Description + + + +## Test Plan + + + +## Checklist + +- [ ] I have run `make style` and fixed any issues +- [ ] I have added tests for my changes (if applicable) +- [ ] All existing tests pass (`make fast-test`) +- [ ] My commits are signed off (`git commit -s`) per the [DCO](DCO) + + diff --git a/.circleci/install-prerequisites.sh b/.github/scripts/install-prerequisites.sh similarity index 89% rename from .circleci/install-prerequisites.sh rename to .github/scripts/install-prerequisites.sh index 446221dba6..6ab602fc37 100755 --- a/.circleci/install-prerequisites.sh +++ b/.github/scripts/install-prerequisites.sh @@ -1,6 +1,6 @@ #!/bin/bash -# This script is intended to be run by an Ubuntu build agent on CircleCI +# This script is intended to be run by an Ubuntu CI build agent # The goal is to install OS-level dependencies that are required before trying to install Python dependencies set -e @@ -25,7 +25,7 @@ elif [ "$ENGINE" == "fabric" ]; then sudo dpkg -i packages-microsoft-prod.deb rm packages-microsoft-prod.deb - ENGINE_DEPENDENCIES="msodbcsql18" + ENGINE_DEPENDENCIES="msodbcsql18" fi ALL_DEPENDENCIES="$COMMON_DEPENDENCIES $ENGINE_DEPENDENCIES" @@ -39,4 +39,4 @@ if [ "$ENGINE" == "spark" ]; then java -version fi -echo "All done" \ No newline at end of file +echo "All done" diff --git a/.circleci/manage-test-db.sh b/.github/scripts/manage-test-db.sh similarity index 77% rename from .circleci/manage-test-db.sh rename to .github/scripts/manage-test-db.sh index f90b567ce8..29d11afcc0 100755 --- a/.circleci/manage-test-db.sh +++ b/.github/scripts/manage-test-db.sh @@ -25,7 +25,7 @@ function_exists() { # Snowflake snowflake_init() { echo "Installing Snowflake CLI" - pip install "snowflake-cli-labs<3.8.0" + pip install "snowflake-cli" } snowflake_up() { @@ -40,20 +40,6 @@ snowflake_down() { databricks_init() { echo "Installing Databricks CLI" curl -fsSL https://raw.githubusercontent.com/databricks/setup-cli/main/install.sh | sudo sh || true - - echo "Writing out Databricks CLI config file" - echo -e "[DEFAULT]\nhost = $DATABRICKS_SERVER_HOSTNAME\ntoken = $DATABRICKS_ACCESS_TOKEN" > ~/.databrickscfg - - # this takes a path like 'sql/protocolv1/o/2934659247569/0723-005339-foobar' and extracts '0723-005339-foobar' from it - CLUSTER_ID=${DATABRICKS_HTTP_PATH##*/} - - echo "Extracted cluster id: $CLUSTER_ID from '$DATABRICKS_HTTP_PATH'" - - # Note: the cluster doesnt need to be running to create / drop catalogs, but it does need to be running to run the integration tests - echo "Ensuring cluster is running" - # the || true is to prevent the following error from causing an abort: - # > Error: is in unexpected state Running. - databricks clusters start $CLUSTER_ID || true } databricks_up() { @@ -82,10 +68,10 @@ redshift_down() { EXIT_CODE=1 ATTEMPTS=0 while [ $EXIT_CODE -ne 0 ] && [ $ATTEMPTS -lt 5 ]; do - # note: sometimes this pg_terminate_backend() call can randomly fail with: ERROR: Insufficient privileges + # note: sometimes this pg_terminate_backend() call can randomly fail with: ERROR: Insufficient privileges # if it does, let's proceed with the drop anyway rather than aborting and never attempting the drop redshift_exec "select pg_terminate_backend(procpid) from pg_stat_activity where datname = '$1'" || true - + # perform drop redshift_exec "drop database $1;" && EXIT_CODE=$? || EXIT_CODE=$? if [ $EXIT_CODE -ne 0 ]; then @@ -117,14 +103,16 @@ clickhouse-cloud_init() { # GCP Postgres gcp-postgres_init() { - # Download and start Cloud SQL Proxy - curl -fsSL -o cloud-sql-proxy https://storage.googleapis.com/cloud-sql-connectors/cloud-sql-proxy/v2.18.0/cloud-sql-proxy.linux.amd64 - chmod +x cloud-sql-proxy + # Download Cloud SQL Proxy if not already present + if [ ! -f cloud-sql-proxy ]; then + curl -fsSL -o cloud-sql-proxy https://storage.googleapis.com/cloud-sql-connectors/cloud-sql-proxy/v2.18.0/cloud-sql-proxy.linux.amd64 + chmod +x cloud-sql-proxy + fi echo "$GCP_POSTGRES_KEYFILE_JSON" > /tmp/keyfile.json - ./cloud-sql-proxy --credentials-file /tmp/keyfile.json $GCP_POSTGRES_INSTANCE_CONNECTION_STRING & - - # Wait for proxy to start - sleep 5 + if ! pgrep -x cloud-sql-proxy > /dev/null; then + ./cloud-sql-proxy --credentials-file /tmp/keyfile.json $GCP_POSTGRES_INSTANCE_CONNECTION_STRING & + sleep 5 + fi } gcp-postgres_exec() { @@ -140,13 +128,13 @@ gcp-postgres_down() { } # Fabric -fabric_init() { +fabric_init() { python --version #note: as at 2025-08-20, ms-fabric-cli is pinned to Python >= 3.10, <3.13 pip install ms-fabric-cli - + # to prevent the '[EncryptionFailed] An error occurred with the encrypted cache.' error # ref: https://microsoft.github.io/fabric-cli/#switch-to-interactive-mode-optional - fab config set encryption_fallback_enabled true + fab config set encryption_fallback_enabled true echo "Logging in to Fabric" fab auth login -u $FABRIC_CLIENT_ID -p $FABRIC_CLIENT_SECRET --tenant $FABRIC_TENANT_ID diff --git a/.circleci/test_migration.sh b/.github/scripts/test_migration.sh similarity index 82% rename from .circleci/test_migration.sh rename to .github/scripts/test_migration.sh index 9b8fe89e6e..ec45772c73 100755 --- a/.circleci/test_migration.sh +++ b/.github/scripts/test_migration.sh @@ -24,17 +24,20 @@ TEST_DIR="$TMP_DIR/$EXAMPLE_NAME" echo "Running migration test for '$EXAMPLE_NAME' in '$TEST_DIR' for example project '$EXAMPLE_DIR' using options '$SQLMESH_OPTS'" +# Copy the example project from the *current* checkout so it's stable across old/new SQLMesh versions +cp -r "$EXAMPLE_DIR" "$TEST_DIR" + git checkout $LAST_TAG # Install dependencies from the previous release. +uv venv .venv --clear +source .venv/bin/activate make install-dev -cp -r $EXAMPLE_DIR $TEST_DIR - # this is only needed temporarily until the released tag for $LAST_TAG includes this config if [ "$EXAMPLE_NAME" == "sushi_dbt" ]; then echo 'migration_test_config = sqlmesh_config(Path(__file__).parent, dbt_target_name="duckdb")' >> $TEST_DIR/config.py -fi +fi # Run initial plan pushd $TEST_DIR @@ -43,14 +46,16 @@ sqlmesh $SQLMESH_OPTS plan --no-prompts --auto-apply rm -rf .cache popd -# Switch back to the starting state of the repository +# Switch back to the starting state of the repository git checkout - # Install updated dependencies. +uv venv .venv --clear +source .venv/bin/activate make install-dev # Migrate and make sure the diff is empty pushd $TEST_DIR sqlmesh $SQLMESH_OPTS migrate sqlmesh $SQLMESH_OPTS diff prod -popd \ No newline at end of file +popd diff --git a/.circleci/update-pypirc.sh b/.github/scripts/update-pypirc.sh similarity index 100% rename from .circleci/update-pypirc.sh rename to .github/scripts/update-pypirc.sh diff --git a/.circleci/wait-for-db.sh b/.github/scripts/wait-for-db.sh similarity index 98% rename from .circleci/wait-for-db.sh rename to .github/scripts/wait-for-db.sh index a313320279..07502e3898 100755 --- a/.circleci/wait-for-db.sh +++ b/.github/scripts/wait-for-db.sh @@ -80,4 +80,4 @@ while [ $EXIT_CODE -ne 0 ]; do fi done -echo "$ENGINE is ready!" \ No newline at end of file +echo "$ENGINE is ready!" diff --git a/.github/workflows/dco.yml b/.github/workflows/dco.yml new file mode 100644 index 0000000000..a1c4e07300 --- /dev/null +++ b/.github/workflows/dco.yml @@ -0,0 +1,17 @@ +name: Sanity check +on: [pull_request] + +jobs: + commits_check_job: + runs-on: ubuntu-latest + name: Commits Check + steps: + - name: Get PR Commits + id: 'get-pr-commits' + uses: tim-actions/get-pr-commits@master + with: + token: ${{ secrets.GITHUB_TOKEN }} + - name: DCO Check + uses: tim-actions/dco@master + with: + commits: ${{ steps.get-pr-commits.outputs.commits }} diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 2e94855d3c..4395c56313 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -6,18 +6,399 @@ on: branches: - main concurrency: - group: 'pr-${{ github.event.pull_request.number }}' + group: pr-${{ github.event.pull_request.number || github.sha }} cancel-in-progress: true permissions: contents: read jobs: + changes: + runs-on: ubuntu-latest + outputs: + python: ${{ steps.filter.outputs.python }} + client: ${{ steps.filter.outputs.client }} + ci: ${{ steps.filter.outputs.ci }} + steps: + - uses: actions/checkout@v5 + - uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + python: + - 'sqlmesh/**' + - 'tests/**' + - 'examples/**' + - 'web/server/**' + - 'pytest.ini' + - 'setup.cfg' + - 'setup.py' + - 'pyproject.toml' + client: + - 'web/client/**' + ci: + - '.github/**' + - 'Makefile' + - '.pre-commit-config.yaml' + + doc-tests: + needs: changes + if: + needs.changes.outputs.python == 'true' || needs.changes.outputs.ci == + 'true' || github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + env: + UV: '1' + steps: + - uses: actions/checkout@v5 + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: '3.10' + - name: Install uv + uses: astral-sh/setup-uv@v7 + - name: Install dependencies + run: | + uv venv .venv + source .venv/bin/activate + make install-dev install-doc + - name: Run doc tests + run: | + source .venv/bin/activate + make doc-test + + style-and-cicd-tests: + needs: changes + if: + needs.changes.outputs.python == 'true' || needs.changes.outputs.ci == + 'true' || github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] + env: + PYTEST_XDIST_AUTO_NUM_WORKERS: 2 + UV: '1' + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 0 + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python-version }} + - name: Install uv + uses: astral-sh/setup-uv@v7 + - name: Install OpenJDK and ODBC + run: + sudo apt-get update && sudo apt-get install -y default-jdk + unixodbc-dev + - name: Install SQLMesh dev dependencies + run: | + uv venv .venv + source .venv/bin/activate + make install-dev + - name: Fix Git URL override + run: + git config --global --unset url."ssh://git@github.com".insteadOf || + true + - name: Run linters and code style checks + run: | + source .venv/bin/activate + make py-style + - name: Exercise the benchmarks + if: matrix.python-version != '3.9' + run: | + source .venv/bin/activate + make benchmark-ci + - name: Run cicd tests + run: | + source .venv/bin/activate + make cicd-test + - name: Upload test results + uses: actions/upload-artifact@v5 + if: ${{ !cancelled() }} + with: + name: test-results-style-cicd-${{ matrix.python-version }} + path: test-results/ + retention-days: 7 + + cicd-tests-windows: + needs: changes + if: + needs.changes.outputs.python == 'true' || needs.changes.outputs.ci == + 'true' || github.ref == 'refs/heads/main' + runs-on: windows-latest + steps: + - name: Enable symlinks in git config + run: git config --global core.symlinks true + - uses: actions/checkout@v5 + - name: Install make + run: choco install make which -y + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: '3.12' + - name: Install SQLMesh dev dependencies + run: | + python -m venv venv + . ./venv/Scripts/activate + python.exe -m pip install --upgrade pip + make install-dev + - name: Run fast unit tests + run: | + . ./venv/Scripts/activate + which python + python --version + make fast-test + - name: Upload test results + uses: actions/upload-artifact@v5 + if: ${{ !cancelled() }} + with: + name: test-results-windows + path: test-results/ + retention-days: 7 + + migration-test: + needs: changes + if: + needs.changes.outputs.python == 'true' || needs.changes.outputs.ci == + 'true' || github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + env: + SQLMESH__DISABLE_ANONYMIZED_ANALYTICS: '1' + UV: '1' + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 0 + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: '3.10' + - name: Install uv + uses: astral-sh/setup-uv@v7 + - name: Run migration test - sushi + run: + ./.github/scripts/test_migration.sh sushi "--gateway + duckdb_persistent" + - name: Run migration test - sushi_dbt + run: + ./.github/scripts/test_migration.sh sushi_dbt "--config + migration_test_config" + + ui-style: + needs: [changes] + if: + needs.changes.outputs.client == 'true' || needs.changes.outputs.ci == + 'true' || github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - uses: actions/setup-node@v6 + with: + node-version: '20' + - uses: pnpm/action-setup@v4 + with: + version: latest + - name: Get pnpm store directory + id: pnpm-cache + run: echo "store=$(pnpm store path)" >> $GITHUB_OUTPUT + - uses: actions/cache@v4 + with: + path: ${{ steps.pnpm-cache.outputs.store }} + key: pnpm-store-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: pnpm-store- + - name: Install dependencies + run: pnpm install + - name: Run linters and code style checks + run: pnpm run lint + + ui-test: + needs: changes + if: + needs.changes.outputs.client == 'true' || needs.changes.outputs.ci == + 'true' || github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + container: + image: mcr.microsoft.com/playwright:v1.54.1-jammy + steps: + - uses: actions/checkout@v5 + - name: Install pnpm via corepack + run: | + npm install --global corepack@latest + corepack enable + corepack prepare pnpm@latest-10 --activate + pnpm config set store-dir .pnpm-store + - name: Install dependencies + run: pnpm install + - name: Build UI + run: npm --prefix web/client run build + - name: Run unit tests + run: npm --prefix web/client run test:unit + - name: Run e2e tests + run: npm --prefix web/client run test:e2e + env: + PLAYWRIGHT_SKIP_BUILD: '1' + HOME: /root + + engine-tests-docker: + needs: changes + if: + needs.changes.outputs.python == 'true' || needs.changes.outputs.ci == + 'true' || github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + timeout-minutes: 25 + strategy: + fail-fast: false + matrix: + engine: + [duckdb, postgres, mysql, mssql, trino, spark, clickhouse, risingwave] + env: + PYTEST_XDIST_AUTO_NUM_WORKERS: 2 + SQLMESH__DISABLE_ANONYMIZED_ANALYTICS: '1' + UV: '1' + steps: + - uses: actions/checkout@v5 + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: '3.12' + - name: Install uv + uses: astral-sh/setup-uv@v7 + - name: Install SQLMesh dev dependencies + run: | + uv venv .venv + source .venv/bin/activate + make install-dev + - name: Install OS-level dependencies + run: ./.github/scripts/install-prerequisites.sh "${{ matrix.engine }}" + - name: Run tests + run: | + source .venv/bin/activate + make ${{ matrix.engine }}-test + - name: Upload test results + uses: actions/upload-artifact@v5 + if: ${{ !cancelled() }} + with: + name: test-results-docker-${{ matrix.engine }} + path: test-results/ + retention-days: 7 + + engine-tests-cloud: + needs: engine-tests-docker + if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + timeout-minutes: 25 + strategy: + fail-fast: false + matrix: + engine: + [ + snowflake, + databricks, + redshift, + bigquery, + clickhouse-cloud, + athena, + fabric, + gcp-postgres, + ] + env: + PYTEST_XDIST_AUTO_NUM_WORKERS: 4 + SQLMESH__DISABLE_ANONYMIZED_ANALYTICS: '1' + UV: '1' + SNOWFLAKE_ACCOUNT: ${{ secrets.SNOWFLAKE_ACCOUNT }} + SNOWFLAKE_USER: ${{ secrets.SNOWFLAKE_USER }} + SNOWFLAKE_WAREHOUSE: ${{ secrets.SNOWFLAKE_WAREHOUSE }} + SNOWFLAKE_AUTHENTICATOR: SNOWFLAKE_JWT + DATABRICKS_SERVER_HOSTNAME: ${{ secrets.DATABRICKS_SERVER_HOSTNAME }} + DATABRICKS_HOST: ${{ secrets.DATABRICKS_SERVER_HOSTNAME }} + DATABRICKS_HTTP_PATH: ${{ secrets.DATABRICKS_HTTP_PATH }} + DATABRICKS_CLIENT_ID: ${{ secrets.DATABRICKS_CLIENT_ID }} + DATABRICKS_CLIENT_SECRET: ${{ secrets.DATABRICKS_CLIENT_SECRET }} + DATABRICKS_CONNECT_VERSION: ${{ secrets.DATABRICKS_CONNECT_VERSION }} + REDSHIFT_HOST: ${{ secrets.REDSHIFT_HOST }} + REDSHIFT_PORT: ${{ secrets.REDSHIFT_PORT }} + REDSHIFT_USER: ${{ secrets.REDSHIFT_USER }} + REDSHIFT_PASSWORD: ${{ secrets.REDSHIFT_PASSWORD }} + BIGQUERY_KEYFILE: ${{ secrets.BIGQUERY_KEYFILE }} + BIGQUERY_KEYFILE_CONTENTS: ${{ secrets.BIGQUERY_KEYFILE_CONTENTS }} + CLICKHOUSE_CLOUD_HOST: ${{ secrets.CLICKHOUSE_CLOUD_HOST }} + CLICKHOUSE_CLOUD_USERNAME: ${{ secrets.CLICKHOUSE_CLOUD_USERNAME }} + CLICKHOUSE_CLOUD_PASSWORD: ${{ secrets.CLICKHOUSE_CLOUD_PASSWORD }} + GCP_POSTGRES_KEYFILE_JSON: ${{ secrets.GCP_POSTGRES_KEYFILE_JSON }} + GCP_POSTGRES_INSTANCE_CONNECTION_STRING: + ${{ secrets.GCP_POSTGRES_INSTANCE_CONNECTION_STRING }} + GCP_POSTGRES_USER: ${{ secrets.GCP_POSTGRES_USER }} + GCP_POSTGRES_PASSWORD: ${{ secrets.GCP_POSTGRES_PASSWORD }} + ATHENA_S3_WAREHOUSE_LOCATION: ${{ secrets.ATHENA_S3_WAREHOUSE_LOCATION }} + ATHENA_WORK_GROUP: ${{ secrets.ATHENA_WORK_GROUP }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_REGION: ${{ secrets.AWS_REGION }} + FABRIC_HOST: ${{ secrets.FABRIC_HOST }} + FABRIC_CLIENT_ID: ${{ secrets.FABRIC_CLIENT_ID }} + FABRIC_CLIENT_SECRET: ${{ secrets.FABRIC_CLIENT_SECRET }} + FABRIC_TENANT_ID: ${{ secrets.FABRIC_TENANT_ID }} + FABRIC_WORKSPACE_ID: ${{ secrets.FABRIC_WORKSPACE_ID }} + steps: + - uses: actions/checkout@v5 + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: '3.12' + - name: Install uv + uses: astral-sh/setup-uv@v7 + - name: Install OS-level dependencies + run: ./.github/scripts/install-prerequisites.sh "${{ matrix.engine }}" + - name: Install SQLMesh dev dependencies + run: | + uv venv .venv + source .venv/bin/activate + make install-dev + - name: Generate database name and setup credentials + run: | + UUID=$(cat /proc/sys/kernel/random/uuid) + TEST_DB_NAME="ci_${UUID:0:8}" + echo "TEST_DB_NAME=$TEST_DB_NAME" >> $GITHUB_ENV + echo "SNOWFLAKE_DATABASE=$TEST_DB_NAME" >> $GITHUB_ENV + echo "DATABRICKS_CATALOG=$TEST_DB_NAME" >> $GITHUB_ENV + echo "REDSHIFT_DATABASE=$TEST_DB_NAME" >> $GITHUB_ENV + echo "GCP_POSTGRES_DATABASE=$TEST_DB_NAME" >> $GITHUB_ENV + echo "FABRIC_DATABASE=$TEST_DB_NAME" >> $GITHUB_ENV + + echo "$SNOWFLAKE_PRIVATE_KEY_RAW" | base64 -d > /tmp/snowflake-keyfile.p8 + echo "SNOWFLAKE_PRIVATE_KEY_FILE=/tmp/snowflake-keyfile.p8" >> $GITHUB_ENV + env: + SNOWFLAKE_PRIVATE_KEY_RAW: ${{ secrets.SNOWFLAKE_PRIVATE_KEY_RAW }} + - name: Create test database + run: + ./.github/scripts/manage-test-db.sh "${{ matrix.engine }}" + "$TEST_DB_NAME" up + - name: Run tests + run: | + source .venv/bin/activate + make ${{ matrix.engine }}-test + - name: Tear down test database + if: always() + run: + ./.github/scripts/manage-test-db.sh "${{ matrix.engine }}" + "$TEST_DB_NAME" down + - name: Upload test results + uses: actions/upload-artifact@v5 + if: ${{ !cancelled() }} + with: + name: test-results-cloud-${{ matrix.engine }} + path: test-results/ + retention-days: 7 + test-vscode: env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v6 with: node-version: '22' - uses: pnpm/action-setup@v4 @@ -30,9 +411,11 @@ jobs: test-vscode-e2e: runs-on: labels: [ubuntu-2204-8] + # As at 2026-01-12 this job flakes 100% of the time. It needs investigation + if: false steps: - uses: actions/checkout@v5 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v6 with: node-version: '22' - uses: pnpm/action-setup@v4 @@ -41,11 +424,11 @@ jobs: - name: Install dependencies run: pnpm install - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: '3.12' - name: Install uv - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@v7 - name: Install python dependencies run: | python -m venv .venv @@ -62,7 +445,7 @@ jobs: run: | source ../../.venv/bin/activate pnpm run test:e2e - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v5 if: ${{ !cancelled() }} with: name: playwright-report @@ -77,11 +460,11 @@ jobs: steps: - uses: actions/checkout@v5 - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: '3.10' - name: Install uv - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@v7 - name: Install SQLMesh dev dependencies run: | uv venv .venv @@ -98,30 +481,30 @@ jobs: if [[ "${{ matrix.dbt-version }}" == "1.3" ]] || \ [[ "${{ matrix.dbt-version }}" == "1.4" ]] || \ [[ "${{ matrix.dbt-version }}" == "1.5" ]]; then - + echo "DBT version is ${{ matrix.dbt-version }} (< 1.6.0), removing semantic_models and metrics sections..." - + schema_file="tests/fixtures/dbt/sushi_test/models/schema.yml" if [[ -f "$schema_file" ]]; then echo "Modifying $schema_file..." - + # Create a temporary file temp_file=$(mktemp) - + # Use awk to remove semantic_models and metrics sections awk ' /^semantic_models:/ { in_semantic=1; next } /^metrics:/ { in_metrics=1; next } - /^[^ ]/ && (in_semantic || in_metrics) { - in_semantic=0; - in_metrics=0 + /^[^ ]/ && (in_semantic || in_metrics) { + in_semantic=0; + in_metrics=0 } !in_semantic && !in_metrics { print } ' "$schema_file" > "$temp_file" - + # Move the temp file back mv "$temp_file" "$schema_file" - + echo "Successfully removed semantic_models and metrics sections" else echo "Schema file not found at $schema_file, skipping..." diff --git a/.github/workflows/private-repo-test.yaml b/.github/workflows/private-repo-test.yaml deleted file mode 100644 index 07253f1a00..0000000000 --- a/.github/workflows/private-repo-test.yaml +++ /dev/null @@ -1,97 +0,0 @@ -name: Private Repo Testing - -on: - pull_request_target: - branches: - - main - -concurrency: - group: 'private-test-${{ github.event.pull_request.number }}' - cancel-in-progress: true - -permissions: - contents: read - -jobs: - trigger-private-test: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v5 - with: - fetch-depth: 0 - ref: ${{ github.event.pull_request.head.sha || github.ref }} - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.12' - - name: Install uv - uses: astral-sh/setup-uv@v6 - - name: Set up Node.js for UI build - uses: actions/setup-node@v4 - with: - node-version: '20' - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - version: latest - - name: Install UI dependencies - run: pnpm install - - name: Build UI - run: pnpm --prefix web/client run build - - name: Install Python dependencies - run: | - python -m venv .venv - source .venv/bin/activate - pip install build twine setuptools_scm - - name: Generate development version - id: version - run: | - source .venv/bin/activate - # Generate a PEP 440 compliant unique version including run attempt - BASE_VERSION=$(python .github/scripts/get_scm_version.py) - COMMIT_SHA=$(git rev-parse --short HEAD) - # Use PEP 440 compliant format: base.devN+pr.sha.attempt - UNIQUE_VERSION="${BASE_VERSION}+pr${{ github.event.pull_request.number }}.${COMMIT_SHA}.run${{ github.run_attempt }}" - echo "version=$UNIQUE_VERSION" >> $GITHUB_OUTPUT - echo "Generated unique version with run attempt: $UNIQUE_VERSION" - - name: Build package - env: - SETUPTOOLS_SCM_PRETEND_VERSION: ${{ steps.version.outputs.version }} - run: | - source .venv/bin/activate - python -m build - - name: Configure PyPI for private repository - env: - TOBIKO_PRIVATE_PYPI_URL: ${{ secrets.TOBIKO_PRIVATE_PYPI_URL }} - TOBIKO_PRIVATE_PYPI_KEY: ${{ secrets.TOBIKO_PRIVATE_PYPI_KEY }} - run: ./.circleci/update-pypirc.sh - - name: Publish to private PyPI - run: | - source .venv/bin/activate - python -m twine upload -r tobiko-private dist/* - - name: Publish Python Tests package - env: - SETUPTOOLS_SCM_PRETEND_VERSION: ${{ steps.version.outputs.version }} - run: | - source .venv/bin/activate - unset TWINE_USERNAME TWINE_PASSWORD && make publish-tests - - name: Get GitHub App token - id: get_token - uses: actions/create-github-app-token@v2 - with: - private-key: ${{ secrets.TOBIKO_RENOVATE_BOT_PRIVATE_KEY }} - app-id: ${{ secrets.TOBIKO_RENOVATE_BOT_APP_ID }} - owner: ${{ secrets.PRIVATE_REPO_OWNER }} - - name: Trigger private repository workflow - uses: convictional/trigger-workflow-and-wait@v1.6.5 - with: - owner: ${{ secrets.PRIVATE_REPO_OWNER }} - repo: ${{ secrets.PRIVATE_REPO_NAME }} - github_token: ${{ steps.get_token.outputs.token }} - workflow_file_name: ${{ secrets.PRIVATE_WORKFLOW_FILE }} - client_payload: | - { - "package_version": "${{ steps.version.outputs.version }}", - "pr_number": "${{ github.event.pull_request.number }}" - } diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000000..75512ffd72 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,71 @@ +name: Release +on: + push: + tags: + - 'v*.*.*' +permissions: + contents: write +jobs: + ui-build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - uses: actions/setup-node@v6 + with: + node-version: '20' + - uses: pnpm/action-setup@v4 + with: + version: latest + - name: Install dependencies + run: pnpm install + - name: Build UI + run: pnpm --prefix web/client run build + - name: Upload UI build artifact + uses: actions/upload-artifact@v5 + with: + name: ui-dist + path: web/client/dist/ + retention-days: 1 + + publish: + needs: ui-build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - name: Download UI build artifact + uses: actions/download-artifact@v4 + with: + name: ui-dist + path: web/client/dist/ + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: '3.10' + - name: Install uv + uses: astral-sh/setup-uv@v7 + - name: Install build dependencies + run: pip install build twine setuptools_scm + - name: Publish Python package + run: make publish + env: + TWINE_USERNAME: ${{ secrets.TWINE_USERNAME }} + TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }} + - name: Update pypirc for private repository + run: ./.github/scripts/update-pypirc.sh + env: + TOBIKO_PRIVATE_PYPI_URL: ${{ secrets.TOBIKO_PRIVATE_PYPI_URL }} + TOBIKO_PRIVATE_PYPI_KEY: ${{ secrets.TOBIKO_PRIVATE_PYPI_KEY }} + - name: Publish Python Tests package + run: unset TWINE_USERNAME TWINE_PASSWORD && make publish-tests + + gh-release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 0 + - name: Create release on GitHub + uses: softprops/action-gh-release@v2 + with: + generate_release_notes: true + tag_name: ${{ github.ref_name }} diff --git a/.github/workflows/release_extension.yaml b/.github/workflows/release_extension.yaml index bb52c32966..ed46d40d47 100644 --- a/.github/workflows/release_extension.yaml +++ b/.github/workflows/release_extension.yaml @@ -28,7 +28,7 @@ jobs: fi echo "Version format is valid: $version" - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: '20' - name: Install pnpm diff --git a/.github/workflows/release_shared_js.yaml b/.github/workflows/release_shared_js.yaml index 96992ae637..eb68163739 100644 --- a/.github/workflows/release_shared_js.yaml +++ b/.github/workflows/release_shared_js.yaml @@ -31,7 +31,7 @@ jobs: fi echo "Version format is valid: $version" - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: '20' registry-url: 'https://registry.npmjs.org' diff --git a/.gitignore b/.gitignore index 72b41b5ce1..16593984dd 100644 --- a/.gitignore +++ b/.gitignore @@ -138,6 +138,12 @@ dmypy.json *~ *# +# Vim +*.swp +*.swo +.null-ls* + + *.duckdb *.duckdb.wal @@ -158,3 +164,4 @@ spark-warehouse/ # claude .claude/ + diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..287a87dab5 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,5 @@ +# Code of Conduct + +SQLMesh follows the [LF Projects Code of Conduct](https://lfprojects.org/policies/code-of-conduct/). All participants in the project are expected to abide by it. + +If you believe someone is violating the code of conduct, please report it by following the instructions in the [LF Projects Code of Conduct](https://lfprojects.org/policies/code-of-conduct/). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..0e1d8e1c6e --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,90 @@ +# Contributing to SQLMesh + +## Welcome + +SQLMesh is a project of the Linux Foundation. We welcome contributions from anyone — whether you're fixing a bug, improving documentation, or proposing a new feature. + +## Technical Steering Committee (TSC) + +The TSC is responsible for technical oversight of the SQLMesh project, including coordinating technical direction, approving contribution policies, and maintaining community norms. + +Initial TSC voting members are the project's Maintainers: + +| Name | GitHub Handle | Affiliation | Role | +|---------------------|---------------|----------------|------------| +| Alexander Butler | z3z1ma | Harness | TSC Member | +| Alexander Filipchik | afilipchik | Cloud Kitchens | TSC Member | +| Reid Hooper | rhooper9711 | Benzinga | TSC Member | +| Yuki Kakegawa | StuffbyYuki | Jump.ai | TSC Member | +| Toby Mao | tobymao | Fivetran | TSC Chair | +| Alex Wilde | alexminerv | Minerva | TSC Member | + + +## Roles + +**Contributors**: Anyone who contributes code, documentation, or other technical artifacts to the project. + +**Maintainers**: Contributors who have earned the ability to modify source code, documentation, or other technical artifacts. A Contributor may become a Maintainer by majority approval of the TSC. A Maintainer may be removed by majority approval of the TSC. + +## How to Contribute + +1. Fork the repository on GitHub +2. Create a branch for your changes +3. Make your changes and commit them with a sign-off (see DCO section below) +4. Submit a pull request against the `main` branch + +File issues at [github.com/sqlmesh/sqlmesh/issues](https://github.com/sqlmesh/sqlmesh/issues). + +## Developer Certificate of Origin (DCO) + +All contributions must include a `Signed-off-by` line in the commit message per the [Developer Certificate of Origin](DCO). This certifies that you wrote the contribution or have the right to submit it under the project's open source license. + +Use `git commit -s` to add the sign-off automatically: + +```bash +git commit -s -m "Your commit message" +``` + +To fix a commit that is missing the sign-off: + +```bash +git commit --amend -s +``` + +To add a sign-off to multiple commits: + +```bash +git rebase HEAD~N --signoff +``` + +## Development Setup + +See [docs/development.md](docs/development.md) for full setup instructions. Key commands: + +```bash +python -m venv .venv +source .venv/bin/activate +make install-dev +make style # Run before submitting +make fast-test # Quick test suite +``` + +## Coding Standards + +- Run `make style` before submitting a pull request +- Follow existing code patterns and conventions in the codebase +- New files should include an SPDX license header: + ```python + # SPDX-License-Identifier: Apache-2.0 + ``` + +## Pull Request Process + +- Describe your changes clearly in the pull request description +- Ensure all CI checks pass +- Include a DCO sign-off on all commits (`git commit -s`) +- Be responsive to review feedback from maintainers + +## Licensing + +Code contributions are licensed under the [Apache License 2.0](LICENSE). Documentation contributions are licensed under [Creative Commons Attribution 4.0 International (CC-BY-4.0)](https://creativecommons.org/licenses/by/4.0/). See the LICENSE file and the [technical charter](sqlmesh-technical-charter.pdf) for details. diff --git a/DCO b/DCO new file mode 100644 index 0000000000..49b8cb0549 --- /dev/null +++ b/DCO @@ -0,0 +1,34 @@ +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. diff --git a/GOVERNANCE.md b/GOVERNANCE.md new file mode 100644 index 0000000000..44b6bc9947 --- /dev/null +++ b/GOVERNANCE.md @@ -0,0 +1,62 @@ +# SQLMesh Project Governance + +## Overview + +SQLMesh is a Series of LF Projects, LLC. The project is governed by its [Technical Charter](sqlmesh-technical-charter.pdf) and overseen by the Technical Steering Committee (TSC). SQLMesh is a project of the [Linux Foundation](https://www.linuxfoundation.org/). + +## Technical Steering Committee + +The TSC is responsible for all technical oversight of the project, including: + +- Coordinating the technical direction of the project +- Approving project or system proposals +- Organizing sub-projects and removing sub-projects +- Creating sub-committees or working groups to focus on cross-project technical issues +- Appointing representatives to work with other open source or open standards communities +- Establishing community norms, workflows, issuing releases, and security vulnerability reports +- Approving and implementing policies for contribution requirements +- Coordinating any marketing, events, or communications regarding the project + +## TSC Composition + +TSC voting members are initially the project's Maintainers as listed in [CONTRIBUTING.md](CONTRIBUTING.md). The TSC may elect a Chair from among its voting members. The Chair presides over TSC meetings and serves as the primary point of contact with the Linux Foundation. + +## Decision Making + +The project operates as a consensus-based community. When a formal vote is required: + +- Each voting TSC member receives one vote +- A quorum of 50% of voting members is required to conduct a vote +- Decisions are made by a majority of those present when quorum is met +- Electronic votes (e.g., via GitHub issues or mailing list) require a majority of all voting members to pass +- Votes that do not meet quorum or remain unresolved may be referred to the Series Manager for resolution + +## Charter Amendments + +The technical charter may be amended by a two-thirds vote of the entire TSC, subject to approval by LF Projects, LLC. + +## Reference + +The full technical charter is available at [sqlmesh-technical-charter.pdf](sqlmesh-technical-charter.pdf). + +# TSC Meeting Minutes + +## 2026-03-10 — Initial TSC Meeting + +**Members present:** Toby Mao (tobymao) + +### Vote 1: Elect Toby Mao as TSC Chair +- **Motion by:** Toby Mao +- **Votes:** Toby Mao: Yes +- **Result:** Approved (1-0-0, yes-no-abstain) + +### Vote 2: Elect TSC founding members +- **Question:** Shall the following members be added to the TSC? + - Alexander Butler (z3z1ma) + - Alexander Filipchik (afilipchik) + - Reid Hooper (rhooper9711) + - Yuki Kakegawa (StuffbyYuki) + - Alex Wilde (alexminerv) +- **Motion by:** Toby Mao +- **Votes:** Toby Mao: Yes +- **Result:** Approved (1-0-0, yes-no-abstain) diff --git a/LICENSE b/LICENSE index eabfad022a..7e95724816 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2024 Tobiko Data Inc. + Copyright Contributors to the SQLMesh project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Makefile b/Makefile index fbf77b8f9b..843beb0624 100644 --- a/Makefile +++ b/Makefile @@ -59,6 +59,10 @@ install-dev-dbt-%: echo "Applying overrides for dbt 1.5.0"; \ $(PIP) install 'dbt-databricks==1.5.6' 'numpy<2' --reinstall; \ fi; \ + if [ "$$version" = "1.3.0" ]; then \ + echo "Applying overrides for dbt $$version - upgrading google-cloud-bigquery"; \ + $(PIP) install 'google-cloud-bigquery>=3.0.0' --upgrade; \ + fi; \ mv pyproject.toml.backup pyproject.toml; \ echo "Restored original pyproject.toml" @@ -107,6 +111,9 @@ ui-build: clean-build: rm -rf build/ && rm -rf dist/ && rm -rf *.egg-info +clear-caches: + find . -type d -name ".cache" -exec rm -rf {} + 2>/dev/null && echo "Successfully removed all .cache directories" + dev-publish: ui-build clean-build publish jupyter-example: @@ -123,7 +130,7 @@ slow-test: pytest -n auto -m "(fast or slow) and not cicdonly" && pytest -m "isolated" && pytest -m "registry_isolation" && pytest -m "dialect_isolated" cicd-test: - pytest -n auto -m "fast or slow" --junitxml=test-results/junit-cicd.xml && pytest -m "isolated" && pytest -m "registry_isolation" && pytest -m "dialect_isolated" + pytest -n auto -m "(fast or slow) and not pyspark" --junitxml=test-results/junit-cicd.xml && pytest -m "pyspark" && pytest -m "isolated" && pytest -m "registry_isolation" && pytest -m "dialect_isolated" core-fast-test: pytest -n auto -m "fast and not web and not github and not dbt and not jupyter" @@ -159,7 +166,7 @@ web-test: pytest -n auto -m "web" guard-%: - @ if [ "${${*}}" = "" ]; then \ + @ if ! printenv ${*} > /dev/null 2>&1; then \ echo "Environment variable $* not set"; \ exit 1; \ fi @@ -169,7 +176,7 @@ engine-%-install: engine-docker-%-up: docker compose -f ./tests/core/engine_adapter/integration/docker/compose.${*}.yaml up -d - ./.circleci/wait-for-db.sh ${*} + ./.github/scripts/wait-for-db.sh ${*} engine-%-up: engine-%-install engine-docker-%-up @echo "Engine '${*}' is up and running" @@ -209,14 +216,14 @@ risingwave-test: engine-risingwave-up # Cloud Engines # ################# -snowflake-test: guard-SNOWFLAKE_ACCOUNT guard-SNOWFLAKE_WAREHOUSE guard-SNOWFLAKE_DATABASE guard-SNOWFLAKE_USER guard-SNOWFLAKE_PASSWORD engine-snowflake-install +snowflake-test: guard-SNOWFLAKE_ACCOUNT guard-SNOWFLAKE_WAREHOUSE guard-SNOWFLAKE_DATABASE guard-SNOWFLAKE_USER engine-snowflake-install pytest -n auto -m "snowflake" --reruns 3 --junitxml=test-results/junit-snowflake.xml bigquery-test: guard-BIGQUERY_KEYFILE engine-bigquery-install $(PIP) install -e ".[bigframes]" pytest -n auto -m "bigquery" --reruns 3 --junitxml=test-results/junit-bigquery.xml -databricks-test: guard-DATABRICKS_CATALOG guard-DATABRICKS_SERVER_HOSTNAME guard-DATABRICKS_HTTP_PATH guard-DATABRICKS_ACCESS_TOKEN guard-DATABRICKS_CONNECT_VERSION engine-databricks-install +databricks-test: guard-DATABRICKS_CATALOG guard-DATABRICKS_SERVER_HOSTNAME guard-DATABRICKS_HTTP_PATH guard-DATABRICKS_CONNECT_VERSION engine-databricks-install $(PIP) install 'databricks-connect==${DATABRICKS_CONNECT_VERSION}' pytest -n auto -m "databricks" --reruns 3 --junitxml=test-results/junit-databricks.xml diff --git a/README.md b/README.md index 3215f7cceb..41f78cc138 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@
SQLMesh is a project of the Linux Foundation.
SQLMesh is a next-generation data transformation framework designed to ship data quickly, efficiently, and without error. Data teams can run and deploy data transformations written in SQL or Python with visibility and control at any size. @@ -12,7 +13,7 @@ It is more than just a [dbt alternative](https://tobikodata.com/reduce_costs_wit ## Core Features -
+
> Get instant SQL impact and context of your changes, both in the CLI and in the [SQLMesh VSCode Extension](https://sqlmesh.readthedocs.io/en/latest/guides/vscode/?h=vs+cod)
@@ -121,19 +122,19 @@ outputs:
* Never build a table [more than once](https://tobikodata.com/simplicity-or-efficiency-how-dbt-makes-you-choose.html)
* Track what data’s been modified and run only the necessary transformations for [incremental models](https://tobikodata.com/correctly-loading-incremental-data-at-scale.html)
* Run [unit tests](https://tobikodata.com/we-need-even-greater-expectations.html) for free and configure automated audits
-* Run [table diffs](https://sqlmesh.readthedocs.io/en/stable/examples/sqlmesh_cli_crash_course/?h=crash#run-data-diff-against-prod) between prod and dev based on tables/views impacted by a change
+* Run [table diffs](https://sqlmesh.readthedocs.io/en/stable/examples/sqlmesh_cli_crash_course/?h=crash#run-data-diff-against-prod) between prod and dev based on tables/views impacted by a change
+
-
+
-
+
+
> Get instant SQL impact analysis of your changes, whether in the CLI or in [SQLMesh Plan Mode](https://sqlmesh.readthedocs.io/en/stable/guides/ui/?h=modes#working-with-an-ide)
@@ -121,7 +121,7 @@ It is more than just a [dbt alternative](https://tobikodata.com/reduce_costs_wit
??? tip "Level Up Your SQL"
Write SQL in any dialect and SQLMesh will transpile it to your target SQL dialect on the fly before sending it to the warehouse.
-
+
* Debug transformation errors *before* you run them in your warehouse in [10+ different SQL dialects](https://sqlmesh.readthedocs.io/en/stable/integrations/overview/#execution-engines)
* Definitions using [simply SQL](https://sqlmesh.readthedocs.io/en/stable/concepts/models/sql_models/#sql-based-definition) (no need for redundant and confusing `Jinja` + `YAML`)
@@ -153,7 +153,7 @@ Follow this [example](https://sqlmesh.readthedocs.io/en/stable/examples/incremen
Together, we want to build data transformation without the waste. Connect with us in the following ways:
* Join the [Tobiko Slack Community](https://tobikodata.com/slack) to ask questions, or just to say hi!
-* File an issue on our [GitHub](https://github.com/TobikoData/sqlmesh/issues/new)
+* File an issue on our [GitHub](https://github.com/SQLMesh/sqlmesh/issues/new)
* Send us an email at [hello@tobikodata.com](mailto:hello@tobikodata.com) with your questions or feedback
* Read our [blog](https://tobikodata.com/blog)
diff --git a/docs/integrations/dbt.md b/docs/integrations/dbt.md
index 7cbef5b8fa..5854236aa2 100644
--- a/docs/integrations/dbt.md
+++ b/docs/integrations/dbt.md
@@ -358,4 +358,4 @@ The dbt jinja methods that are not currently supported are:
## Missing something you need?
-Submit an [issue](https://github.com/TobikoData/sqlmesh/issues), and we'll look into it!
+Submit an [issue](https://github.com/SQLMesh/sqlmesh/issues), and we'll look into it!
diff --git a/docs/integrations/dlt.md b/docs/integrations/dlt.md
index a53dc184ea..7125510de9 100644
--- a/docs/integrations/dlt.md
+++ b/docs/integrations/dlt.md
@@ -70,7 +70,7 @@ SQLMesh will retrieve the data warehouse connection credentials from your dlt pr
### Example
-Generating a SQLMesh project dlt is quite simple. In this example, we'll use the example `sushi_pipeline.py` from the [sushi-dlt project](https://github.com/TobikoData/sqlmesh/tree/main/examples/sushi_dlt).
+Generating a SQLMesh project dlt is quite simple. In this example, we'll use the example `sushi_pipeline.py` from the [sushi-dlt project](https://github.com/SQLMesh/sqlmesh/tree/main/examples/sushi_dlt).
First, run the pipeline within the project directory:
diff --git a/docs/integrations/engines/bigquery.md b/docs/integrations/engines/bigquery.md
index a454996ecd..b93d6837ed 100644
--- a/docs/integrations/engines/bigquery.md
+++ b/docs/integrations/engines/bigquery.md
@@ -193,6 +193,23 @@ If the `impersonated_service_account` argument is set, SQLMesh will:
The user account must have [sufficient permissions to impersonate the service account](https://cloud.google.com/docs/authentication/use-service-account-impersonation).
+## Query Label
+
+BigQuery supports a `query_label` session variable which is attached to query jobs and can be used for auditing / attribution.
+
+SQLMesh supports setting it via `session_properties.query_label` on a model, as an array (or tuple) of key/value tuples.
+
+Example:
+```sql
+MODEL (
+ name my_project.my_dataset.my_model,
+ dialect 'bigquery',
+ session_properties (
+ query_label = [('team', 'data_platform'), ('env', 'prod')]
+ )
+);
+```
+
## Permissions Required
With any of the above connection methods, ensure these BigQuery permissions are enabled to allow SQLMesh to work correctly.
diff --git a/docs/integrations/engines/duckdb.md b/docs/integrations/engines/duckdb.md
index bc0af4f242..5f63a4688d 100644
--- a/docs/integrations/engines/duckdb.md
+++ b/docs/integrations/engines/duckdb.md
@@ -81,8 +81,9 @@ SQLMesh will place models with the explicit catalog "ephemeral", such as `epheme
data_path: data/ducklake
encrypted: True
data_inlining_row_limit: 10
+ metadata_schema: main
```
-
+
=== "Python"
```python linenums="1"
@@ -106,6 +107,7 @@ SQLMesh will place models with the explicit catalog "ephemeral", such as `epheme
data_path="data/ducklake",
encrypted=True,
data_inlining_row_limit=10,
+ metadata_schema="main",
),
}
)
@@ -114,6 +116,14 @@ SQLMesh will place models with the explicit catalog "ephemeral", such as `epheme
)
```
+**DuckLake Configuration Options:**
+
+- `path`: Path to the DuckLake catalog file
+- `data_path`: Path where DuckLake data files are stored
+- `encrypted`: Whether to enable encryption for the catalog (default: `False`)
+- `data_inlining_row_limit`: Maximum number of rows to inline in the catalog (default: `0`)
+- `metadata_schema`: The schema in the catalog server in which to store the DuckLake metadata tables (default: `main`)
+
#### Other Connection Catalogs Example
Catalogs can also be defined to connect to anything that [DuckDB can be attached to](https://duckdb.org/docs/sql/statements/attach.html).
diff --git a/docs/integrations/engines/trino.md b/docs/integrations/engines/trino.md
index ec1139e20d..db732f0cc1 100644
--- a/docs/integrations/engines/trino.md
+++ b/docs/integrations/engines/trino.md
@@ -90,6 +90,7 @@ hive.metastore.glue.default-warehouse-dir=s3://my-bucket/
| `http_scheme` | The HTTP scheme to use when connecting to your cluster. By default, it's `https` and can only be `http` for no-auth or basic auth. | string | N |
| `port` | The port to connect to your cluster. By default, it's `443` for `https` scheme and `80` for `http` | int | N |
| `roles` | Mapping of catalog name to a role | dict | N |
+| `source` | Value to send as Trino's `source` field for query attribution / auditing. Default: `sqlmesh`. | string | N |
| `http_headers` | Additional HTTP headers to send with each request. | dict | N |
| `session_properties` | Trino session properties. Run `SHOW SESSION` to see all options. | dict | N |
| `retries` | Number of retries to attempt when a request fails. Default: `3` | int | N |
diff --git a/docs/integrations/github.md b/docs/integrations/github.md
index a11d90d044..07903fce56 100644
--- a/docs/integrations/github.md
+++ b/docs/integrations/github.md
@@ -286,21 +286,22 @@ Below is an example of how to define the default config for the bot in either YA
### Configuration Properties
-| Option | Description | Type | Required |
-|---------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------:|:--------:|
-| `invalidate_environment_after_deploy` | Indicates if the PR environment created should be automatically invalidated after changes are deployed. Invalidated environments are cleaned up automatically by the Janitor. Default: `True` | bool | N |
-| `merge_method` | The merge method to use when automatically merging a PR after deploying to prod. Defaults to `None` meaning automatic merge is not done. Options: `merge`, `squash`, `rebase` | string | N |
-| `enable_deploy_command` | Indicates if the `/deploy` command should be enabled in order to allowed synchronized deploys to production. Default: `False` | bool | N |
-| `command_namespace` | The namespace to use for SQLMesh commands. For example if you provide `#SQLMesh` as a value then commands will be expected in the format of `#SQLMesh/