> ## Documentation Index
> Fetch the complete documentation index at: https://docs.paradime.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Column-Level Lineage Diff on Azure DevOps

> Set up Paradime Column-Level Lineage Diff on Azure DevOps pull requests to post upstream and downstream column-impact reports as PR comments for dbt™ changes.

export const Arcade = ({src, title}) => <div style={{
  position: 'relative',
  paddingBottom: 'calc(56.2225% + 41px)',
  height: 0,
  width: '100%'
}}>
    <iframe src={src} title={title} frameBorder="0" loading="lazy" allow="clipboard-write" allowFullScreen style={{
  position: 'absolute',
  top: 0,
  left: 0,
  width: '100%',
  height: '100%',
  colorScheme: 'light'
}} />
  </div>;

Set up Column-Level Lineage Diff on Azure DevOps. First complete the shared [Lineage Diff prerequisites](/products/bolt/ci-cd/lineage-diff/index), then configure your Azure DevOps pipeline.

<Frame>
  <img src="https://2337193041-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FHET0AD04uHMgdeLAjptq%2Fuploads%2FARJwpjOJrlQ6rMRuO693%2Fimage.png?alt=media&token=ce564f1e-12a9-48bb-9e2e-cfdbd5cb35e3" alt="" />
</Frame>

***

## Generate API keys

Generate a Paradime [API key](/developers/api-keys) with the **Bolt schedules admin** capability. Use an **Account API key** (a `prdm_cmp_...` Bearer token), and note your **workspace token** and **API endpoint**; you will add them as CI/CD variables in a later step.

<Card title="Generate API keys" href="/developers/api-keys" horizontal icon="arrow-right" />

## Create an Azure Pipeline

Now you will need to create a new `azure-pipeline.yml` file in your dbt™️ repository. Copy the code below.

This pipeline has two jobs:

1. **`paradime_turbo_ci`** — Runs the Turbo CI bolt schedule and passes the `BOLT_RUN_ID` to the next job.
2. **`lineage_diff_report`** — Uses the `BOLT_RUN_ID` to trigger the lineage diff report and posts the result as a comment on the Pull Request.

