← All posts
· 2 min read ·
SalesforceCopadoCI/CDDevOps

Automating Salesforce Deployments with Copado and GitHub Actions

A practical guide to building a robust Salesforce CI/CD pipeline that combines Copado's native release management with GitHub Actions for full traceability and automation.

Abstract data flow representing a CI/CD pipeline

Release management in Salesforce has historically been painful. Manual deployments, undocumented change sets, and no real audit trail - it’s a recipe for production incidents. After leading release pipelines for 50+ person teams across multiple simultaneous projects, here’s what actually works.

Why Copado Alone Isn’t Enough

Copado handles the Salesforce-native side of your pipeline beautifully - environment branches, user stories, quality gates. But your Salesforce org doesn’t live in isolation. You have microservices, integration middleware, infrastructure config, and documentation that all need to move in lockstep with your metadata deployments.

GitHub Actions fills that gap.

The Architecture

The pattern I use keeps Copado as the source of truth for Salesforce metadata, while GitHub Actions handles everything else:

feature/branch → Copado pipeline → GitHub Actions → staging → production

Copado triggers a webhook on successful promotion. GitHub Actions picks that up and orchestrates the rest: running Apex tests, syncing connected app configs, notifying Slack, updating Jira, and cutting a release tag.

Setting Up the Webhook Integration

In Copado, configure a pipeline step that fires a repository_dispatch event to your GitHub repo:

curl -X POST \
  -H "Authorization: token $GITHUB_TOKEN" \
  -H "Accept: application/vnd.github.v3+json" \
  https://api.github.com/repos/org/repo/dispatches \
  -d '{"event_type":"copado-promoted","client_payload":{"env":"staging","pipeline":"main"}}'

On the GitHub side, listen for it:

on:
  repository_dispatch:
    types: [copado-promoted]

Running Apex Tests in CI Without Copado

For PRs that don’t go through Copado (hotfixes, config changes), use the Salesforce CLI directly in GitHub Actions:

- name: Run Apex Tests
  run: |
    sf org create scratch --definition-file config/project-scratch-def.json --alias ci-org --duration-days 1
    sf project deploy start --source-dir force-app --target-org ci-org
    sf apex run test --target-org ci-org --code-coverage --result-format human --wait 20
    sf org delete scratch --target-org ci-org --no-prompt

Delta Deployments

Full deployments take 20-30 minutes. Delta deployments - shipping only what changed - cut that to under 5 minutes for most PRs. Use sf-git-delta to generate your package:

sgd --to HEAD --from HEAD~1 --output . --repo .
sf project deploy start --manifest package/package.xml --target-org $TARGET_ORG

Quality Gates That Actually Block Deploys

The gates that have saved us the most production incidents:

  1. Code coverage > 85% - not 75%, the SF minimum
  2. PMD static analysis - catches SOQL in loops, hardcoded IDs, missing sharing keywords
  3. Destructive change review - any deletion requires two approvals
  4. API version drift check - flag metadata still on API versions older than current - 2

Lessons from the Field

The biggest wins come from treating Salesforce deployments exactly like software deployments: version everything, automate everything, and make the pipeline the only path to production. No one should be able to deploy via change set in a mature org.

The second biggest win is fast feedback. If a developer has to wait 30 minutes to know their code broke a test, they’ve already moved on mentally. Get that under 5 minutes and adoption of the pipeline goes from fought to beloved.

← All posts