Writing Skills
writing-skills
效率与协作技能,来自 obra/superpowers,查看原文获取完整用途和操作说明。
data-pipeline-cicd【部署与运维】Use this skill when asked about data pipeline CI/CD, dbt Cloud CI/CD, SQLFluff, SQL linting, Atlantis for SQL, data pipeline testing, environment promotion, schema change management, dbt test, data quality in CI, dataops, or database change management. This skill enforces: dbt Cloud CI/CD with environment promotion gates, SQL linting with SQLFluff in…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
Establish continuous integration and delivery for data pipelines covering SQL code quality, dbt model testing, schema change management, and environment promotion from dev to production.
Exact user phrases: "data pipeline CI/CD", "dbt CI/CD", "SQLFluff", "SQL linting", "Atlantis SQL", "data pipeline testing", "environment promotion", "schema change management", "dbt test", "data CI", "database CI/CD", "data quality CI", "SQL review", "data deployment".
Before activating, verify:
CI/CD pipeline configuration with SQL linting rules, dbt test setup, environment promotion workflow, and schema change management as YAML, SQL, and configuration.
# CI/CD pipeline configuration
# SQLFluff config
-- dbt test example
-- dbt Cloud job config
No preamble. No postamble. No explanations. No filler/hedging/transitions. Compress output.
4096
# .github/workflows/dbt-ci.yml
name: dbt CI
on:
pull_request:
branches: [main]
paths: ['transform/**', 'profiles.yml']
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: pip install sqlfluff==3.0.0 sqlfluff-templater-dbt
- run: sqlfluff lint transform/models/ --dialect snowflake --templater dbt
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: pip install dbt-snowflake dbt-core==1.7.0
- run: dbt deps --project-dir transform
- run: dbt build --project-dir transform --target ci
- run: dbt docs generate --project-dir transform
# .sqlfluff
[sqlfluff]
dialect = snowflake
templater = dbt
max_line_length = 80
indent_unit = space
tab_space_size = 4
[sqlfluff:indentation]
indented_joins = False
indented_ctes = True
indented_on_contents = True
[sqlfluff:rules:L003]
force_equal_tab_space = True
[sqlfluff:rules:L010]
capitalisation_policy = upper
[sqlfluff:rules:L014]
capitalisation_policy = lower
[sqlfluff:rules:L030]
capitalisation_policy = upper
[sqlfluff:rules:L040]
capitalisation_policy = upper
[sqlfluff:rules:L042]
force_divide_by_zero = False
[sqlfluff:rules:AM04]
allow_scalar = False
[sqlfluff:rules:CP01]
ignore_words = ["customer", "company", "vendor"]
# dbt_project.yml
name: analytics
version: "1.0.0"
config-version: 2
profile: analytics
model-paths: ["models"]
analysis-paths: ["analyses"]
test-paths: ["tests"]
seed-paths: ["seeds"]
macro-paths: ["macros"]
snapshot-paths: ["snapshots"]
models:
analytics:
staging:
+materialized: view
+schema: stg
tags: ["staging"]
intermediate:
+materialized: ephemeral
+schema: int
tags: ["intermediate"]
marts:
+materialized: table
+schema: marts
tags: ["marts"]
marketing:
+schema: marketing
tags: ["marketing"]
# .github/workflows/promote-to-prod.yml
name: Promote to Production
on:
workflow_dispatch:
inputs:
commit-sha:
description: 'Commit SHA to promote'
required: true
jobs:
diff:
runs-on: ubuntu-latest
outputs:
has_changes: ${{ steps.dbt-diff.outputs.has_changes }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: dbt data diff
id: dbt-diff
run: |
git checkout ${{ github.event.inputs.commit-sha }}
# Compare staging vs prod with data-diff
pip install data-diff
data-diff \
--d1 "snowflake://${{ secrets.SF_STAGING }}" \
--d2 "snowflake://${{ secrets.SF_PROD }}" \
--table analytics.marts.orders \
--key order_id \
--output diff_output.json
echo "has_changes=true" >> $GITHUB_OUTPUT
approve:
needs: diff
runs-on: ubuntu-latest
environment: production
steps:
- name: Manual approval required
run: echo "Approved by ${{ github.actor }}"
deploy:
needs: [diff, approve]
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- run: pip install dbt-snowflake dbt-core==1.7.0
- run: dbt deps --project-dir transform
- name: Run dbt in production
run: dbt build --project-dir transform --target prod --full-refresh
env:
DBT_TARGET: prod
# migrations/001_add_created_at.sql
-- Migration: Add created_at column to customer_orders
-- Date: 2026-05-15
-- Author: j4flmao
-- Step 1: Add column as nullable
ALTER TABLE analytics.marts.customer_orders
ADD COLUMN created_at TIMESTAMP_NTZ;
-- Step 2: Backfill existing rows
UPDATE analytics.marts.customer_orders
SET created_at = (
SELECT MIN(order_date)
FROM analytics.stg.orders o
WHERE o.customer_id = customer_orders.customer_id
)
WHERE created_at IS NULL;
-- Step 3: Add NOT NULL constraint
ALTER TABLE analytics.marts.customer_orders
ALTER COLUMN created_at SET NOT NULL;
# .github/workflows/schema-migration.yml
name: Schema Migration
on:
pull_request:
paths: ['migrations/**']
jobs:
lint-migration:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pip install sqlfluff
- run: sqlfluff lint migrations/ --dialect snowflake
- run: |
# Check migration naming convention
for f in migrations/*.sql; do
basename=$(basename "$f")
if ! echo "$basename" | grep -qE '^[0-9]{3}_.+\.sql#x27;; then
echo "ERROR: Migration $basename must match pattern 3-digit-number_description.sql"
exit 1
fi
done
dry-run:
runs-on: ubuntu-latest
steps:
- run: |
# Simulate migration ordering
pip install sqlparse
python -c "
import os, glob
migrations = sorted(glob.glob('migrations/*.sql'))
print(f'Found {len(migrations)} migrations to apply:')
for m in migrations:
print(f' {os.path.basename(m)}')
"
-- tests/generic/test_positive_revenue.sql
{% test positive_revenue(model, column_name) %}
SELECT *
FROM {{ model }}
WHERE {{ column_name }} < 0
{% endtest %}
-- tests/singleton/customer_id_not_null.sql
SELECT *
FROM {{ ref('dim_customers') }}
WHERE customer_id IS NULL
-- tests/singleton/order_after_customer.sql
SELECT
o.order_id,
o.customer_id,
o.order_date,
c.first_order_date
FROM {{ ref('fact_orders') }} o
LEFT JOIN {{ ref('dim_customers') }} c
ON o.customer_id = c.customer_id
WHERE o.order_date < c.first_order_date
# models/marts/schema.yml
version: 2
models:
- name: fact_orders
description: "Order fact table"
columns:
- name: order_id
tests:
- unique
- not_null
- name: customer_id
tests:
- not_null
- relationships:
to: ref('dim_customers')
field: customer_id
- name: order_amount
tests:
- positive_revenue
- dbt_expectations.expect_column_values_to_be_between:
min_value: 0
max_value: 1000000
- name: order_status
tests:
- accepted_values:
values: ['pending', 'shipped', 'delivered', 'cancelled']
# atlantis.yml
version: 3
projects:
- name: analytics-dbt
dir: transform
workflow: dbt-plan
autoplan:
enabled: true
when_modified: ["models/**/*.sql", "models/**/*.yml"]
workflows:
dbt-plan:
plan:
steps:
- run: pip install dbt-snowflake dbt-core==1.7.0
- run: dbt deps --project-dir $DIR
- run: dbt compile --project-dir $DIR
- run: dbt ls --project-dir $DIR --output json > $DIR/model_list.txt
- run: |
echo "## dbt Model Changes"
cat $DIR/model_list.txt | python -c "
import json, sys
models = json.load(sys.stdin)
for m in models:
print(f'- {m.get('name', 'unknown')} ({m.get('materialized', 'view')})')
"
apply:
steps:
- run: pip install dbt-snowflake dbt-core==1.7.0
- run: dbt deps --project-dir $DIR
- run: |
if [[ "${{.Environment}}" == "production" ]]; then
dbt run --project-dir $DIR --target prod
dbt test --project-dir $DIR --target prod
else
dbt build --project-dir $DIR
fi
# dbt Cloud API job configuration (created via dbt Cloud API)
job:
name: "CI - PR Checks"
environment_id: 12345
dbt_version: "1.7.0"
triggers:
- pull_request
execute_steps:
- "dbt deps"
- "dbt build --select state:modified+ --target ci"
- "dbt test --select tag:ci"
defer_to_production: true
job_type: ci
# ---
job:
name: "Deploy to Production"
environment_id: 67890
dbt_version: "1.7.0"
triggers:
- merge
execute_steps:
- "dbt deps"
- "dbt build --target prod --full-refresh"
- "dbt test --target prod"
defer_to_production: true
job_type: merge
| Gate | Check | Blocking | Auto or Manual |
|---|---|---|---|
| Developer | SQLFluff pass, dbt test pass | Yes | Auto |
| Code Review | PR approval from senior engineer | Yes | Manual |
| Staging | dbt build success, data-diff < 0.5% variance | Yes | Auto |
| Performance | model run time, query profile review | Warning | Auto |
| Business | Data quality score > 95% | Yes | Manual |
| Prod Deploy | All gates passed, run during maintenance window | Yes | Manual |
-- Rollback script: revert_schema_change_v001.sql
-- Reverts migration 001: Remove created_at column
-- Step 1: Drop dependent objects first
DROP VIEW IF EXISTS analytics.marts.customer_kpi_view;
-- Step 2: Drop NOT NULL constraint
ALTER TABLE analytics.marts.customer_orders
ALTER COLUMN created_at DROP NOT NULL;
-- Step 3: Clean up data
UPDATE analytics.marts.customer_orders
SET created_at = NULL;
-- Step 4: Drop column
ALTER TABLE analytics.marts.customer_orders
DROP COLUMN created_at;
-- Step 5: Recreate view
-- (original CREATE VIEW statement here)
# Rollback procedure in CI
rollback:
steps:
- trigger: dbt build --select tag:rollback --target prod
- execute: rollback.sql migration in reverse order
- verify: dbt test --select tag:critical --target prod
- notify: slack #data-alerts with rollback summary
001_description.sql, 002_description.sql)dbt build --full-refresh on prod without a prior successful staging runALTER TABLE ... ADD COLUMN ... NULL before adding NOT NULL.sqlfluff in the repository rootdata-diff in staging to detect unexpected data changes before prod promotiondata-data-quality for data quality monitoring and alerting in production
data-etl-pipeline for pipeline orchestration and execution
data-workflow-orchestration for scheduling and dependency management