```yaml theme={"system"}
trigger:
  - none

pr:
  - "*"

jobs:
  - job: paradime_turbo_ci
    displayName: "Run Paradime Turbo CI"
    pool:
      vmImage: ubuntu-latest
    variables:
      PARADIME_SCHEDULE_SLUG: "flowing-pachy-wyy4fs"
    steps:
      - task: UsePythonVersion@0
        inputs:
          versionSpec: "3.11"
          addToPath: true
        displayName: Use Python 3.11

      - checkout: self
        fetchDepth: 0
        displayName: Clone repository

      - script: |
          pip install paradime-io

          echo "Merge Request Number: $(System.PullRequest.PullRequestId)"
          echo "Commit SHA: $(System.PullRequest.SourceCommitId)"

          python3 -u <<EOF
          import os
          from paradime import Paradime

          paradime = Paradime(
            workspace_uid=os.environ['PARADIME_WORKSPACE_UID'],
            api_secret=os.environ['PARADIME_API_SECRET'],
            api_endpoint=os.environ['PARADIME_API_ENDPOINT']
          )

          run_id = paradime.bolt.trigger_run(
            slug=os.environ['PARADIME_SCHEDULE_SLUG'],
            branch=os.environ['SOURCE_COMMIT_SHA'],
            pr_number=int(os.environ['PR_NUMBER']),
          )

          print(f"Bolt Run ID: {run_id}")

          with open("bolt_run_id.txt", "w") as f:
            f.write(str(run_id))
          EOF

          BOLT_RUN_ID=$(cat bolt_run_id.txt)
          echo "##vso[task.setvariable variable=BOLT_RUN_ID;isOutput=true]$BOLT_RUN_ID"
        name: runTurboCI
        displayName: "Run Turbo CI and export Bolt Run ID"
        env:
          PARADIME_WORKSPACE_UID: $(PARADIME_WORKSPACE_UID)
          PARADIME_API_SECRET: $(PARADIME_API_SECRET)
          PARADIME_API_ENDPOINT: $(PARADIME_API_ENDPOINT)
          SOURCE_COMMIT_SHA: $(System.PullRequest.SourceCommitId)
          PR_NUMBER: $(System.PullRequest.PullRequestId)

  - job: lineage_diff_report
    displayName: "Generate Lineage Diff Report"
    dependsOn: paradime_turbo_ci
    pool:
      vmImage: ubuntu-latest
    variables:
      BOLT_RUN_ID: $[ dependencies.paradime_turbo_ci.outputs['runTurboCI.BOLT_RUN_ID'] ]
    steps:
      - task: UsePythonVersion@0
        inputs:
          versionSpec: "3.11"
          addToPath: true
        displayName: Use Python 3.11

      - checkout: self
        fetchDepth: 0
        displayName: Clone repository

      - script: |
          pip install paradime-io

          echo "Bolt Run ID: $BOLT_RUN_ID"
          echo "Pull Request Number: $(System.PullRequest.PullRequestId)"
          echo "Pull Request Author Email: $(Build.RequestedForEmail)"

          export BASE_COMMIT_SHA=$(git rev-parse origin/$(System.PullRequest.TargetBranchName))
          export HEAD_COMMIT_SHA=$(System.PullRequest.SourceCommitId)
          export CHANGED_FILES=$(git diff --name-only $BASE_COMMIT_SHA $HEAD_COMMIT_SHA)
          echo "Files changed in this PR: $CHANGED_FILES"

          export REPORT_FILE="report_$(openssl rand -hex 12).txt"

          python3 -u <<EOF
          import os
          import json
          from pathlib import Path
          from paradime import Paradime

          paradime = Paradime(
            workspace_uid=os.environ['PARADIME_WORKSPACE_UID'],
            api_secret=os.environ['PARADIME_API_SECRET'],
            api_endpoint=os.environ['PARADIME_API_ENDPOINT']
          )

          report = paradime.lineage_diff.trigger_report_and_wait(
            bolt_run_id=int(os.environ['BOLT_RUN_ID']),
            pull_request_number=int(os.environ['PR_NUMBER']),
            user_email=os.environ['USER_EMAIL'],
            changed_file_paths=os.environ['CHANGED_FILES'].split('\\n'),
          )

          print("Lineage Diff Report Message:", report.message)

          if report.result_markdown:
            Path(os.environ['REPORT_FILE']).write_text(report.result_markdown)
          EOF

          if [ -f "$REPORT_FILE" ]; then
            COMMENT=$(cat "$REPORT_FILE")
            ADO_API="$(System.CollectionUri)$(System.TeamProject)/_apis/git/repositories/$(Build.Repository.Name)/pullRequests/$(System.PullRequest.PullRequestId)/threads?api-version=7.1-preview.1"
            PR_COMMENT=$(jq -n --arg comment "$COMMENT" '{"comments": [{"parentCommentId": 0, "content": $comment, "commentType": 1}], "status": 1}')

            curl --request POST "$ADO_API" \
              --header "Content-Type: application/json" \
              --header "Accept: application/json" \
              --header "Authorization: Bearer $(System.AccessToken)" \
              --data "$PR_COMMENT"
          else
            echo "Report file not found, skipping comment."
          fi
        displayName: "Generate report and comment on PR"
        env:
          PARADIME_WORKSPACE_UID: $(PARADIME_WORKSPACE_UID)
          PARADIME_API_SECRET: $(PARADIME_API_SECRET)
          PARADIME_API_ENDPOINT: $(PARADIME_API_ENDPOINT)
          BOLT_RUN_ID: $(BOLT_RUN_ID)
          PR_NUMBER: $(System.PullRequest.PullRequestId)
          USER_EMAIL: $(Build.RequestedForEmail)
```

## Add the API keys and Credential in the Azure Pipeline variables

Finally you need to add the API key and credentials generated in the previous step in Azure Pipelines.

Set the corresponding values using your credentials for the variable names:

* `PARADIME_WORKSPACE_UID`
* `PARADIME_API_SECRET`
* `PARADIME_API_ENDPOINT`

<Arcade src="https://demo.arcade.software/tCJyMGYsHX7weycpd3kq?embed&embed_mobile=tab&embed_desktop=inline&show_copy_link=true" title="Column-Level Lineage Diff" />

## Update Build Service User Permissions

You will need to add the Contribute to pull requests permission to enable Comments to be generated when opening the Pull Request.

Go to Project Settings in Azure DevOps

* Navigate to "Repositories" under Repos
* Select your repository
* Click "Security"
* Find "Project Collection Build Service" or "\[Project Name] Build Service"
* Set "Contribute to pull requests" to **allowed**

<Frame>
  <img src="https://2337193041-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FHET0AD04uHMgdeLAjptq%2Fuploads%2FWktZYl8dWiDHinfTQaqi%2Fimage.png?alt=media&token=585e92cf-202a-4659-9fb2-94ded20c89e2" alt="" />
</Frame>


## Related topics

- [Column-Level Lineage Diff](/products/bolt/ci-cd/lineage-diff/index.md)
- [Azure DevOps](/products/settings/git-repositories/importing-a-repository/azure-devops.md)
- [Create Azure DevOps Items](/products/bolt/creating-schedules/templates/ticketing-templates/create-azure-devops-items.md)
- [Turbo CI on Azure DevOps pull requests](/products/bolt/ci-cd/turbo-ci/azure-devops.md)
- [Lineage Diff](/developers/python-sdk/modules/lineage-diff.md)
