From 83928a1ed04b71e1735cfc4bb73735fb04240d87 Mon Sep 17 00:00:00 2001 From: Jared Scott Date: Thu, 30 Oct 2025 15:59:02 +0800 Subject: [PATCH 1/5] feat: DRC-1868 - Refactor CI/CD Documentation - Create a section for GitHub, move ci/cd setup docs there - Create a section for GitLab. Create docs for GitLab. - Create getting-started.md to cover choices Signed-off-by: Jared Scott --- docs/7-cicd/getting-started.md | 92 +++++++++ docs/7-cicd/github/scenario-ci.md | 211 ++++++++++++++++++++ docs/7-cicd/github/setup-cd.md | 109 +++++++++++ docs/7-cicd/github/setup-ci.md | 111 +++++++++++ docs/7-cicd/gitlab/gitlab-pat-guide.md | 84 ++++++++ docs/7-cicd/gitlab/setup-cd.md | 260 +++++++++++++++++++++++++ docs/7-cicd/gitlab/setup-ci.md | 218 +++++++++++++++++++++ docs/styles/extra.css | 5 + mkdocs.yml | 30 +-- 9 files changed, 1109 insertions(+), 11 deletions(-) create mode 100644 docs/7-cicd/getting-started.md create mode 100644 docs/7-cicd/github/scenario-ci.md create mode 100644 docs/7-cicd/github/setup-cd.md create mode 100644 docs/7-cicd/github/setup-ci.md create mode 100644 docs/7-cicd/gitlab/gitlab-pat-guide.md create mode 100644 docs/7-cicd/gitlab/setup-cd.md create mode 100644 docs/7-cicd/gitlab/setup-ci.md diff --git a/docs/7-cicd/getting-started.md b/docs/7-cicd/getting-started.md new file mode 100644 index 0000000..2d51cec --- /dev/null +++ b/docs/7-cicd/getting-started.md @@ -0,0 +1,92 @@ +--- +title: Getting Started +--- + +# Getting Started + +Automate data validation in your development workflow. Catch data issues before they reach production with continuous integration and delivery built specifically for dbt projects. + +## What you'll achieve + +Set up automated workflows that: + +- **Maintain current baselines** - Auto-update comparison baselines on every merge to main +- **Validate every PR/MR** - Run data validation checks automatically when changes are proposed +- **Prevent regressions** - Catch data quality issues before they reach production +- **Save team time** - Eliminate manual validation steps for every change + +## Understanding CI vs CD + +Recce uses both continuous integration and continuous delivery to automate data validation: + +**Continuous Integration (CI)** + +- **When**: Runs on every PR/MR update +- **Purpose**: Validates proposed changes against baseline +- **Benefit**: Catches issues before merge, with results in your PR/MR + +**Continuous Delivery (CD)** + +- **When**: Runs after merge to main branch +- **Purpose**: Updates your baseline Recce session with latest production state +- **Benefit**: Ensures future comparisons use current baseline + +## Choose your platform + +Recce integrates with both GitHub Actions and GitLab CI/CD. + +Select your Git platform to get started: + +### GitHub +If your dbt project uses GitHub: + +1. [Setup CI](./github/setup-ci.md) - Auto-validate changes in every PR +2. [Setup CD](./github/setup-cd.md) - Auto-update baseline on merge to main +3. [Open Source Setup](./github/scenario-ci.md) - Alternative approach for open source projects + +### GitLab +If your dbt project uses GitLab: + +2. [Setup CI](./gitlab/setup-ci.md) - Auto-validate changes in every MR +1. [Setup CD](./gitlab/setup-cd.md) - Auto-update baseline on merge to main +3. [GitLab Personal Access Token Guide](./gitlab/gitlab-pat-guide.md) - Required for GitLab integration + +!!!note + CI/CD automation requires Recce Cloud Team plan. A free trial is available. + +## Prerequisites + +Before setting up, ensure you have: + +- **Recce Cloud account** with Team plan or free trial +- **Repository connected** to Recce Cloud ([setup guide](../2-getting-started/start-free-with-cloud.md#git-integration)) +- **dbt artifacts** (`manifest.json` and `catalog.json`) from your project + +## Architecture overview + +Both CI and CD workflows follow the same pattern: + +1. **Trigger event** (merge to main, or PR/MR opened/updated) +2. **Generate dbt artifacts** (`dbt docs generate` or external source) +3. **Upload to Recce Cloud** (automatic via workflow action) +4. **Validation results** appear in Recce dashboard and PR/MR + +
+ ![Recce CI/CD architecture](../assets/images/7-cicd/ci-cd.png){: .shadow} +
Automated validation workflow for pull requests
+
+ +## Next steps + +1. Choose your platform (GitHub or GitLab) +2. Start with CD setup to establish baseline updates +3. Add CI setup to enable PR/MR validation +4. Review [best practices](./best-practices-prep-env.md) for environment preparation + +## Related workflows + +After setting up CI/CD automation, explore these workflow guides: + +- [Development workflow](./scenario-dev.md) - Validate changes during development +- [PR/MR review workflow](./scenario-pr-review.md) - Collaborate on validation results +- [Preset checks](./preset-checks.md) - Configure automatic validation checks diff --git a/docs/7-cicd/github/scenario-ci.md b/docs/7-cicd/github/scenario-ci.md new file mode 100644 index 0000000..a0cbeba --- /dev/null +++ b/docs/7-cicd/github/scenario-ci.md @@ -0,0 +1,211 @@ +--- +title: Setup CI in Open Source +--- + +# Recce CI integration with GitHub Action + +Recce provides the `recce run` command for CI/CD pipeline. You can integrate Recce with GitHub Actions (or other CI tools) to compare the data models between two environments when a new pull-request is created. The below image describes the basic architecture. + +![ci/cd architecture](/assets/images/7-cicd/ci-cd.png){: .shadow} + +The following guide demonstrates how to configure Recce in GitHub Actions. + +## Prerequisites + +Before integrating Recce with GitHub Actions, you will need to configure the following items: + +- Set up **two environments** in your data warehouse. For example, one for base and another for pull request. + +- Provide the **credentials profile** for both environments in your `profiles.yml` so that Recce can access your data warehouse. You can put the credentials in a `profiles.yml` file, or use environment variables. + +- Set up the **data warehouse credentials** in your [GitHub repository secrets](https://docs.github.com/en/actions/reference/encrypted-secrets). + +## Set up Recce with GitHub Actions + +We suggest setting up two GitHub Actions workflows in your GitHub repository. One for the base environment and another for the PR environment. + +- **Base environment workflow**: Triggered on every merge to the `main branch`. This ensures that base artifacts are readily available for use when a PR is opened. + +- **PR environment workflow**: Triggered on every push to the `pull-request branch`. This workflow will compare base models with the current PR environment. + +### Base Workflow (Main Branch) + +This workflow will perform the following actions: + +1. Run dbt on the base environment +2. Upload the generated DBT artifacts to [GitHub workflow artifacts](https://docs.github.com/en/actions/using-workflows/storing-workflow-data-as-artifacts) for later use + +```yaml +name: Recce CI Base Branch + +on: + workflow_dispatch: + push: + branches: + - main + +concurrency: + group: recce-ci-base + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: "3.10.x" + + - name: Install dependencies + run: | + pip install -r requirements.txt + + - name: Run DBT + run: | + dbt deps + dbt seed --target ${{ env.DBT_BASE_TARGET }} + dbt run --target ${{ env.DBT_BASE_TARGET }} + dbt docs generate --target ${{ env.DBT_BASE_TARGET }} + env: + DBT_BASE_TARGET: "prod" + + - name: Upload DBT Artifacts + uses: actions/upload-artifact@v4 + with: + name: target + path: target/ +``` + +!!! note + + Please place the above file in `.github/workflows/dbt_base.yml`. This workflow path will also be used in the next PR workflow. If you place it in a different location, please remember to make the corresponding changes in the next step. + +### PR Workflow (Pull Request Branch) + +This workflow will perform the following actions: + +1. Run dbt on the PR environment. +2. Download previously generated base artifacts from base workflow. +3. Use Recce to compare the PR environment with the downloaded base artifacts. + + +````yaml +name: Recce CI PR Branch + +on: + pull_request: + branches: [main] + +jobs: + check-pull-request: + name: Check pull request by Recce CI + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Merge Base Branch into PR + uses: DataRecce/PR-Update@v1 + with: + baseBranch: ${{ github.event.pull_request.base.ref }} + autoMerge: false + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.10.x" + - name: Install dependencies + run: | + pip install -r requirements.txt + pip install recce + - name: Prepare dbt Base environment + run: | + gh repo set-default ${{ github.repository }} + base_branch=${{ github.base_ref }} + run_id=$(gh run list --workflow ${WORKFLOW_BASE} --branch ${base_branch} --status success --limit 1 --json databaseId --jq '.[0].databaseId') + echo "Download artifacts from run $run_id" + gh run download ${run_id} -n target -D target-base + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + WORKFLOW_BASE: ".github/workflows/dbt_base.yml" + - name: Prepare dbt Current environment + run: | + git checkout ${{ github.event.pull_request.head.sha }} + dbt deps + dbt seed --target ${{ env.DBT_CURRENT_TARGET}} + dbt run --target ${{ env.DBT_CURRENT_TARGET}} + dbt docs generate --target ${{ env.DBT_CURRENT_TARGET}} + env: + DBT_CURRENT_TARGET: "dev" + + - name: Run Recce CI + run: | + recce run --github-pull-request-url ${{ github.event.pull_request.html_url }} + + - name: Upload DBT Artifacts + uses: actions/upload-artifact@v4 + with: + name: target + path: target/ + + - name: Upload Recce State File + uses: actions/upload-artifact@v4 + id: recce-artifact-uploader + with: + name: recce-state-file + path: recce_state.json +```` + + + +## Review the Recce State File + +Review the downloaded Recce [state file](../../8-technical-concepts/state-file.md) with the following command: + +```bash +recce server --review recce_state.json +``` + +In the Recce server `--review` mode, you can review the comparison results of the data models between the base and current environments. It will contain the row counts of modified data models. + diff --git a/docs/7-cicd/github/setup-cd.md b/docs/7-cicd/github/setup-cd.md new file mode 100644 index 0000000..5a452b2 --- /dev/null +++ b/docs/7-cicd/github/setup-cd.md @@ -0,0 +1,109 @@ +--- +title: Setup CD +--- + +# Setup CD + +Set up automatic updates for your Recce Cloud base sessions. Keep your data comparison baseline current every time you merge to main, with no manual work required. + +## Purpose + +**Automated Base Session Management** eliminates manual baseline maintenance. + +- **Triggers**: PR merge to main + scheduled updates +- **Action**: Auto-update base Recce session +- **Benefit**: Current comparison baseline for future PRs + +## Prerequisites + +You need `manifest.json` and `catalog.json` files (dbt artifacts) for Recce Cloud. See [Start Free with Cloud](../../2-getting-started/start-free-with-cloud.md) for instructions on preparing these files. + +## Implementation + +### 1. Core Workflow + +Create `.github/workflows/cd-workflow.yml`: + +```yaml +name: Update Base Recce Session + +on: + push: + branches: ["main"] + schedule: + - cron: "0 2 * * *" # Daily at 2 AM UTC + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }} + cancel-in-progress: true + +jobs: + update-base-session: + runs-on: ubuntu-latest + timeout-minutes: 30 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + cache: "pip" + + - name: Install dependencies + run: | + pip install -r requirements.txt + + - name: Prepare dbt artifacts + run: | + # Install dbt packages + dbt deps + + # Optional: Build tables to ensure they're materialized and updated + # dbt build --target prod + + # Required: Generate artifacts (provides all we need) + dbt docs generate --target prod + env: + DBT_ENV_SECRET_KEY: ${{ secrets.DBT_ENV_SECRET_KEY }} + + - name: Update Recce Cloud Base Session + uses: DataRecce/recce-cloud-cicd-action@v0.1 + # This action automatically uploads artifacts to Recce Cloud +``` + +### 2. Artifact Preparation Options + +**Default: Fresh Build** (shown in example above) + +- `dbt docs generate` is required and provides the needed `manifest.json` and `catalog.json` artifacts. +- `dbt build` is optional but ensures tables are materialized and updated. + +**Alternative Methods:** + +- **External Download**: Download from dbt Cloud, Paradime, or other platforms +- **Pipeline Integration**: Use existing dbt build workflows + + +### 3. Verification + +#### Manual Trigger Test + +1. Go to **Actions** tab in your repository +2. Select "Update Base Recce Session" workflow +3. Click **Run workflow** button +4. Monitor the run for successful completion + +#### Verify Success + +- ✅ **Workflow completes** without errors in Actions tab +- ✅ **Base session updated** in Recce Cloud dashboard + +![Recce Cloud dashboard showing updated base sessions](/assets/images/7-cicd/verify-setup-cd.png){: .shadow} + +## Next Steps + +**[Setup CI](./setup-ci.md)** to automatically validate PR changes against your updated base session. This completes your CI/CD pipeline by adding automated data validation for every pull request. diff --git a/docs/7-cicd/github/setup-ci.md b/docs/7-cicd/github/setup-ci.md new file mode 100644 index 0000000..0cacd0c --- /dev/null +++ b/docs/7-cicd/github/setup-ci.md @@ -0,0 +1,111 @@ +--- +title: Setup CI +--- + +# Setup CI + +Automatically validate your data changes in every pull request using Recce Cloud. Catch data issues before they reach production, with validation results right in your PR. + +## Purpose + +**Automated PR Validation** prevents data regressions before merge. + +- **Triggers**: PR opened/updated against main +- **Action**: Auto-update Recce session for PR validation +- **Benefit**: Automated data validation and comparison + +## Prerequisites + +You need `manifest.json` and `catalog.json` files (dbt artifacts) for Recce Cloud. See [Start Free with Cloud](../../2-getting-started/start-free-with-cloud.md) for instructions on preparing these files. + +## Implementation + +### 1. Core Workflow + +Create `.github/workflows/ci-workflow.yml`: + +```yaml +name: Validate PR Changes + +on: + pull_request: + branches: ["main"] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + validate-changes: + runs-on: ubuntu-latest + timeout-minutes: 45 + + steps: + - name: Checkout PR branch + uses: actions/checkout@v4 + with: + fetch-depth: 2 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + cache: "pip" + + - name: Install dependencies + run: | + pip install -r requirements.txt + + # Step 1: Prepare current branch artifacts + - name: Build current branch artifacts + run: | + # Install dbt packages + dbt deps + + # Optional: Build tables to ensure they're materialized + # dbt build --target ci + + # Required: Generate artifacts for comparison + dbt docs generate --target ci + env: + DBT_ENV_SECRET_KEY: ${{ secrets.DBT_ENV_SECRET_KEY }} + + - name: Update Recce PR Session + uses: DataRecce/recce-cloud-cicd-action@v0.1 + # This action automatically creates a PR session in Recce Cloud +``` + +### 2. Artifact Preparation Options + +**Default: Fresh Build** (shown in example above) + +- `dbt docs generate` is required and provides all needed artifacts. +- `dbt build` is optional but ensures tables are materialized and updated. + +**Alternative Methods:** + +- **External Download**: Download from dbt Cloud, Paradime, or other platforms +- **Pipeline Integration**: Use existing dbt build workflows + +### 3. Verification + +#### Test with a PR + +1. Create a test PR with small data changes +2. Check **Actions** tab for CI workflow execution +3. Verify validation runs successfully + +#### Verify Success + +- ✅ **Workflow completes** without errors in Actions tab +- ✅ **PR session updated** in Recce Cloud dashboard + +![Recce Cloud showing PR validation session](/assets/images/7-cicd/verify-setup-ci.png){: .shadow} + +#### Review PR Session + +To analyze the PR changes in detail: + +- Go to your [Recce Cloud dashboard](https://cloud.reccehq.com) +- Find the PR session that was created +- Launch Recce instance to explore data differences diff --git a/docs/7-cicd/gitlab/gitlab-pat-guide.md b/docs/7-cicd/gitlab/gitlab-pat-guide.md new file mode 100644 index 0000000..f69d18f --- /dev/null +++ b/docs/7-cicd/gitlab/gitlab-pat-guide.md @@ -0,0 +1,84 @@ +--- +title: GitLab Personal Access Token +--- + +# GitLab Personal Access Token Setup + +To integrate Recce with your GitLab project, you'll need to create a Personal Access Token (PAT) with appropriate +permissions. + +## Token Scope Requirements + +Recce supports two different permission levels depending on your needs: + +| Scope | Permissions | Features Available | +|------------|----------------------------------|-------------------------------------------------------------------------------------------------------------------------------------| +| `api` | Full API access (read and write) | • View and track merge requests
• **Receive generated summaries and notes on MRs from Recce**
• Full integration capabilities | +| `read_api` | Read-only API access | • View and track merge requests
• **Cannot receive generated summaries and notes on MRs from Recce** | + +!!!warning "Important: Choose the Right Scope" + If you want Recce to automatically post validation summaries and notes directly to your merge requests, you **must** use + the `api` scope. The `read_api` scope only allows Recce to read merge request information but cannot write comments or + summaries back to GitLab. + +## How to Create a Personal Access Token + +Follow these steps to create a Personal Access Token in GitLab: + +1. **Navigate to [Personal Access Token Settings in GitLab](https://gitlab.com/-/user_settings/personal_access_tokens)** + +2. **Create New Token** + - Click **Add new token** button + - Enter a descriptive **Token name** (e.g., "Recce Integration") + - Set an **Expiration date** + +3. **Select Scopes** + + Choose one of the following based on your needs: + + **Option A: Full Integration (Recommended)**
+ - ✅ `api` scope
+ - This enables Recce to post validation summaries and notes to your merge requests + + **Option B: Read-Only Access**
+ - ✅ `read_api` scope
+ - ⚠️ You will **not** receive generated PR summaries and notes on your MRs from Recce + +4. **Generate Token** + - Click **Create personal access token** + - **Important**: Copy the token immediately - you won't be able to see it again! + +5. **Save Token Securely** + - Store the token in a secure location + + +## Using Your Token with Recce + +Once you have your Personal Access Token: + +1. Navigate to Recce settings +2. Select GitLab integration +3. Paste your Personal Access Token +4. Complete the connection setup + +## Troubleshooting + +**Token not working?** + +- Verify you've selected the correct scope (`api` or `read_api`) +- Check that the token hasn't expired +- Ensure you have appropriate project permissions (Maintainer or Owner role) + +**Not receiving summaries on merge requests?** + +- Verify your token uses the `api` scope (not just `read_api`) +- Check that Recce has write permissions to your project + +**Still having issues?** + +- Please reach out to us on [our Discord](https://discord.gg/HUUx9fyphJ) or via email at `help@reccehq.com` + +## Related Documentation + +- [Cloud-based Git Platform Integration](../2-getting-started/start-free-with-cloud.md#git-integration) +- [CI/CD Automation](../2-getting-started/start-free-with-cloud.md#cicd-automation) diff --git a/docs/7-cicd/gitlab/setup-cd.md b/docs/7-cicd/gitlab/setup-cd.md new file mode 100644 index 0000000..d78127e --- /dev/null +++ b/docs/7-cicd/gitlab/setup-cd.md @@ -0,0 +1,260 @@ +--- +title: Setup CD +--- + +# Setup CD + +Set up automatic updates for your Recce Cloud base sessions. Keep your data comparison baseline current every time you merge to main, with no manual work required. + +## Purpose + +**Automated Base Session Management** eliminates manual baseline maintenance. + +- **Triggers**: MR merge to main + scheduled updates +- **Action**: Auto-update base Recce session +- **Benefit**: Current comparison baseline for future MRs + +## Prerequisites + +You need `manifest.json` and `catalog.json` files (dbt artifacts) for Recce Cloud. See [Start Free with Cloud](../../2-getting-started/start-free-with-cloud.md) for instructions on preparing these files. + +## Implementation + +### 1. Core Workflow + +GitLab's CD setup uses the same Recce Cloud component as CI, but with different trigger rules. Add to your `.gitlab-ci.yml`: +```yaml +include: + - component: gitlab.com/recce/recce-cloud-cicd-component/recce-cloud@1.2.0 + inputs: + stage: upload + +stages: + - build + - upload + +variables: + DBT_TARGET_PROD: "prod" + +# Disable the default component job +recce-cloud-upload: + rules: + - when: never + +# Production build - runs on schedule or manual trigger +prod-build: + stage: build + image: python:3.11-slim + script: + - pip install -r requirements.txt + - dbt deps + + # Optional: Build tables to ensure they're materialized and updated + # - dbt build --target $DBT_TARGET_PROD + + # Required: Generate artifacts + - dbt docs generate --target $DBT_TARGET_PROD + artifacts: + paths: + - target/ + expire_in: 7 days + rules: + - if: $CI_PIPELINE_SOURCE == "schedule" + - if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + - if: $CI_PIPELINE_SOURCE == "web" + when: manual + +# Production Recce upload +recce-cloud-upload-prod: + extends: recce-cloud-upload + needs: + - job: prod-build + artifacts: true + rules: + - if: $CI_PIPELINE_SOURCE == "schedule" + - if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + - if: $CI_PIPELINE_SOURCE == "web" + when: manual +``` + +This configuration: + +- **Scheduled updates**: Runs automatically on schedule (configure in CI/CD → Schedules) +- **Post-merge updates**: Runs when commits are pushed to main branch +- **Manual triggers**: Available via web UI for on-demand updates + +### 2. Unified CI/CD Configuration + +The Recce Cloud component can handle both CI (MR validation) and CD (base session updates) in a single configuration. Here's the combined approach: +```yaml +include: + - component: gitlab.com/recce/recce-cloud-cicd-component/recce-cloud@1.2.0 + inputs: + stage: upload + +stages: + - build + - upload + +# Disable the default component job +recce-cloud-upload: + rules: + - when: never + +# MR build - runs on merge requests +mr-build: + stage: build + image: python:3.11-slim + script: + - pip install -r requirements.txt + - dbt deps + - dbt build --target dev + - dbt docs generate --target dev + artifacts: + paths: + - target/ + expire_in: 7 days + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + +# Production build - runs on schedule or main branch +prod-build: + stage: build + image: python:3.11-slim + script: + - pip install -r requirements.txt + - dbt deps + - dbt build --target prod + - dbt docs generate --target prod + artifacts: + paths: + - target/ + expire_in: 7 days + rules: + - if: $CI_PIPELINE_SOURCE == "schedule" + - if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + +# MR Recce upload +recce-cloud-upload-mr: + extends: recce-cloud-upload + needs: + - job: mr-build + artifacts: true + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + +# Production Recce upload +recce-cloud-upload-prod: + extends: recce-cloud-upload + needs: + - job: prod-build + artifacts: true + rules: + - if: $CI_PIPELINE_SOURCE == "schedule" + - if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH +``` + +This unified approach: + +- Uses the same component for both CI and CD +- Separates MR validation from production updates via `rules` +- Maintains different dbt targets for each environment +- Reduces configuration duplication + +### 3. Schedule Configuration + +To enable automatic baseline updates: + +1. Go to **CI/CD → Schedules** in your GitLab project +2. Click **New schedule** +3. Configure schedule: + - **Description**: "Daily Recce Base Session Update" + - **Interval Pattern**: `0 2 * * *` (Daily at 2 AM UTC) + - **Target Branch**: `main` +4. Save schedule + +### 4. Artifact Preparation Options + +**Default: Fresh Build** (shown in examples above) + +- `dbt docs generate` is required and provides needed `manifest.json` and `catalog.json` artifacts +- `dbt build` is optional but ensures tables are materialized and updated + +**Alternative Methods:** + +- **External Download**: Download from dbt Cloud, Paradime, or other platforms +- **Pipeline Integration**: Use existing dbt build workflows + +### 5. Verification + +#### Manual Trigger Test + +1. Go to **CI/CD → Pipelines** in your project +2. Click **Run pipeline** +3. Select **main** branch +4. Click **Run pipeline** button +5. Monitor the pipeline for successful completion + +#### Verify Success + +- ✅ **Pipeline completes** without errors in CI/CD → Pipelines +- ✅ **Base session updated** in Recce Cloud dashboard + +![Recce Cloud dashboard showing updated base sessions](../../assets/images/7-cicd/verify-setup-cd.png){: .shadow} + +#### Verify Scheduled Runs + +1. Go to **CI/CD → Schedules** +2. Check **Last pipeline** status for your schedule +3. Verify regular updates appear in pipeline history + +## Troubleshooting + +### Schedule not triggering + +**Issue**: Scheduled pipeline doesn't run + +**Solutions**: + +1. Verify schedule is **Active** in CI/CD → Schedules +2. Check schedule timezone settings (UTC by default) +3. Ensure target branch exists and is protected if required +4. Review project's CI/CD minutes quota + +### Branch protection issues + +**Error**: Pipeline fails on protected branch + +**Solutions**: + +1. Configure protected branch settings to allow scheduled pipelines +2. Ensure CI/CD variables are available to protected branches +3. Verify schedule owner has push permissions + +### Artifact conflicts + +**Issue**: Wrong artifacts uploaded for production + +**Solutions**: + +1. Ensure `needs` dependencies are correct in upload jobs +2. Verify artifact paths match between build and upload jobs: +```yaml +prod-build: + artifacts: + paths: + - target/ # Must match component's dbt_target_path + +recce-cloud-upload-prod: + needs: + - job: prod-build + artifacts: true # Required +``` + +## Complete Example + +See the [complete working example](https://gitlab.com/recce/jaffle-shop-snowflake/-/blob/main/.gitlab-ci.yml) showing unified CI/CD configuration with the Recce Cloud component. + +## Next Steps + +If you haven't already, **[Setup CI](./setup-ci.md)** to automatically validate MR changes. The unified configuration above handles both CI and CD together, giving you a complete automated validation pipeline. diff --git a/docs/7-cicd/gitlab/setup-ci.md b/docs/7-cicd/gitlab/setup-ci.md new file mode 100644 index 0000000..7c18595 --- /dev/null +++ b/docs/7-cicd/gitlab/setup-ci.md @@ -0,0 +1,218 @@ +--- +title: Setup CI +--- + +# Setup CI + +Automatically validate your data changes in every merge request using Recce Cloud. Catch data issues before they reach production, with validation results right in your MR. + +## Purpose + +**Automated MR Validation** prevents data regressions before merge. + +- **Triggers**: MR opened/updated against main +- **Action**: Auto-update Recce session for MR validation +- **Benefit**: Automated data validation and comparison + +## Prerequisites + +You need `manifest.json` and `catalog.json` files (dbt artifacts) for Recce Cloud. See [Start Free with Cloud](../../2-getting-started/start-free-with-cloud.md) for instructions on preparing these files. + +## Implementation + +### 1. Core Workflow + +Add to your `.gitlab-ci.yml`: +```yaml +include: + - component: gitlab.com/recce/recce-cloud-cicd-component/recce-cloud@1.2.0 + inputs: + stage: test + +stages: + - build + - test + +variables: + DBT_TARGET: "ci" + +dbt-build: + stage: build + image: python:3.11-slim + script: + - pip install -r requirements.txt + + # Install dbt packages + - dbt deps + + # Optional: Build tables to ensure they're materialized + # - dbt build --target $DBT_TARGET + + # Required: Generate artifacts for comparison + - dbt docs generate --target $DBT_TARGET + artifacts: + paths: + - target/ + expire_in: 1 week + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" +``` + +The included Recce Cloud component automatically: +- Creates a session in Recce Cloud for the merge request +- Uploads your dbt artifacts (`manifest.json` and `catalog.json`) +- Provides session URL for validation review + +### 2. Component Configuration Options + +The component accepts optional inputs for customization: +```yaml +include: + - component: gitlab.com/recce/recce-cloud-cicd-component/recce-cloud@1.2.0 + inputs: + stage: test # Pipeline stage (default: test) + dbt_target_path: target # Path to dbt artifacts (default: target) + base_branch: main # Base branch for comparison (default: main) + gitlab_token: $CUSTOM_GITLAB_TOKEN # Custom GitLab token (default: $CI_JOB_TOKEN) +``` + +**Default Configuration** (shown in example above): + +- Component uses `$CI_JOB_TOKEN` automatically (no manual token setup required) +- Uploads from `target/` directory by default +- Compares against `main` branch + +**Custom Token** (optional): + +If you need to use a custom GitLab token instead of the default `$CI_JOB_TOKEN`: + +1. Create a [Project Access Token](../gitlab-pat-guide.md) with `api` scope +2. Add it as a [CI/CD variable](https://docs.gitlab.com/ee/ci/variables/) in your project +3. Reference it in the component inputs: +```yaml +include: + - component: gitlab.com/recce/recce-cloud-cicd-component/recce-cloud@1.2.0 + inputs: + gitlab_token: $CUSTOM_GITLAB_TOKEN +``` + +### 3. Artifact Preparation Options + +**Default: Fresh Build** (shown in example above) + +- `dbt docs generate` is required and provides all needed artifacts +- `dbt build` is optional but ensures tables are materialized and updated + +**Alternative Methods:** + +- **External Download**: Download from dbt Cloud, Paradime, or other platforms +- **Pipeline Integration**: Use existing dbt build workflows + +### 4. Verification + +#### Test with an MR + +1. Create a test MR with small data changes +2. Check **CI/CD → Pipelines** for workflow execution +3. Verify validation runs successfully + +#### Verify Success + +- ✅ **Pipeline completes** without errors in CI/CD → Pipelines +- ✅ **MR session updated** in Recce Cloud dashboard +- ✅ **Session URL** appears in pipeline job output + +![Recce Cloud showing MR validation session](../../assets/images/7-cicd/verify-setup-ci.png){: .shadow} + +#### Review MR Session + +To analyze the MR changes in detail: + +- Go to your [Recce Cloud dashboard](https://cloud.reccehq.com) +- Find the MR session that was created +- Launch Recce instance to explore data differences + +Or use the session launch URL from the pipeline output: +```bash +# Pipeline output example +RECCE_SESSION_LAUNCH_URL: https://cloud.reccehq.com/launch/abc123 +``` + +## Troubleshooting + +### Missing dbt files + +**Error**: `Missing manifest.json` or `Missing catalog.json` + +**Solution**: Ensure `dbt docs generate` runs successfully before the Recce component: +```yaml +dbt-build: + script: + - dbt build + - dbt docs generate # Required + artifacts: + paths: + - target/ +``` + +### Authentication issues + +**Error**: `Failed to create session: 401 Unauthorized` + +**Solutions**: + +1. Verify Recce Cloud GitLab integration is set up for your project +2. Check that your project is connected in [Recce Cloud settings](https://cloud.reccehq.com/settings) +3. For custom tokens, ensure the token has `api` scope ([setup guide](../gitlab-pat-guide.md)) + +### Upload failures + +**Error**: `Failed to upload manifest/catalog` + +**Solutions**: + +1. Check network connectivity to Recce Cloud +2. Verify artifact files exist in `target/` directory +3. Review pipeline job logs for detailed error messages +4. Ensure artifacts are passed between jobs: +```yaml +dbt-build: + artifacts: + paths: + - target/ # Must include dbt artifacts +``` + +## Complete Example + +Here's a full working example combining dbt build and Recce validation: +```yaml +include: + - component: gitlab.com/recce/recce-cloud-cicd-component/recce-cloud@1.2.0 + inputs: + stage: test + +stages: + - build + - test + +variables: + DBT_TARGET: "ci" + +dbt-build: + stage: build + image: python:3.11-slim + before_script: + - pip install -r requirements.txt + script: + - dbt deps + - dbt build --target $DBT_TARGET + - dbt docs generate --target $DBT_TARGET + artifacts: + paths: + - target/ + expire_in: 1 week + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" +``` + +See the [complete example project](https://gitlab.com/recce/jaffle-shop-snowflake/-/blob/main/.gitlab-ci.yml) for a full working configuration. diff --git a/docs/styles/extra.css b/docs/styles/extra.css index 804cf65..54ecd99 100644 --- a/docs/styles/extra.css +++ b/docs/styles/extra.css @@ -16,6 +16,11 @@ --md-typeset-a-color: #ff6e42; --md-default-fg-color--light: #e7e8ef; --md-default-fg-color--dark: #e7e7ea; + --md-code-hl-operator-color: var(--md-default-fg-color--dark); + --md-code-hl-punctuation-color: var(--md-default-fg-color--dark); + --md-code-hl-comment-color: var(--md-default-fg-color--dark); + --md-code-hl-generic-color: var(--md-default-fg-color--dark); + --md-code-hl-variable-color: var(--md-default-fg-color--dark); --md-default-bg-color: oklch(0.248 0.016 269.03); --md-default-fg-color: #e7e8ef; --md-code-bg-color: #0b121e; diff --git a/mkdocs.yml b/mkdocs.yml index 0e045c0..618af9d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -75,21 +75,29 @@ nav: - 6-collaboration/checklist.md - 6-collaboration/share.md - CI/CD: - - 7-cicd/setup-cd.md - - Development: - - 7-cicd/scenario-dev.md - #- 7-cicd/recce-debug.md # content outdated - - Continuous Integration: - - 7-cicd/setup-ci.md + # Brief intro explaining GitHub vs GitLab paths + - 7-cicd/getting-started.md + + # GitHub CI/CD + - Using GitHub: + - 7-cicd/github/setup-ci.md #- 7-cicd/cloud-recce-summary.md #- 7-cicd/cloud-preset-checks.md - - 7-cicd/scenario-pr-review.md - - CI/CD for Open Source: - - 7-cicd/scenario-ci.md + - 7-cicd/github/scenario-ci.md + - 7-cicd/github/setup-cd.md + + # GitLab CI/CD + - Using GitLab: + - 7-cicd/gitlab/setup-ci.md + - 7-cicd/gitlab/setup-cd.md + - 7-cicd/gitlab/gitlab-pat-guide.md + + #- 7-cicd/recce-debug.md # content outdated + - 7-cicd/scenario-dev.md + - 7-cicd/scenario-pr-review.md + - 7-cicd/best-practices-prep-env.md #- 7-cicd/recce-summary.md content outdated - 7-cicd/preset-checks.md - - 7-cicd/best-practices-prep-env.md - - 7-cicd/gitlab-pat-guide.md - Technical Concepts: - 8-technical-concepts/state-file.md From 5588a26f78dc5eadfb7cbe562252b5061556eb1f Mon Sep 17 00:00:00 2001 From: Jared Scott Date: Thu, 30 Oct 2025 16:02:05 +0800 Subject: [PATCH 2/5] feat: DRC-1868 - Add missing newline Signed-off-by: Jared Scott --- docs/7-cicd/gitlab/setup-ci.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/7-cicd/gitlab/setup-ci.md b/docs/7-cicd/gitlab/setup-ci.md index 7c18595..35d5134 100644 --- a/docs/7-cicd/gitlab/setup-ci.md +++ b/docs/7-cicd/gitlab/setup-ci.md @@ -59,6 +59,7 @@ dbt-build: ``` The included Recce Cloud component automatically: + - Creates a session in Recce Cloud for the merge request - Uploads your dbt artifacts (`manifest.json` and `catalog.json`) - Provides session URL for validation review From 064f90325930cd0c3ad40e2c5c3aee46866a23ab Mon Sep 17 00:00:00 2001 From: Jared Scott Date: Thu, 30 Oct 2025 17:10:14 +0800 Subject: [PATCH 3/5] feat: DRC-1868 - Fix Karen's comments Signed-off-by: Jared Scott --- .../{getting-started.md => ci-cd-getting-started.md} | 10 +++++----- mkdocs.yml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) rename docs/7-cicd/{getting-started.md => ci-cd-getting-started.md} (98%) diff --git a/docs/7-cicd/getting-started.md b/docs/7-cicd/ci-cd-getting-started.md similarity index 98% rename from docs/7-cicd/getting-started.md rename to docs/7-cicd/ci-cd-getting-started.md index 2d51cec..c18d508 100644 --- a/docs/7-cicd/getting-started.md +++ b/docs/7-cicd/ci-cd-getting-started.md @@ -1,8 +1,8 @@ --- -title: Getting Started +title: CI/CD Getting Started --- -# Getting Started +# CI/CD Getting Started Automate data validation in your development workflow. Catch data issues before they reach production with continuous integration and delivery built specifically for dbt projects. @@ -15,6 +15,9 @@ Set up automated workflows that: - **Prevent regressions** - Catch data quality issues before they reach production - **Save team time** - Eliminate manual validation steps for every change +!!!note + CI/CD automation requires Recce Cloud Team plan. A free trial is available. + ## Understanding CI vs CD Recce uses both continuous integration and continuous delivery to automate data validation: @@ -51,9 +54,6 @@ If your dbt project uses GitLab: 1. [Setup CD](./gitlab/setup-cd.md) - Auto-update baseline on merge to main 3. [GitLab Personal Access Token Guide](./gitlab/gitlab-pat-guide.md) - Required for GitLab integration -!!!note - CI/CD automation requires Recce Cloud Team plan. A free trial is available. - ## Prerequisites Before setting up, ensure you have: diff --git a/mkdocs.yml b/mkdocs.yml index 618af9d..908667f 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -76,7 +76,7 @@ nav: - 6-collaboration/share.md - CI/CD: # Brief intro explaining GitHub vs GitLab paths - - 7-cicd/getting-started.md + - 7-cicd/ci-cd-getting-started.md # GitHub CI/CD - Using GitHub: From 30752a0d744930b9864a531efcd9366efeab2139 Mon Sep 17 00:00:00 2001 From: Jared Scott Date: Thu, 30 Oct 2025 17:11:53 +0800 Subject: [PATCH 4/5] feat: DRC-1868 - Change to Recce Cloud from Recce Cloud dashboard Signed-off-by: Jared Scott --- docs/7-cicd/github/setup-cd.md | 4 ++-- docs/7-cicd/github/setup-ci.md | 4 ++-- docs/7-cicd/gitlab/setup-cd.md | 4 ++-- docs/7-cicd/gitlab/setup-ci.md | 4 ++-- docs/7-cicd/setup-cd.md | 4 ++-- docs/7-cicd/setup-ci.md | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/7-cicd/github/setup-cd.md b/docs/7-cicd/github/setup-cd.md index 5a452b2..aa77249 100644 --- a/docs/7-cicd/github/setup-cd.md +++ b/docs/7-cicd/github/setup-cd.md @@ -100,9 +100,9 @@ jobs: #### Verify Success - ✅ **Workflow completes** without errors in Actions tab -- ✅ **Base session updated** in Recce Cloud dashboard +- ✅ **Base session updated** in Recce Cloud -![Recce Cloud dashboard showing updated base sessions](/assets/images/7-cicd/verify-setup-cd.png){: .shadow} +![Recce Cloud showing updated base sessions](/assets/images/7-cicd/verify-setup-cd.png){: .shadow} ## Next Steps diff --git a/docs/7-cicd/github/setup-ci.md b/docs/7-cicd/github/setup-ci.md index 0cacd0c..7922669 100644 --- a/docs/7-cicd/github/setup-ci.md +++ b/docs/7-cicd/github/setup-ci.md @@ -98,7 +98,7 @@ jobs: #### Verify Success - ✅ **Workflow completes** without errors in Actions tab -- ✅ **PR session updated** in Recce Cloud dashboard +- ✅ **PR session updated** in Recce Cloud ![Recce Cloud showing PR validation session](/assets/images/7-cicd/verify-setup-ci.png){: .shadow} @@ -106,6 +106,6 @@ jobs: To analyze the PR changes in detail: -- Go to your [Recce Cloud dashboard](https://cloud.reccehq.com) +- Go to your [Recce Cloud](https://cloud.reccehq.com) - Find the PR session that was created - Launch Recce instance to explore data differences diff --git a/docs/7-cicd/gitlab/setup-cd.md b/docs/7-cicd/gitlab/setup-cd.md index d78127e..f2dabf2 100644 --- a/docs/7-cicd/gitlab/setup-cd.md +++ b/docs/7-cicd/gitlab/setup-cd.md @@ -198,9 +198,9 @@ To enable automatic baseline updates: #### Verify Success - ✅ **Pipeline completes** without errors in CI/CD → Pipelines -- ✅ **Base session updated** in Recce Cloud dashboard +- ✅ **Base session updated** in Recce Cloud -![Recce Cloud dashboard showing updated base sessions](../../assets/images/7-cicd/verify-setup-cd.png){: .shadow} +![Recce Cloud showing updated base sessions](../../assets/images/7-cicd/verify-setup-cd.png){: .shadow} #### Verify Scheduled Runs diff --git a/docs/7-cicd/gitlab/setup-ci.md b/docs/7-cicd/gitlab/setup-ci.md index 35d5134..5406989 100644 --- a/docs/7-cicd/gitlab/setup-ci.md +++ b/docs/7-cicd/gitlab/setup-ci.md @@ -120,7 +120,7 @@ include: #### Verify Success - ✅ **Pipeline completes** without errors in CI/CD → Pipelines -- ✅ **MR session updated** in Recce Cloud dashboard +- ✅ **MR session updated** in Recce Cloud - ✅ **Session URL** appears in pipeline job output ![Recce Cloud showing MR validation session](../../assets/images/7-cicd/verify-setup-ci.png){: .shadow} @@ -129,7 +129,7 @@ include: To analyze the MR changes in detail: -- Go to your [Recce Cloud dashboard](https://cloud.reccehq.com) +- Go to your [Recce Cloud](https://cloud.reccehq.com) - Find the MR session that was created - Launch Recce instance to explore data differences diff --git a/docs/7-cicd/setup-cd.md b/docs/7-cicd/setup-cd.md index 891f4e0..1a7f866 100644 --- a/docs/7-cicd/setup-cd.md +++ b/docs/7-cicd/setup-cd.md @@ -100,9 +100,9 @@ jobs: #### Verify Success - ✅ **Workflow completes** without errors in Actions tab -- ✅ **Base session updated** in Recce Cloud dashboard +- ✅ **Base session updated** in Recce Cloud -![Recce Cloud dashboard showing updated base sessions](../assets/images/7-cicd/verify-setup-cd.png){: .shadow} +![Recce Cloud showing updated base sessions](../assets/images/7-cicd/verify-setup-cd.png){: .shadow} ## Next Steps diff --git a/docs/7-cicd/setup-ci.md b/docs/7-cicd/setup-ci.md index 2668ab4..4a9e9b0 100644 --- a/docs/7-cicd/setup-ci.md +++ b/docs/7-cicd/setup-ci.md @@ -98,7 +98,7 @@ jobs: #### Verify Success - ✅ **Workflow completes** without errors in Actions tab -- ✅ **PR session updated** in Recce Cloud dashboard +- ✅ **PR session updated** in Recce Cloud ![Recce Cloud showing PR validation session](../assets/images/7-cicd/verify-setup-ci.png){: .shadow} @@ -106,6 +106,6 @@ jobs: To analyze the PR changes in detail: -- Go to your [Recce Cloud dashboard](https://cloud.reccehq.com) +- Go to your [Recce Cloud](https://cloud.reccehq.com) - Find the PR session that was created - Launch Recce instance to explore data differences From 1af1b35c8fe7fcffdb1f0a8bddcd5545e7542acc Mon Sep 17 00:00:00 2001 From: Jared Scott Date: Thu, 30 Oct 2025 17:17:37 +0800 Subject: [PATCH 5/5] feat: DRC-1868 - Refactor section in start-free-with-cloud.md - Cleanup titles to make it clearer Signed-off-by: Jared Scott --- docs/2-getting-started/start-free-with-cloud.md | 12 +++++++----- docs/7-cicd/ci-cd-getting-started.md | 1 - docs/7-cicd/github/setup-cd.md | 2 +- docs/7-cicd/github/setup-ci.md | 2 +- docs/7-cicd/gitlab/setup-cd.md | 2 +- docs/7-cicd/gitlab/setup-ci.md | 2 +- mkdocs.yml | 2 +- 7 files changed, 12 insertions(+), 11 deletions(-) diff --git a/docs/2-getting-started/start-free-with-cloud.md b/docs/2-getting-started/start-free-with-cloud.md index 5ed516a..cefeb57 100644 --- a/docs/2-getting-started/start-free-with-cloud.md +++ b/docs/2-getting-started/start-free-with-cloud.md @@ -172,11 +172,13 @@ Set up CI/CD to automatically upload metadata and run validation checks on every See the CI/CD sections for complete setup guides: -- [Setup CD](/7-cicd/setup-cd/) -- [Setup CI](/7-cicd/setup-ci/) - -- GitHub integration configured -- Team plan subscription or free trial +- [Getting Started with CI/CD](../7-cicd/ci-cd-getting-started.md) +- GitHub CI/CD + - [Setup CI for GitHub](../7-cicd/github/setup-ci.md) + - [Setup CD for GitHub](../7-cicd/github/setup-cd.md) +- GitLab CI/CD + - [Setup CI for Gitlab](../7-cicd/gitlab/setup-ci.md) + - [Setup CD for Gitlab](../7-cicd/gitlab/setup-cd.md) ### Automation Benefits diff --git a/docs/7-cicd/ci-cd-getting-started.md b/docs/7-cicd/ci-cd-getting-started.md index c18d508..395a81c 100644 --- a/docs/7-cicd/ci-cd-getting-started.md +++ b/docs/7-cicd/ci-cd-getting-started.md @@ -45,7 +45,6 @@ If your dbt project uses GitHub: 1. [Setup CI](./github/setup-ci.md) - Auto-validate changes in every PR 2. [Setup CD](./github/setup-cd.md) - Auto-update baseline on merge to main -3. [Open Source Setup](./github/scenario-ci.md) - Alternative approach for open source projects ### GitLab If your dbt project uses GitLab: diff --git a/docs/7-cicd/github/setup-cd.md b/docs/7-cicd/github/setup-cd.md index aa77249..810f628 100644 --- a/docs/7-cicd/github/setup-cd.md +++ b/docs/7-cicd/github/setup-cd.md @@ -1,5 +1,5 @@ --- -title: Setup CD +title: Setup CD for GitHub --- # Setup CD diff --git a/docs/7-cicd/github/setup-ci.md b/docs/7-cicd/github/setup-ci.md index 7922669..730386c 100644 --- a/docs/7-cicd/github/setup-ci.md +++ b/docs/7-cicd/github/setup-ci.md @@ -1,5 +1,5 @@ --- -title: Setup CI +title: Setup CI for GitHub --- # Setup CI diff --git a/docs/7-cicd/gitlab/setup-cd.md b/docs/7-cicd/gitlab/setup-cd.md index f2dabf2..b9f3ecb 100644 --- a/docs/7-cicd/gitlab/setup-cd.md +++ b/docs/7-cicd/gitlab/setup-cd.md @@ -1,5 +1,5 @@ --- -title: Setup CD +title: Setup CD for GitLab --- # Setup CD diff --git a/docs/7-cicd/gitlab/setup-ci.md b/docs/7-cicd/gitlab/setup-ci.md index 5406989..a6a13ff 100644 --- a/docs/7-cicd/gitlab/setup-ci.md +++ b/docs/7-cicd/gitlab/setup-ci.md @@ -1,5 +1,5 @@ --- -title: Setup CI +title: Setup CI for GitLab --- # Setup CI diff --git a/mkdocs.yml b/mkdocs.yml index 908667f..f121729 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -83,7 +83,7 @@ nav: - 7-cicd/github/setup-ci.md #- 7-cicd/cloud-recce-summary.md #- 7-cicd/cloud-preset-checks.md - - 7-cicd/github/scenario-ci.md +# - 7-cicd/github/scenario-ci.md - 7-cicd/github/setup-cd.md # GitLab CI/CD