Skip to main content

CI/CD Integration

For Data Analysts

Integrate Olytix Core tests into your CI/CD pipeline to catch data quality issues before they reach production. This guide covers automated testing with GitHub Actions.

Overview

A robust CI/CD pipeline for Olytix Core projects includes:

┌─────────────────────────────────────────────────────────────────────┐
│ Olytix Core CI/CD Pipeline │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ Code Push │
│ ┌──────────┐ │
│ │ Git │ │
│ │ Push │ │
│ └────┬─────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ CI Pipeline │ │
│ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ │
│ │ │ Lint │─►│Compile │─►│ Test │─►│ Deploy │ │ │
│ │ └────────┘ └────────┘ └────────┘ └────────┘ │ │
│ │ │ │ │
│ │ ┌─────────┴─────────┐ │ │
│ │ ▼ ▼ │ │
│ │ ┌──────────┐ ┌──────────┐ │ │
│ │ │ Data │ │ Schema │ │ │
│ │ │ Tests │ │ Tests │ │ │
│ │ └──────────┘ └──────────┘ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘

GitHub Actions Workflow

Create a workflow file to automate Olytix Core testing on every pull request and push.

Basic Workflow

# .github/workflows/olytix-core-ci.yml
name: Olytix Core CI

on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]

env:
PYTHON_VERSION: "3.11"

jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}

- name: Install dependencies
run: |
pip install -e ".[dev]"

- name: Run ruff linter
run: ruff check src/

- name: Run ruff formatter check
run: ruff format --check src/

- name: Run mypy type checker
run: mypy src/

compile:
name: Compile Project
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}

- name: Install Olytix Core
run: pip install -e ".[dev]"

- name: Compile Olytix Core project
run: olytix-core compile --validate-schema
env:
OLYTIX_DATABASE__HOST: ${{ secrets.DATABASE_HOST }}
OLYTIX_DATABASE__USER: ${{ secrets.DATABASE_USER }}
OLYTIX_DATABASE__PASSWORD: ${{ secrets.DATABASE_PASSWORD }}
OLYTIX_DATABASE__NAME: ${{ secrets.DATABASE_NAME }}

- name: Upload manifest artifact
uses: actions/upload-artifact@v4
with:
name: manifest
path: target/manifest.json

test:
name: Run Tests
runs-on: ubuntu-latest
needs: compile
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}

- name: Install Olytix Core
run: pip install -e ".[dev]"

- name: Download manifest
uses: actions/download-artifact@v4
with:
name: manifest
path: target/

- name: Run data tests
run: olytix-core test --verbose
env:
OLYTIX_DATABASE__HOST: ${{ secrets.DATABASE_HOST }}
OLYTIX_DATABASE__USER: ${{ secrets.DATABASE_USER }}
OLYTIX_DATABASE__PASSWORD: ${{ secrets.DATABASE_PASSWORD }}
OLYTIX_DATABASE__NAME: ${{ secrets.DATABASE_NAME }}

- name: Run schema tests
run: olytix-core test --schema-only --verbose
env:
OLYTIX_DATABASE__HOST: ${{ secrets.DATABASE_HOST }}
OLYTIX_DATABASE__USER: ${{ secrets.DATABASE_USER }}
OLYTIX_DATABASE__PASSWORD: ${{ secrets.DATABASE_PASSWORD }}
OLYTIX_DATABASE__NAME: ${{ secrets.DATABASE_NAME }}

deploy:
name: Deploy to Production
runs-on: ubuntu-latest
needs: test
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}

- name: Install Olytix Core
run: pip install -e ".[dev]"

- name: Deploy models
run: olytix-core run --target prod
env:
OLYTIX_DATABASE__HOST: ${{ secrets.PROD_DATABASE_HOST }}
OLYTIX_DATABASE__USER: ${{ secrets.PROD_DATABASE_USER }}
OLYTIX_DATABASE__PASSWORD: ${{ secrets.PROD_DATABASE_PASSWORD }}
OLYTIX_DATABASE__NAME: ${{ secrets.PROD_DATABASE_NAME }}

Advanced Workflow with Matrix Testing

Test against multiple warehouse types:

# .github/workflows/olytix-core-matrix.yml
name: Olytix Core Matrix CI

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test:
name: Test (${{ matrix.warehouse }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
warehouse: [postgresql, snowflake, bigquery]
include:
- warehouse: postgresql
connection_env: OLYTIX_WAREHOUSE_POSTGRESQL
- warehouse: snowflake
connection_env: OLYTIX_WAREHOUSE_SNOWFLAKE
- warehouse: bigquery
connection_env: OLYTIX_WAREHOUSE_BIGQUERY

steps:
- uses: actions/checkout@v4

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

- name: Install Olytix Core
run: pip install -e ".[dev]"

- name: Configure warehouse connection
run: |
echo "OLYTIX_WAREHOUSE__TYPE=${{ matrix.warehouse }}" >> $GITHUB_ENV
env:
CONNECTION_SECRET: ${{ secrets[matrix.connection_env] }}

- name: Compile project
run: olytix-core compile --target ${{ matrix.warehouse }}

- name: Run tests
run: olytix-core test --target ${{ matrix.warehouse }}

Pull Request Checks

Add status checks to require passing tests before merge:

# .github/workflows/pr-checks.yml
name: PR Checks

on:
pull_request:
types: [opened, synchronize, reopened]

jobs:
data-quality:
name: Data Quality Gates
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

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

- name: Install Olytix Core
run: pip install -e ".[dev]"

- name: Get changed models
id: changed
run: |
CHANGED=$(git diff --name-only origin/${{ github.base_ref }}...HEAD -- 'models/**' 'cubes/**' | xargs)
echo "models=$CHANGED" >> $GITHUB_OUTPUT

- name: Compile changed models
if: steps.changed.outputs.models != ''
run: olytix-core compile --select ${{ steps.changed.outputs.models }}

- name: Test changed models
if: steps.changed.outputs.models != ''
run: olytix-core test --select ${{ steps.changed.outputs.models }}

- name: Post test results
if: always()
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const results = fs.readFileSync('target/test_results.json', 'utf8');
const parsed = JSON.parse(results);

const summary = `## Test Results

| Status | Count |
|--------|-------|
| Passed | ${parsed.passed} |
| Failed | ${parsed.failed} |
| Warnings | ${parsed.warnings} |
`;

github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: summary
});

