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.
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;
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.
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.
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.
A one-file change deploys one file. No full-org deploy on every push, so pipeline time does not balloon as the org grows.
Touching only the changed components keeps each deploy scoped to the work in flight, which means fewer unintended side effects.
sfdx-git-delta generates destructiveChanges.xml for anything removed from source. No hand-maintained delete manifest.
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.
fetch-depth: 0 for full history. Secrets via secrets.<NAME>. Test artifacts via upload-artifact.
Full clone via fetchDepth: '0'. Auth URLs injected via env block. Results via PublishTestResults.
GIT_DEPTH: 0 for history. Base image node:20. JUnit via artifacts:reports:junit.
GitSCM checkout with shallow: false. Credentials via credentials(). Results via junit post step.
clone: depth: full. Base image node:20. Pipelines can be toggled on via REST API.
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.
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.
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.
| Secret name | Purpose |
|---|---|
| SIT_AUTH_URL | SIT environment |
| QA_AUTH_URL | QA environment |
| UAT_AUTH_URL | UAT environment |
| STAGING_AUTH_URL | Staging environment |
| PROD_AUTH_URL | Production |
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.
The Pipeline Manager extension writes everything from the setup wizard. Nothing here needs to be handwritten.
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.
Set up once per project. A 4-step wizard generates every pipeline file for the chosen CI platform, an activity-bar panel shows the live config, ci-config.json gets JSON IntelliSense, and the secrets checklist tells you exactly what to add.
The daily driver. Deploy the current file, delta-deploy from git tags, validate check-only, run Apex tests, check coverage, switch orgs, rotate pipeline credentials, and export a Confluence space to Markdown, all from the editor.