// project 03 DEV

CI/CD Pipeline Blueprint

Set up once with Pipeline Manager, develop daily with Developer Tools

A ready-made release system for Salesforce teams. Each release deploys only what changed and runs the Apex tests. If the deploy or the tests fail, it rolls back to a backup taken just before the release. It comes as templates for five CI platforms (the services that run each release), and it keeps every org login out of the code, stored as a secret. Two VSCode extensions sit on top. Pipeline Manager sets the pipeline up once per project, and Developer Tools handles day-to-day development.

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

How a Release Runs

Every push starts the pipeline, and a settings file, ci-config.json, decides what happens next. A feature branch gets a check-only deploy of the whole package to the Dev org. Salesforce confirms the package would deploy without saving anything, so each pull request is known to deploy before it merges. An environment branch runs every step: sign in, work out what changed, back up the org, deploy the change and tag it, run the tests, and roll back if anything fails.

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

    C -->|"feature/*"| D["feature/* branch"]
    D --> F["Validate the full package
against Dev (check-only)"] F --> H["PR into dev"] C -->|"env branch"| E["env branch
(dev / 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 --> Q["sf project retrieve start
back up the org"] Q --> L["sf project deploy start
deploy the delta"] L --> O["Tag deployed/#lt;env#gt;"] O --> M["sf apex run test
run local tests"] M --> N{"Passed?"} N -->|"Yes"| Z["Release done"] N -->|"No"| P["scripts/rollback.sh
redeploy the backup"] L -->|"deploy fails"| P %% Blueprint tokens as literal hex (Mermaid cannot parse CSS vars or color-mix) classDef trigger fill:#e0be621f,stroke:#e0be62,stroke-width:1.5px; classDef ci fill:#8b93e81f,stroke:#8b93e8,stroke-width:1.5px; classDef sf fill:#62d99a1f,stroke:#62d99a,stroke-width:1.5px; classDef decision fill:#e0be621f,stroke:#e0be62,stroke-width:1.5px; classDef ok fill:#62d99a1f,stroke:#62d99a,stroke-width:1.5px; classDef fail fill:#e697521f,stroke:#e69752,stroke-width:1.5px; class A trigger; class C,N decision; class B,D,E,F,H ci; class I,J,K,Q,L,O,M sf; class Z ok; class P fail;
Branch Model
Set in ci-config.json

Map any branch pattern to any org. By default, feature/* branches are validated, and named branches (dev, sit, qa, uat, staging, main) move each release through the environments in order.

First Run
Starts From the Previous Commit

With no deployed/<env> tag yet, the first run deploys what changed in the latest commit. To start from the current commit, run Initialise Deploy Tag in Developer Tools and push the tag. Only a repository with a single commit gets a full deploy from package.xml.

Delta Deployment

Each release ships only what changed. sfdx-git-delta compares the latest commit with the last deploy to work out exactly what changed, including anything deleted, and deleted items are removed from Salesforce as well. A commit that only changes documents deploys nothing.

Faster Deploys
Deploy Only What Changed

A one-file change deploys one file. There is no full deploy on every push, so releases stay quick as the org grows.

Safer Deploys
Lower Risk Per Deploy

Each deploy touches only the components that changed, so there are fewer side effects elsewhere in the org.

Deletions Handled
Removals Cleaned Up Automatically

Anything deleted from the project is removed from Salesforce too. sfdx-git-delta writes the destructiveChanges.xml file for it, so nobody keeps a list of deletions by hand.

Tags mark each release. Each successful deploy pushes a deployed/<env> Git tag, and the next run compares against that point instead of the previous commit.

Five Platforms, Same Steps

The release steps are the same on every platform. Each template only handles that platform's differences: how it fetches the full Git history, what it calls the branch, how it passes in secrets, and how it publishes test results.

ci_platform_templatesfive templates, same logic
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. Developer Tools can switch Pipelines on through the Bitbucket API.

Automatic Rollback

Before each deploy, the pipeline backs up the org's current metadata with sf project retrieve. If the deploy or the tests fail, scripts/rollback.sh deploys that backup to the org before the pipeline ends. The backup covers nine common metadata types, listed below, and anything new that the release added stays in the org.

Apex Tests on Every Release

After each deploy, if tests are switched on (the default), scripts/run-tests.sh runs the org's own Apex tests (skipping those from installed packages) with sf apex run test. The results are published as JUnit reports, and any failure triggers the rollback.

rollback_and_test_commandsthe exact CLI calls
# Pre-deploy backup
sf project retrieve start \
--manifest manifests/retrieve.xml \
--output-dir backups/<env>/<timestamp>
# On failure: redeploy the newest backup
scripts/rollback.sh staging
# retrieve.xml covers Apex classes and triggers,
# objects, fields, flows, Lightning components,
# page layouts, profiles and permission sets
sf apex run test \
--result-format junit \
--output-dir test-results \
--wait 30
# Failure → rollback → pipeline fails

Secrets Management

Each org's login, an SFDX auth URL, is stored as a secret in the CI platform and never in the code. There is one secret per org, named <ORGALIAS_UPPER>_AUTH_URL. Pipeline Manager lists exactly which secrets to add.

secret_nameshow to fetch them, what each is for
# Get the auth URL for any org
sf org display \
--verbose --json \
--target-org sit \
| jq -r '.result.sfdxAuthUrl'
Secret name Purpose
DEV_AUTH_URLDev environment, feature validation target
SIT_AUTH_URLSIT environment
QA_AUTH_URLQA environment
UAT_AUTH_URLUAT environment
STAGING_AUTH_URLStaging environment
PROD_AUTH_URLProduction

One Settings File

ci-config.json holds every pipeline setting: which branch deploys to which org, the deploy options and the test settings. The setup wizard writes it, VSCode checks it against a JSON schema while you edit it, and the pipeline reads it on every run.

ci_config_shapethe file the wizard writes
{
"branchingModel": {
"feature": "feature/*",
"base": "develop",
"environments": [
{ "name": "Dev", "branch": "dev", "orgAlias": "dev" },
{ "name": "SIT", "branch": "sit", "orgAlias": "sit" },
{ "name": "QA", "branch": "qa", "orgAlias": "qa" },
{ "name": "UAT", "branch": "uat", "orgAlias": "uat" },
{ "name": "Staging", "branch": "staging", "orgAlias": "staging" },
{ "name": "Production", "branch": "main", "orgAlias": "prod" }
]
},
"deployOptions": {
"checkOnlyOnFeature": true,
"destructiveChanges": true,
"sourceDir": "force-app"
},
"testOptions": { "runAllTests": true }
}

What Gets Generated

Pipeline Manager's setup wizard writes all of these files, with one pipeline file for the CI platform you chose. Before the first run, trim package.xml to the metadata types your project uses, as its own comments ask.

generated_filesthe full file tree
your-project/
├── ci-config.json            # Every pipeline setting
├── # One pipeline file, for the platform you chose:
├── .github/workflows/sfdx-ci.yml
├── azure-pipelines.yml
├── .gitlab-ci.yml
├── Jenkinsfile
└── bitbucket-pipelines.yml
├── manifests/
├── package.xml           # Used by feature-branch checks
├── retrieve.xml          # What the backup covers
└── destructiveChanges.xml
├── scripts/
├── delta-deploy.sh
├── rollback.sh
└── run-tests.sh
└── docs/cicd-pipeline.md     # Optional team guide

Two Extensions, Two Jobs

Pipeline Manager is for setup. A wizard creates the pipeline once, and a panel keeps track of it. Developer Tools is for every day: deploy, validate, test and manage orgs without leaving the editor.