UNPKG

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
# 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)