sf-agent-framework
Version:
AI Agent Orchestration Framework for Salesforce Development - Two-phase architecture with 70% context reduction
679 lines (539 loc) • 15.5 kB
Markdown
# Salesforce Deployment Patterns
## Overview
Deployment patterns define strategies and methodologies for moving Salesforce
metadata and configurations between environments. These patterns ensure
reliable, repeatable, and safe deployments while minimizing risk and downtime.
## Deployment Strategies
### Change Set Deployment Pattern
**Use Case**: Simple deployments between connected orgs
**Process Flow**:
```
1. Developer Sandbox → Create Change Set
2. Upload to Target Org
3. Validate in Target
4. Deploy Change Set
5. Run Tests
6. Post-Deployment Tasks
```
**Best Practices**:
- Use for small, simple changes
- Document components included
- Clone change sets for multiple environments
- Always validate before deploying
- Include all dependencies
### Metadata API Pattern
**Use Case**: Automated deployments, CI/CD pipelines
**Implementation**:
```xml
<!-- package.xml example -->
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
<types>
<members>AccountController</members>
<members>AccountTrigger</members>
<name>ApexClass</name>
</types>
<types>
<members>Account.CustomField__c</members>
<name>CustomField</name>
</types>
<version>58.0</version>
</Package>
```
**Deployment Script**:
```bash
# Retrieve metadata
sf project retrieve start --manifest package.xml
# Deploy to target
sf project deploy start --target-org production --manifest package.xml
```
### Package-Based Deployment
**Use Case**: Modular application deployment, ISV distribution
**Types**:
1. **Unmanaged Packages**: One-time deployment
2. **Managed Packages**: Upgradeable, namespace
3. **Unlocked Packages**: Source-driven, flexible
4. **Second-Generation Packages**: Modern packaging
**Package Development**:
```json
// sfdx-project.json
{
"packageDirectories": [
{
"path": "force-app",
"package": "MyPackage",
"versionName": "Version 1.0",
"versionNumber": "1.0.0.NEXT",
"default": true
}
],
"namespace": "myNamespace",
"packageAliases": {
"MyPackage": "0Ho..."
}
}
```
## Environment Strategy Patterns
### Single Pipeline Pattern
```
Developer Sandbox → Integration Sandbox → UAT → Production
```
**Characteristics**:
- Linear progression
- Simple to manage
- Clear promotion path
- Suitable for small teams
### Multiple Pipeline Pattern
```
Feature Branch 1 → Dev Sandbox 1 ─┐
├─→ Integration → UAT → Production
Feature Branch 2 → Dev Sandbox 2 ─┘
```
**Characteristics**:
- Parallel development
- Feature isolation
- Complex coordination
- Suitable for large teams
### Hotfix Pattern
```
Hotfix Branch → Hotfix Sandbox → Production
↓
Integration ← (backport)
```
**Characteristics**:
- Emergency fixes
- Bypasses normal flow
- Requires backporting
- Minimal testing
## Source Control Integration Patterns
### Git Flow Pattern
```bash
# Feature development
git checkout -b feature/new-feature develop
# Make changes
git commit -m "Add new feature"
git push origin feature/new-feature
# Create pull request
# Review and merge to develop
# Release preparation
git checkout -b release/1.0 develop
# Deploy to UAT
# Fix issues
git commit -m "Release fixes"
# Merge to main and develop
git checkout main
git merge --no-ff release/1.0
git tag -a v1.0 -m "Version 1.0"
git checkout develop
git merge --no-ff release/1.0
```
### GitHub Flow Pattern
```bash
# Simple branching
git checkout -b feature/my-feature main
# Develop feature
git commit -m "Implement feature"
git push origin feature/my-feature
# Pull request to main
# Deploy to production after merge
```
### Trunk-Based Development
```bash
# Work on main/master
git checkout main
git pull origin main
# Small, frequent commits
git commit -m "Small change"
git push origin main
# Feature flags for incomplete work
```
## Continuous Integration Patterns
### Basic CI Pipeline
```yaml
# .github/workflows/ci.yml
name: CI Pipeline
on:
push:
branches: [develop, main]
pull_request:
branches: [develop, main]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: salesforce/cli-action@v1
- name: Authenticate
run: |
echo ${{ secrets.SFDX_AUTH_URL }} > auth.txt
sf org login sfdx-url -f auth.txt -a targetOrg
- name: Deploy and Test
run: |
sf project deploy start --target-org targetOrg --wait 30
sf apex test run --target-org targetOrg --wait 30
```
### Advanced CI/CD Pipeline
```yaml
# Jenkinsfile
pipeline {
agent any
environment {
SF_USERNAME = credentials('sf-username')
SF_PASSWORD = credentials('sf-password')
SF_INSTANCE_URL = 'https://test.salesforce.com'
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build') {
steps {
sh 'npm install'
sh 'npm run lint'
sh 'npm run test:unit'
}
}
stage('Validate') {
steps {
sh '''
sf org login username \
--username $SF_USERNAME \
--password $SF_PASSWORD \
--instance-url $SF_INSTANCE_URL \
--alias ci-org
sf project deploy validate \
--target-org ci-org \
--manifest manifest/package.xml \
--test-level RunLocalTests
'''
}
}
stage('Deploy') {
when {
branch 'main'
}
steps {
sh '''
sf project deploy start \
--target-org ci-org \
--manifest manifest/package.xml
'''
}
}
}
post {
always {
junit '**/test-results.xml'
archiveArtifacts artifacts: 'logs/**/*'
}
}
}
```
## Deployment Automation Patterns
### Script-Based Deployment
```bash
#!/bin/bash
# deploy.sh
set -e
ENVIRONMENT=$1
BRANCH=$2
echo "Deploying $BRANCH to $ENVIRONMENT"
# Authenticate
case $ENVIRONMENT in
"dev")
sf org login sfdx-url -f ./auth/dev.txt -a targetOrg
;;
"uat")
sf org login sfdx-url -f ./auth/uat.txt -a targetOrg
;;
"prod")
sf org login sfdx-url -f ./auth/prod.txt -a targetOrg
;;
esac
# Deploy
sf project deploy start \
--target-org targetOrg \
--manifest manifest/package.xml \
--test-level RunLocalTests \
--wait 30
# Run post-deployment scripts
./scripts/post-deploy-$ENVIRONMENT.sh
```
### Metadata Filtering Pattern
```javascript
// filter-metadata.js
const fs = require('fs');
const xml2js = require('xml2js');
function filterMetadata(packageXml, environment) {
const parser = new xml2js.Parser();
const builder = new xml2js.Builder();
fs.readFile(packageXml, (err, data) => {
parser.parseString(data, (err, result) => {
// Filter based on environment
if (environment !== 'production') {
// Remove production-only components
result.Package.types = result.Package.types.filter((type) => {
return !type.members.includes('ProductionOnly__c');
});
}
// Write filtered package.xml
const xml = builder.buildObject(result);
fs.writeFile('filtered-package.xml', xml, (err) => {
console.log('Filtered package.xml created');
});
});
});
}
```
## Delta Deployment Pattern
### Git-Based Delta Detection
```bash
# detect-changes.sh
#!/bin/bash
# Get changed files
CHANGED_FILES=$(git diff --name-only origin/main...HEAD)
# Generate package.xml for changed components
sf sgd source delta \
--from origin/main \
--to HEAD \
--output delta-package \
--generate-manifest
# Deploy only changes
sf project deploy start \
--manifest delta-package/package.xml \
--source-dir delta-package/force-app
```
### Change Tracking Pattern
```apex
// Track deployments
public class DeploymentTracker {
public static void logDeployment(String componentType, String componentName) {
Deployment_Log__c log = new Deployment_Log__c(
Component_Type__c = componentType,
Component_Name__c = componentName,
Deployed_By__c = UserInfo.getUserId(),
Deployment_Date__c = Datetime.now(),
Source_Commit__c = getGitCommit()
);
insert log;
}
}
```
## Rollback Patterns
### Backup and Restore Pattern
```bash
# backup-before-deploy.sh
#!/bin/bash
# Create backup
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="backups/$TIMESTAMP"
mkdir -p $BACKUP_DIR
# Retrieve current state
sf project retrieve start \
--target-org production \
--manifest manifest/package.xml \
--output-dir $BACKUP_DIR
# Tag backup
git tag backup-$TIMESTAMP
# Deploy new version
./deploy.sh production
# If deployment fails, restore
if [ $? -ne 0 ]; then
echo "Deployment failed, restoring backup"
sf project deploy start \
--target-org production \
--source-dir $BACKUP_DIR
fi
```
### Feature Flag Pattern
```apex
// Feature flag implementation
public class FeatureFlag {
public static Boolean isEnabled(String featureName) {
Feature_Flag__mdt flag = [
SELECT Is_Enabled__c
FROM Feature_Flag__mdt
WHERE DeveloperName = :featureName
LIMIT 1
];
return flag?.Is_Enabled__c ?? false;
}
}
// Usage in code
if (FeatureFlag.isEnabled('NewFeature')) {
// New implementation
} else {
// Old implementation
}
```
## Org-Specific Deployment Patterns
### Multi-Org Deployment
```javascript
// deploy-multi-org.js
const orgs = [
{ alias: 'na-prod', region: 'NA' },
{ alias: 'eu-prod', region: 'EU' },
{ alias: 'apac-prod', region: 'APAC' },
];
async function deployToAllOrgs() {
for (const org of orgs) {
console.log(`Deploying to ${org.alias}`);
// Region-specific package
const packageXml = `manifest/package-${org.region}.xml`;
await execShellCommand(`
sf project deploy start \
--target-org ${org.alias} \
--manifest ${packageXml} \
--wait 30
`);
}
}
```
### Sandbox Refresh Pattern
```bash
# post-refresh.sh
#!/bin/bash
# Wait for sandbox to be ready
while ! sf org display --target-org mysandbox &> /dev/null; do
echo "Waiting for sandbox..."
sleep 60
done
# Deploy latest code
sf project deploy start \
--target-org mysandbox \
--source-dir force-app
# Run data scripts
sf apex run --target-org mysandbox \
--file scripts/setup-test-data.apex
# Update integration endpoints
sf data update record \
--target-org mysandbox \
--sobject Custom_Setting__c \
--where "Name='Integration'" \
--values "Endpoint__c='https://test.example.com'"
```
## Testing Patterns
### Test-Level Strategy
```bash
# Determine test level based on components
if grep -q "ApexClass\|ApexTrigger" manifest/package.xml; then
TEST_LEVEL="RunLocalTests"
elif grep -q "Flow\|Process" manifest/package.xml; then
TEST_LEVEL="RunSpecifiedTests"
TEST_CLASSES="FlowTestClass"
else
TEST_LEVEL="NoTestRun"
fi
sf project deploy start \
--test-level $TEST_LEVEL \
${TEST_CLASSES:+--tests $TEST_CLASSES}
```
### Parallel Test Execution
```apex
// Run tests in parallel
@IsTest
public class ParallelTestRunner {
public static void runTestsInParallel(List<String> testClasses) {
Integer batchSize = 10;
for (Integer i = 0; i < testClasses.size(); i += batchSize) {
List<String> batch = new List<String>();
for (Integer j = i; j < Math.min(i + batchSize, testClasses.size()); j++) {
batch.add(testClasses[j]);
}
Test.startTest();
System.enqueueJob(new TestQueueable(batch));
Test.stopTest();
}
}
}
```
## Monitoring and Validation
### Deployment Monitoring
```javascript
// monitor-deployment.js
const { exec } = require('child_process');
const slack = require('./slack-integration');
function monitorDeployment(deployId) {
const checkInterval = setInterval(() => {
exec(`sf project deploy report --job-id ${deployId} --json`, (error, stdout) => {
const result = JSON.parse(stdout);
if (result.status === 'Succeeded') {
slack.notify('✅ Deployment successful');
clearInterval(checkInterval);
} else if (result.status === 'Failed') {
slack.notify('❌ Deployment failed: ' + result.message);
clearInterval(checkInterval);
}
});
}, 30000); // Check every 30 seconds
}
```
### Post-Deployment Validation
```apex
// Validate deployment
@RestResource(urlMapping='/deployment/validate/*')
global class DeploymentValidator {
@HttpPost
global static ValidationResult validate() {
ValidationResult result = new ValidationResult();
// Check critical components
result.addCheck('Apex Classes', validateApexClasses());
result.addCheck('Triggers', validateTriggers());
result.addCheck('Flows', validateFlows());
result.addCheck('Integration', validateIntegrations());
return result;
}
private static Boolean validateApexClasses() {
List<ApexClass> classes = [
SELECT Name, Status
FROM ApexClass
WHERE Status != 'Active'
];
return classes.isEmpty();
}
}
```
## Security Patterns
### Secure Credential Storage
```yaml
# GitHub Secrets
# Store in repository settings
SFDX_AUTH_URL: force://ClientId:ClientSecret:RefreshToken@instance.salesforce.com
# Azure Key Vault
az keyvault secret set \
--vault-name mykeyvault \
--name sf-prod-auth \
--value $SFDX_AUTH_URL
```
### Deployment Approval Pattern
```yaml
# GitHub Actions with approval
jobs:
deploy-production:
environment: production
needs: [test, security-scan]
steps:
- name: Deploy to Production
run: |
sf project deploy start \
--target-org production \
--manifest manifest/package.xml
```
## Best Practices
1. **Version Control Everything**: All metadata in source control
2. **Automate Deployments**: Reduce manual errors
3. **Test Thoroughly**: Appropriate test levels
4. **Monitor Continuously**: Track deployment success
5. **Document Changes**: Clear commit messages
6. **Use Scratch Orgs**: For development and testing
7. **Implement Rollback**: Plan for failures
8. **Secure Credentials**: Never commit secrets
9. **Validate First**: Always validate before deploy
10. **Communicate Status**: Keep team informed
## Additional Resources
- [Salesforce DX Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/)
- [Metadata API Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/)
- [CI/CD for Salesforce](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_ci_cd.htm)
- [Salesforce DevOps Center](https://help.salesforce.com/s/articleView?id=sf.devops_center_overview.htm)