sf-agent-framework
Version:
AI Agent Orchestration Framework for Salesforce Development - Two-phase architecture with 70% context reduction
899 lines (735 loc) • 21.4 kB
Markdown
# Salesforce DevOps Tools
## Overview
Salesforce DevOps tools enable continuous integration, continuous delivery, and
automated deployment processes. This document provides a comprehensive guide to
tools, platforms, and best practices for implementing DevOps in Salesforce
environments.
## Native Salesforce Tools
### Salesforce CLI (sf)
**Purpose**: Command-line interface for Salesforce development and deployment
```bash
# Installation
npm install -g @salesforce/cli
# Version check
sf --version
# Key commands
sf org login web --alias myorg
sf project generate --name myproject
sf project retrieve start --manifest package.xml
sf project deploy start --target-org production
sf apex test run --test-level RunLocalTests
```
**Configuration**:
```json
// .sf/config.json
{
"target-org": "myorg",
"target-dev-hub": "devhub",
"apiVersion": "59.0",
"disableTelemetry": false
}
```
### Salesforce DX
**Purpose**: Source-driven development framework
```json
// sfdx-project.json
{
"packageDirectories": [
{
"path": "force-app",
"default": true,
"package": "MyPackage",
"versionName": "Version 1.0",
"versionNumber": "1.0.0.NEXT"
}
],
"namespace": "",
"sourceApiVersion": "59.0",
"packageAliases": {
"MyPackage": "0Ho5e000000CaS1CAK"
}
}
```
### DevOps Center
**Purpose**: Native Salesforce DevOps platform
**Features**:
- Work item tracking
- Pipeline management
- Environment management
- Release orchestration
**Setup**:
```apex
// Enable DevOps Center
public class DevOpsCenterSetup {
public static void enableDevOpsCenter() {
// Navigate to Setup > DevOps Center
// Enable and configure
// Connect source control
// Define pipelines
}
}
```
## Version Control Systems
### Git Integration
**GitHub**:
```yaml
# .github/workflows/salesforce.yml
name: Salesforce CI/CD
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install Salesforce CLI
run: npm install -g @salesforce/cli
- name: Authenticate
run: |
echo ${{ secrets.SFDX_AUTH_URL }} > auth.txt
sf org login sfdx-url -f auth.txt -a ci-org
- name: Deploy and Test
run: |
sf project deploy start --target-org ci-org --test-level RunLocalTests
```
**GitLab**:
```yaml
# .gitlab-ci.yml
stages:
- validate
- test
- deploy
variables:
SALESFORCE_CLI_VERSION: 'latest'
validate:
stage: validate
script:
- npm install -g @salesforce/cli
- echo $SFDX_AUTH_URL > auth.txt
- sf org login sfdx-url -f auth.txt -a ci-org
- sf project deploy validate --target-org ci-org
test:
stage: test
script:
- sf apex test run --target-org ci-org --wait 10
- sf apex test report --target-org ci-org
deploy:
stage: deploy
only:
- main
script:
- sf project deploy start --target-org production
```
**Bitbucket**:
```yaml
# bitbucket-pipelines.yml
pipelines:
default:
- step:
name: Validate
script:
- npm install -g @salesforce/cli
- echo $SFDX_AUTH_URL > auth.txt
- sf org login sfdx-url -f auth.txt -a ci-org
- sf project deploy validate --target-org ci-org
branches:
main:
- step:
name: Deploy to Production
deployment: production
script:
- sf project deploy start --target-org production
```
## CI/CD Platforms
### Jenkins
**Setup**:
```groovy
// Jenkinsfile
pipeline {
agent any
environment {
SF_USERNAME = credentials('sf-username')
SF_PASSWORD = credentials('sf-password')
SF_INSTANCE_URL = 'https://login.salesforce.com'
}
stages {
stage('Checkout') {
steps {
git branch: 'main',
url: 'https://github.com/company/salesforce-repo.git'
}
}
stage('Build') {
steps {
sh 'npm install'
sh 'npm run lint'
}
}
stage('Authenticate') {
steps {
sh '''
echo "Authenticating to Salesforce"
sf org login username \
--username $SF_USERNAME \
--password $SF_PASSWORD \
--instance-url $SF_INSTANCE_URL \
--alias jenkins-org
'''
}
}
stage('Validate') {
steps {
sh '''
sf project deploy validate \
--target-org jenkins-org \
--test-level RunLocalTests
'''
}
}
stage('Deploy') {
when {
branch 'main'
}
steps {
sh '''
sf project deploy start \
--target-org jenkins-org \
--test-level RunLocalTests
'''
}
}
}
post {
always {
publishHTML([
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: 'test-results',
reportFiles: 'test-results.html',
reportName: 'Test Results'
])
}
}
}
```
### Azure DevOps
**Pipeline Configuration**:
```yaml
# azure-pipelines.yml
trigger:
branches:
include:
- main
- develop
pool:
vmImage: 'ubuntu-latest'
variables:
- group: Salesforce-Credentials
stages:
- stage: Build
jobs:
- job: Validate
steps:
- task: NodeTool@0
inputs:
versionSpec: '18.x'
- script: npm install -g @salesforce/cli
displayName: 'Install Salesforce CLI'
- script: |
echo $(SFDX_AUTH_URL) > auth.txt
sf org login sfdx-url -f auth.txt -a azdo-org
displayName: 'Authenticate to Salesforce'
- script: |
sf project deploy validate \
--target-org azdo-org \
--test-level RunLocalTests
displayName: 'Validate Deployment'
- stage: Deploy
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
jobs:
- deployment: Production
environment: 'salesforce-production'
strategy:
runOnce:
deploy:
steps:
- script: |
sf project deploy start \
--target-org production \
--test-level RunLocalTests
displayName: 'Deploy to Production'
```
### CircleCI
**Configuration**:
```yaml
# .circleci/config.yml
version: 2.1
orbs:
salesforce: circleci/salesforce@2.0.0
jobs:
validate:
docker:
- image: cimg/node:18.0
steps:
- checkout
- salesforce/install
- salesforce/auth:
auth-url: SFDX_AUTH_URL
- salesforce/deploy:
deploy-type: validate
test-level: RunLocalTests
deploy:
docker:
- image: cimg/node:18.0
steps:
- checkout
- salesforce/install
- salesforce/auth:
auth-url: SFDX_AUTH_URL_PROD
- salesforce/deploy:
deploy-type: deploy
test-level: RunLocalTests
workflows:
version: 2
validate_and_deploy:
jobs:
- validate
- deploy:
requires:
- validate
filters:
branches:
only: main
```
## Salesforce-Specific DevOps Tools
### Copado
**Features**:
- User story management
- Automated deployments
- Compliance and governance
- Release management
**Implementation**:
```apex
// Copado integration
public class CopadoIntegration {
public static void createUserStory(String title, String criteria) {
copado__User_Story__c story = new copado__User_Story__c(
copado__User_Story_Title__c = title,
copado__Acceptance_Criteria__c = criteria,
copado__Status__c = 'Draft',
copado__Project__c = getActiveProject()
);
insert story;
}
public static void promoteUserStory(Id storyId, String targetEnv) {
copado__Promotion__c promotion = new copado__Promotion__c(
copado__User_Story__c = storyId,
copado__Source_Org_Credential__c = getCurrentOrg(),
copado__Destination_Org_Credential__c = getTargetOrg(targetEnv)
);
insert promotion;
}
}
```
### Gearset
**Features**:
- Comparison and deployment
- CI/CD pipelines
- Backup and recovery
- Monitoring and alerts
**API Integration**:
```javascript
// Gearset API usage
const axios = require('axios');
class GearsetClient {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://api.gearset.com/v1';
}
async createDeployment(sourceOrg, targetOrg, metadata) {
const response = await axios.post(
`${this.baseUrl}/deployments`,
{
source: sourceOrg,
target: targetOrg,
metadata: metadata,
testLevel: 'RunLocalTests',
},
{
headers: {
Authorization: `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
},
}
);
return response.data.deploymentId;
}
async getDeploymentStatus(deploymentId) {
const response = await axios.get(`${this.baseUrl}/deployments/${deploymentId}`, {
headers: {
Authorization: `Bearer ${this.apiKey}`,
},
});
return response.data.status;
}
}
```
### AutoRABIT
**Features**:
- Version control integration
- Automated testing
- Code quality analysis
- Rollback capabilities
**Configuration**:
```xml
<!-- AutoRABIT configuration file -->
<autorabit-config>
<version-control>
<type>Git</type>
<url>https://github.com/company/salesforce-repo</url>
<branch>main</branch>
</version-control>
<deployment>
<source>feature/new-feature</source>
<target>UAT</target>
<test-level>RunSpecifiedTests</test-level>
<test-classes>
<class>AccountTriggerTest</class>
<class>OpportunityTriggerTest</class>
</test-classes>
</deployment>
<quality-gates>
<code-coverage>80</code-coverage>
<pmd-violations>0</pmd-violations>
<security-scan>enabled</security-scan>
</quality-gates>
</autorabit-config>
```
## Code Quality Tools
### PMD for Salesforce
**Setup**:
```xml
<!-- pmd-ruleset.xml -->
<?xml version="1.0"?>
<ruleset name="Salesforce PMD Rules"
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0
https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
<description>Salesforce Apex PMD Rules</description>
<rule ref="category/apex/design.xml">
<exclude name="ExcessiveParameterList"/>
</rule>
<rule ref="category/apex/performance.xml"/>
<rule ref="category/apex/security.xml"/>
<rule ref="category/apex/bestpractices.xml">
<exclude name="ApexUnitTestClassShouldHaveAsserts"/>
</rule>
<rule ref="category/apex/codestyle.xml">
<exclude name="MethodNamingConventions"/>
</rule>
</ruleset>
```
**Integration**:
```bash
# Run PMD analysis
pmd check -d force-app/main/default/classes -R pmd-ruleset.xml -f text
# CI integration
npm install -g @salesforce/sfdx-scanner
sf scanner run --target force-app --category "Design,Best Practices,Security"
```
### ESLint for LWC
**Configuration**:
```json
// .eslintrc.json
{
"extends": ["@salesforce/eslint-config-lwc/recommended"],
"rules": {
"@lwc/lwc/no-async-await": "error",
"@lwc/lwc/no-inner-html": "error",
"@lwc/lwc/no-document-query": "error",
"no-console": "warn",
"no-debugger": "error"
},
"overrides": [
{
"files": ["*.test.js"],
"env": {
"jest": true
}
}
]
}
```
## Testing Tools
### Jest for LWC
**Setup**:
```json
// jest.config.js
const { jestConfig } = require('@salesforce/sfdx-lwc-jest/config');
module.exports = {
...jestConfig,
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80
}
},
testPathIgnorePatterns: [
'<rootDir>/node_modules/',
'<rootDir>/test/jest-mocks/'
]
};
```
**Test Example**:
```javascript
// accountList.test.js
import { createElement } from 'lwc';
import AccountList from 'c/accountList';
import getAccounts from '@salesforce/apex/AccountController.getAccounts';
jest.mock('@salesforce/apex/AccountController.getAccounts', () => ({ default: jest.fn() }), { virtual: true });
describe('c-account-list', () => {
afterEach(() => {
jest.clearAllMocks();
});
it('displays accounts when data is returned', async () => {
const mockAccounts = [
{ Id: '001', Name: 'Test Account 1' },
{ Id: '002', Name: 'Test Account 2' },
];
getAccounts.mockResolvedValue(mockAccounts);
const element = createElement('c-account-list', {
is: AccountList,
});
document.body.appendChild(element);
await Promise.resolve();
const accountElements = element.shadowRoot.querySelectorAll('.account');
expect(accountElements.length).toBe(2);
});
});
```
### Apex Test Automation
```apex
// Test data factory
@isTest
public class TestDataFactory {
public static List<Account> createAccounts(Integer count) {
List<Account> accounts = new List<Account>();
for (Integer i = 0; i < count; i++) {
accounts.add(new Account(
Name = 'Test Account ' + i,
BillingCity = 'San Francisco',
Industry = 'Technology'
));
}
return accounts;
}
}
// Automated test execution
public class TestAutomation {
@future
public static void runTestsAsync(String className) {
ApexTestQueueItem[] testItems = [
SELECT Id, Status, ApexClassId
FROM ApexTestQueueItem
WHERE ApexClass.Name = :className
];
if (testItems.isEmpty()) {
enqueueTests(new List<String>{className});
}
}
public static void enqueueTests(List<String> classNames) {
List<ApexClass> testClasses = [
SELECT Id FROM ApexClass
WHERE Name IN :classNames
];
if (!testClasses.isEmpty()) {
System.enqueueTestRun(testClasses);
}
}
}
```
## Deployment Tools
### SFDX Deployment Scripts
```bash
#!/bin/bash
# deploy.sh
set -e
ENVIRONMENT=$1
TEST_LEVEL=${2:-RunLocalTests}
echo "Deploying to $ENVIRONMENT with test level $TEST_LEVEL"
# Authenticate
case $ENVIRONMENT in
"sandbox")
sf org login web --instance-url https://test.salesforce.com --alias deploy-org
;;
"production")
sf org login web --instance-url https://login.salesforce.com --alias deploy-org
;;
*)
echo "Unknown environment: $ENVIRONMENT"
exit 1
;;
esac
# Validate first
echo "Running validation..."
sf project deploy validate \
--target-org deploy-org \
--test-level $TEST_LEVEL \
--wait 30
if [ $? -eq 0 ]; then
echo "Validation successful. Proceeding with deployment..."
sf project deploy start \
--target-org deploy-org \
--test-level $TEST_LEVEL \
--wait 30
else
echo "Validation failed. Aborting deployment."
exit 1
fi
echo "Deployment complete!"
```
### Package Management
```json
// package.json for Salesforce project
{
"name": "salesforce-project",
"version": "1.0.0",
"scripts": {
"lint": "npm run lint:lwc && npm run lint:apex",
"lint:lwc": "eslint force-app/main/default/lwc",
"lint:apex": "sf scanner run --target force-app --format table",
"test": "npm run test:unit && npm run test:apex",
"test:unit": "sfdx-lwc-jest",
"test:apex": "sf apex test run --test-level RunLocalTests --output-dir test-results",
"prettier": "prettier --write \"force-app/**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}\"",
"validate": "sf project deploy validate --test-level RunLocalTests",
"deploy:sandbox": "./scripts/deploy.sh sandbox",
"deploy:production": "./scripts/deploy.sh production",
"retrieve": "sf project retrieve start",
"create:scratch": "sf org create scratch --definition-file config/project-scratch-def.json --alias scratch-org --duration-days 7"
},
"devDependencies": {
"@salesforce/eslint-config-lwc": "^3.2.3",
"@salesforce/sfdx-lwc-jest": "^1.1.0",
"eslint": "^8.11.0",
"prettier": "^2.6.0"
}
}
```
## Monitoring and Logging
### Application Monitoring
```apex
// Custom deployment monitoring
public class DeploymentMonitor {
public static void logDeployment(String status, String details) {
Deployment_Log__c log = new Deployment_Log__c(
Status__c = status,
Deployed_By__c = UserInfo.getUserId(),
Deployment_Date__c = DateTime.now(),
Details__c = details,
Components_Deployed__c = getDeployedComponents()
);
insert log;
if (status == 'Failed') {
sendAlertToDevOpsTeam(log);
}
}
private static void sendAlertToDevOpsTeam(Deployment_Log__c log) {
Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage();
email.setToAddresses(new List<String>{'devops@company.com'});
email.setSubject('Deployment Failed: ' + log.Id);
email.setHtmlBody(buildEmailBody(log));
Messaging.sendEmail(new List<Messaging.SingleEmailMessage>{email});
}
}
```
### Performance Monitoring
```javascript
// Monitor deployment performance
class DeploymentMetrics {
constructor() {
this.metrics = {
startTime: null,
endTime: null,
componentsDeployed: 0,
testsRun: 0,
testsPassed: 0,
codeCoverage: 0,
};
}
startDeployment() {
this.metrics.startTime = new Date();
}
endDeployment(results) {
this.metrics.endTime = new Date();
this.metrics.duration = this.metrics.endTime - this.metrics.startTime;
this.metrics.componentsDeployed = results.numberComponentsDeployed;
this.metrics.testsRun = results.numberTestsCompleted;
this.metrics.testsPassed = results.numberTestsCompleted - results.numberTestErrors;
this.metrics.codeCoverage = results.totalCoverage;
this.logMetrics();
}
logMetrics() {
console.log('Deployment Metrics:', JSON.stringify(this.metrics, null, 2));
// Send to monitoring service
fetch('https://monitoring.company.com/api/deployments', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + process.env.MONITORING_API_KEY,
},
body: JSON.stringify(this.metrics),
});
}
}
```
## Best Practices
### DevOps Maturity Model
| Level | Characteristics | Tools |
| ------------------- | -------------------------------------- | ---------------------------- |
| 1 - Manual | Manual deployments, no version control | Change Sets |
| 2 - Version Control | Code in Git, manual deployments | Git + Change Sets |
| 3 - CI/CD | Automated testing and deployment | Git + Jenkins/GitHub Actions |
| 4 - Advanced | Full automation, quality gates | Git + CI/CD + Copado/Gearset |
| 5 - Optimized | Predictive analytics, self-healing | AI-powered DevOps platforms |
### Tool Selection Criteria
```yaml
tool_evaluation:
criteria:
- version_control_integration: required
- deployment_automation: required
- testing_support: required
- rollback_capability: required
- monitoring_and_reporting: important
- cost_effectiveness: important
- learning_curve: consider
- community_support: consider
scoring_matrix:
native_tools:
pros: ['Free', 'Direct integration', 'Salesforce support']
cons: ['Limited features', 'Manual configuration']
score: 7/10
enterprise_platforms:
pros: ['Full features', 'Support', 'Compliance']
cons: ['Cost', 'Complexity']
score: 9/10
open_source:
pros: ['Free', 'Customizable', 'Community']
cons: ['Setup complexity', 'Maintenance']
score: 6/10
```
## Additional Resources
- [Salesforce DX Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/)
- [DevOps Center Documentation](https://help.salesforce.com/s/articleView?id=sf.devops_center.htm)
- [CI/CD for Salesforce Best Practices](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_ci_cd.htm)
- [Trailhead: Salesforce DevOps](https://trailhead.salesforce.com/content/learn/trails/build-devops-culture)