// project 03 DEV

CI/CD Pipeline Blueprint

Complete CI/CD platform: setup once with the Pipeline Manager, develop daily with Developer Tools. Five CI vendors, zero context switching.

A reusable CI/CD setup for Salesforce teams. The same delta-deployment logic is templated for five CI platforms, with Apex test gating, automatic rollback and secrets handling built in. Two VSCode extensions sit on top: one to generate and manage the pipeline, one for daily development. The aim is simple: deploy only what changed, prove it with tests, and roll back automatically if anything fails.

05 ci platforms templated 02 vscode extensions Δ delta-only deploys Auto rollback on failure
pipeline_architecture [01]

End-to-End Flow

Every push reads ci-config.json to decide what to do. Feature branches validate check-only, so a pull request is proven against the target org before it merges. Environment branches run the full sequence: authenticate, work out the delta, deploy, test, tag on success, or roll back on failure.

flowchart TD
    A["Git Push"] --> B["Read ci-config.json"]
    B --> C{"Branch type?"}

    C -->|"feature/*"| D["feature/* branch"]
    D --> F["Validate only
(check-only)"] F --> G["Apex tests"] G --> H["PR into base"] C -->|"env branch"| E["env branch
(sit / qa / uat / staging / main)"] E --> I["Authenticate org
(SFDX Auth URL)"] I --> J["sfdx-git-delta
detect changed metadata"] J --> K["Generate destructiveChanges.xml
for deletions"] K --> L["sf project deploy start
deploy the delta"] L --> M["sf apex run test
gate on test results"] M --> N{"Success?"} N -->|"Yes"| O["Tag deployed/<env>"] N -->|"No"| P["scripts/rollback.sh"] %% Blueprint tokens as literal hex (Mermaid cannot parse CSS vars or color-mix) classDef trigger fill:#e0be621f,stroke:#e0be62,color:#dfe4ee,stroke-width:1.5px; classDef ci fill:#8b93e81f,stroke:#8b93e8,color:#dfe4ee,stroke-width:1.5px; classDef sf fill:#62d99a1f,stroke:#62d99a,color:#dfe4ee,stroke-width:1.5px; classDef decision fill:#e0be621f,stroke:#e0be62,color:#dfe4ee,stroke-width:1.5px; classDef ok fill:#62d99a1f,stroke:#62d99a,color:#dfe4ee,stroke-width:1.5px; classDef fail fill:#e697521f,stroke:#e69752,color:#dfe4ee,stroke-width:1.5px; class A trigger; class C,N decision; class B,D,E,F,G,H ci; class I,J,K,L,M sf; class O ok; class P fail;
Branch Model
Set in ci-config.json

Map any branch pattern to any org alias. The default uses feature/* for validation, a base branch for integration, and named environment branches (sit, qa, uat, staging, main) for sequential promotion.

First Run
Falls Back to a Full Deploy

With no deployed/<env> tag to diff against, the first run deploys everything from package.xml. Every run after that is a delta from the last successful tag.

core_strategy [02]

Delta Deployment

Only changed metadata is deployed on each run. sfdx-git-delta diffs the current commit against the last successful deploy tag to build a precise delta package, and works out which metadata was deleted so it can be removed cleanly. A delta with no members is skipped entirely, so a docs-only commit never triggers an empty deploy.

Faster Deploys
Deploy Only What Changed

A one-file change deploys one file. No full-org deploy on every push, so pipeline time does not balloon as the org grows.

Smaller Blast Radius
Lower Risk Per Deploy

Touching only the changed components keeps each deploy scoped to the work in flight, which means fewer unintended side effects.

Deletions Handled
Auto destructiveChanges.xml

sfdx-git-delta generates destructiveChanges.xml for anything removed from source. No hand-maintained delete manifest.

Tag-based accuracy: each successful deploy pushes a deployed/<env> git tag. The next run diffs from that exact point, so the delta tracks the real state of the org rather than just the previous commit.
ci_platforms [03]

Five Platforms, One Logic

The delta-deploy logic is identical across platforms. Each template just handles its own quirks: how to fetch full git history, what the branch variable is called, how secrets are injected, and how test results are published.

GitHub Actions
.github/workflows/sfdx-ci.yml

fetch-depth: 0 for full history. Secrets via secrets.<NAME>. Test artifacts via upload-artifact.

Azure DevOps
azure-pipelines.yml

Full clone via fetchDepth: '0'. Auth URLs injected via env block. Results via PublishTestResults.

GitLab CI/CD
.gitlab-ci.yml

GIT_DEPTH: 0 for history. Base image node:20. JUnit via artifacts:reports:junit.

Jenkins
Jenkinsfile

GitSCM checkout with shallow: false. Credentials via credentials(). Results via junit post step.

Bitbucket Pipelines
bitbucket-pipelines.yml

clone: depth: full. Base image node:20. Pipelines can be toggled on via REST API.

recovery_and_quality_gate [04]

Automatic Rollback

Each deploy is preceded by a metadata backup via sf project retrieve. If the deploy errors or a test fails, scripts/rollback.sh restores the org from that backup before the pipeline exits.

# Pre-deploy backup
sf project retrieve start \
--output-dir backups/<env>/<timestamp>
# On failure
scripts/rollback.sh --env staging

Apex Test Gating

After each deploy, scripts/run-tests.sh runs local Apex tests via sf apex run test. Results publish as JUnit artifacts, and any failure triggers rollback before the run ends.

sf apex run test \
--test-level RunLocalTests \
--result-format junit \
--output-dir test-results
# Failure → rollback → pipeline fails
security [05]

Secrets Management

SFDX Auth URLs live as CI secrets, never in source. One secret per org alias, named <ORGALIAS_UPPER>_AUTH_URL. The Pipeline Manager extension generates the checklist of exactly which secrets to add.

# Get the auth URL for any org
sf org display \
--verbose --json \
--target-org sit \
| jq -r '.result.sfdxAuthUrl'
Secret name Purpose
SIT_AUTH_URLSIT environment
QA_AUTH_URLQA environment
UAT_AUTH_URLUAT environment
STAGING_AUTH_URLStaging environment
PROD_AUTH_URLProduction
configuration [06]

ci-config.json

The single source of truth for pipeline behaviour. Generated by the setup wizard, validated by a JSON schema, and read at runtime. Branch-to-org mappings, deploy options and test settings all live here.

{
"branchingModel": {
"feature": "feature/*",
"base": "develop",
"environments": [
{ "name": "SIT", "branch": "sit", "orgAlias": "sit" },
{ "name": "UAT", "branch": "uat", "orgAlias": "uat" },
{ "name": "Production", "branch": "main", "orgAlias": "prod" }
]
},
"deployOptions": {
"checkOnlyOnFeature": true,
"destructiveChanges": true,
"sourceDir": "force-app"
},
"testOptions": { "runAllTests": true }
}
repository_structure [07]

What Gets Generated

The Pipeline Manager extension writes everything from the setup wizard. Nothing here needs to be handwritten.

salesforce-cicd-blueprint/
├── ci-config.json           # Branch-to-org mapping
├── github/workflows/      # GitHub Actions pipeline
├── azure-pipelines.yml     # Azure DevOps
├── .gitlab-ci.yml          # GitLab CI
├── Jenkinsfile             # Jenkins
├── bitbucket-pipelines.yml  # Bitbucket
├── manifests/
├── package.xml          # Full deploy fallback
└── destructiveChanges.xml
└── scripts/
├── delta-deploy.sh
├── rollback.sh
└── run-tests.sh
vscode_extensions [08]

Two extensions. Two jobs.

The blueprint ships two separate VSCode extensions that split the work cleanly. Pipeline Manager is the one-time setup tool: it generates and tracks the pipeline. Developer Tools is the daily driver: deploy, validate, test and manage orgs without leaving the editor.