Environment Configuration

GitHub Secrets Setup

Configure repository secrets for database connections:

Settings > Secrets and variables > Actions > New repository secret

Required secrets:

Secret NameDescription
DATABASE_HOSTDatabase hostname
DATABASE_USERDatabase username
DATABASE_PASSWORDDatabase password
DATABASE_NAMEDatabase name
PROD_DATABASE_HOSTProduction database host
PROD_DATABASE_USERProduction database user
PROD_DATABASE_PASSWORDProduction database password
PROD_DATABASE_NAMEProduction database name

Environment Variables

Olytix Core uses environment variables with the OLYTIX_ prefix:

env:
# Database connection
OLYTIX_DATABASE__HOST: ${{ secrets.DATABASE_HOST }}
OLYTIX_DATABASE__PORT: 5432
OLYTIX_DATABASE__USER: ${{ secrets.DATABASE_USER }}
OLYTIX_DATABASE__PASSWORD: ${{ secrets.DATABASE_PASSWORD }}
OLYTIX_DATABASE__NAME: ${{ secrets.DATABASE_NAME }}

# Project settings
OLYTIX_PROJECT__NAME: my-analytics
OLYTIX_TARGET: ci

# Test settings
OLYTIX_TEST__FAIL_FAST: true
OLYTIX_TEST__STORE_FAILURES: true

Staging Environment Testing

Test in a staging environment before production:

# .github/workflows/staging.yml
name: Staging Deployment

on:
push:
branches: [develop]

jobs:
deploy-staging:
name: Deploy to Staging
runs-on: ubuntu-latest
environment: staging

steps:
- uses: actions/checkout@v4

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

- name: Install Olytix Core
run: pip install -e ".[dev]"

- name: Compile for staging
run: olytix-core compile --target staging

- name: Run models in staging
run: olytix-core run --target staging

- name: Run all tests
run: |
olytix-core test --target staging
olytix-core test --schema-only --target staging

- name: Run integration tests
run: pytest tests/integration/ -v

- name: Validate cube queries
run: olytix-core query --validate-only --cube orders

Test Reporting

Generate and publish test reports:

- name: Run tests with JUnit output
run: olytix-core test --output-format junit --output-file test-results.xml

- name: Publish Test Results
uses: dorny/test-reporter@v1
if: always()
with:
name: Olytix Core Test Results
path: test-results.xml
reporter: java-junit

- name: Upload test artifacts
uses: actions/upload-artifact@v4
if: failure()
with:
name: test-failures
path: |
target/test_results.json
target/failed_tests/

Scheduled Testing

Run tests on a schedule to catch data drift:

# .github/workflows/scheduled-tests.yml
name: Scheduled Data Quality Checks

on:
schedule:
- cron: '0 6 * * *' # Daily at 6 AM UTC
workflow_dispatch: # Allow manual trigger

jobs:
daily-tests:
name: Daily Data Quality
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

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

- name: Install Olytix Core
run: pip install -e ".[dev]"

- name: Run full test suite
run: olytix-core test --verbose
env:
OLYTIX_DATABASE__HOST: ${{ secrets.PROD_DATABASE_HOST }}
OLYTIX_DATABASE__USER: ${{ secrets.PROD_DATABASE_USER }}
OLYTIX_DATABASE__PASSWORD: ${{ secrets.PROD_DATABASE_PASSWORD }}
OLYTIX_DATABASE__NAME: ${{ secrets.PROD_DATABASE_NAME }}

- name: Notify on failure
if: failure()
uses: slackapi/slack-github-action@v1
with:
channel-id: 'data-alerts'
slack-message: 'Daily data quality tests failed. Check workflow: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}

Best Practices

1. Fail Fast on Critical Tests

Configure critical tests to fail the pipeline immediately:

- name: Run critical tests
run: olytix-core test --select tag:critical --fail-fast

2. Cache Dependencies

Speed up workflows with dependency caching:

- name: Cache pip dependencies
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-

3. Use Branch Protection

Require tests to pass before merging:

Settings > Branches > Branch protection rules
- Require status checks to pass
- Select: lint, compile, test

4. Separate Test Environments

Use dedicated test databases to avoid impacting production:

env:
OLYTIX_DATABASE__NAME: analytics_ci_${{ github.run_id }}

5. Clean Up Resources

Remove temporary resources after tests:

- name: Cleanup test database
if: always()
run: |
olytix-core run --select tag:cleanup
psql -c "DROP SCHEMA IF EXISTS ci_${{ github.run_id }} CASCADE"

Next Steps

With CI/CD integration complete:

  1. Data Tests - Configure data quality tests
  2. Schema Tests - Add schema validation
  3. Lineage - Track data flow