Start typing to search.

Salesforce Salesforce CI/CD DevOps

CI/CD for Salesforce: Deployment Automation

Complete implementation of CI/CD pipelines for Salesforce using GitHub Actions, SFDX CLI, and Scratch Orgs. Includes best practices and troubleshooting.

18 min read

Deployment Automation

Modern DevOps Pipeline

1. The Philosophy: Developer in Control

Our main workflow is manual, based on workflow_dispatch:

on:
  workflow_dispatch:
    inputs:
      action:
        description: 'Action to execute (Deploy or Validate)'
        required: true
        default: 'Validate'
      environment:
        description: 'Target environment'
        required: true
        default: 'develop'
      testLevel:
        description: 'Testing level'
        required: true
        default: 'RunLocalTests'

Advantages:

  • ✅ Full control by the developer
  • ✅ Avoids unintended automatic deployments
  • ✅ Improves traceability

GitHub Actions Trigger

2. Pull Request Verification and Status

We verify that the PR exists and is clean (CLEAN):

PR_STATE=$(gh pr list --head $GITHUB_REF_NAME --json state --jq '.[0].state')

Objective: ensure that the change has been reviewed and is integrable without conflicts.

3. Synchronization and Merge

- name: Merge target branch into current
  run: git merge origin/$TARGET_BRANCH

This ensures we test on the updated code from the target branch (e.g., develop).

4. Smart Delta Package Generation

Why incremental deployment?

In large projects, deploying all metadata can be extremely slow. Our delta strategy only deploys modified components, reducing times from hours to minutes.

Implementation with sfdx-git-delta

# Create delta packages for new, modified or deleted metadata
branch="$GITHUB_REF"
environment_branch="origin/$TARGET_BRANCH"
mkdir $CHANGE_SOURCE
sfdx sgd:source:delta --to="$branch" --from $(git merge-base "$branch" "$environment_branch") \
  --output changed-sources/ --generate-delta --source force-app/ --ignore scripts/CI/.deltaignore

# Verify generated content
echo "========== package.xml =========="
cat "changed-sources/package/package.xml"
echo "========== destructiveChanges.xml =========="
cat "changed-sources/destructiveChanges/destructiveChanges.xml"

Generated files:

  • package.xml: Added/modified components
  • destructiveChanges.xml: Deleted components
  • .deltaignore: Files to omit (static files, CI configurations)

Advantages:

  • ⏩ Only deploys what changed
  • 🔎 Maximum visibility with package.xml
  • ⚖️ Compatible with .deltaignore
  • 🚀 Avoids side effects on unrelated components

Incremental deployment

5. Selective Testing Strategy with RunSpecifiedTests

The Problem: Coverage vs Speed

Salesforce requires 75% average coverage for production. With RunLocalTests this is based on global average, but with RunSpecifiedTests each class in the package must achieve 75% individually - a stricter criterion that guarantees quality.

Smart Test Selection

1. CSV Mapping of Classes to Tests

Class,TestClass
MyService,MyServiceTest
UserUtil,UserUtilTest
TriggerHandler,TriggerHandlerTest

2. Automatic Test Determination

- name: Get Apex Tests
  if: env.METADATA_CHANGES == 'yes'
  run: |
    TESTS="$INPUT_APEX_TESTS"
    BASE_PATH="scripts/CI/"
    folder_path="changed-sources/force-app/main/default/classes"
    
    if [ "$TEST_LEVEL" == "Run all specified tests" ]; then
      TESTS=$(node "${BASE_PATH}getAllTests.js" "$SKIP_TESTS")
    elif [ -z "$TESTS" ] && test -f "${BASE_PATH}getTestsToRun.js"; then
      TESTS=$(node "${BASE_PATH}getTestsToRun.js" "${folder_path}")
    fi
    
    echo "APEX_TESTS=$TESTS" >> $GITHUB_ENV

3. Deployment Command with Specific Tests

sfdx force:source:deploy -u $TARGET_ORG -x changed-sources/package/package.xml \
  -l RunSpecifiedTests -r "$APEX_TESTS"

Advantages of RunSpecifiedTests:

  • 📊 Stricter criterion: Each new class must have 75% coverage
  • Faster testing: Only relevant tests
  • 🎯 Precision: Specific tests for real changes
  • 🛡️ Quality: Prevents low-coverage code from “slipping through” under global average

Additional benefits:

  • 📊 Faster testing
  • 🌐 Independent tests per package
  • 🧳 Precision for real changes

6. Additional Security Barriers

  • checkDeploymentAllowed.sh: Validations according to schedule, environment and corporate rules.
  • Retries on PR status:
while [ $attempt -le 3 ]; do
  pr_state=$(gh pr list --head $GITHUB_REF_NAME --json state --jq '.[0].state')
  [ "$pr_state" != "UNKNOWN" ] && break
  sleep 5; ((attempt++))
done

7. Continuous Monitoring and Scheduled Executions

Periodic Complete Executions

Although we use selective tests in each deployment, we run scheduled complete verifications:

# workflow: run_all_tests.yaml
schedule:
  - cron: '0 2 * * *'  # Every night at 2 AM

This gives us:

  • 🔄 Continuous verification of the complete codebase
  • 🚨 Early detection of unexpected regressions
  • 📊 Updated global coverage report

8. Notifications and Cycle Closure

Communication Integration

  • 💬 Slack/Teams Webhooks: Automatic status notifications
  • 🔗 Direct links: Links to PR, execution and logs
  • 📈 Coverage metrics: Text report with covered lines

Smart Auto-merge

  • Automatic merge if deployment successful
  • 🔄 Branch alignment without manual intervention
  • 🚨 Immediate alerts in case of failures

Slack CI Notification

9. Results and Metrics

Quantifiable Improvements

  • Deployment time: From hours to minutes
  • Code coverage: 75% guaranteed per component (not just average)
  • Quality: Stricter criterion prevents quality regression
  • Efficiency: Fewer tests executed, greater precision

Use Cases

  • 🟢 Development: NoTestRun for speed
  • 🟡 Staging: RunSpecifiedTests for validation
  • 🔴 Production: RunSpecifiedTests mandatory

Conclusion

Our strategy combines speed and quality through:

📦 Delta deployments: Only relevant changes

🧪 Selective testing: RunSpecifiedTests with strict 75% per class criterion

🔄 Continuous monitoring: Scheduled executions for global verification

🤖 Smart automation: Automatic test selection via CSV mapping

This CI/CD pipeline is a key tool in our DevOps culture for Salesforce. It allows us to deliver with confidence, audit with ease, and continuously improve.

🚀 Automated, but under control.

💡 Fast, but secure.

😎 Efficient, but transparent.


References

Configuration based on Salesforce best practices and community tools like sfdx-git-delta for incremental deployments and advanced use of the Metadata API testLevel parameter.