sfb2b-deploy Skill
Deployment, CI/CD, and org management strategies for Salesforce B2B Commerce at {{clientName}}.
Org Strategy
Progression Path: Scratch Orgs (dev) -> Developer Sandbox -> QA Sandbox -> Staging (Full) -> Production
Each environment serves distinct purposes in the development and release lifecycle:
- •Scratch Orgs: Disposable, feature-branch development
- •Developer Sandbox: Isolated developer experiments
- •QA Sandbox: Integration testing and cross-feature validation
- •Staging (Full): UAT, pre-production validation, performance testing
- •Production: Live {{clientName}} environment
Scratch Org Management
project-scratch-def.json Configuration
{
"orgName": "{{clientName}} B2B Commerce",
"edition": "Enterprise",
"features": [
"B2BCommerce",
"Communities",
"ServiceCloud",
"ExperienceCloudSites",
"StateAndCountryPicklist"
],
"settings": {
"lightningExperienceSettings": {
"enableS1DesktopEnabled": true
},
"mobileSettings": {
"enableS1EncryptedStoragePref2": false
},
"communitiesSettings": {
"enableNetworkSearch": true
},
"chatterSettings": {
"enableChatter": true
},
"contentDeliveryNetworkSettings": {
"enableCDN": true
},
"omniChannelSettings": {
"enableOmniChannel": true
},
"experienceCloudSettings": {
"enableExperienceCloudSites": true,
"enableExperienceCloudLogins": true
}
}
}
Key Features Enabled:
- •
B2BCommerce: Core B2B Commerce Cloud platform - •
Communities: Community Cloud for buyer portal - •
ServiceCloud: Service case management (if needed) - •
ExperienceCloudSites: Modern site builder - •
StateAndCountryPicklist: Standardized address fields
Bootstrap Sequence (8 Steps)
Step 1: Create Scratch Org
sf org create scratch \
--definition-file config/project-scratch-def.json \
--alias {{scratchOrgAlias}} \
--set-default \
--duration-days 30
Step 2: Verify Org Creation
sf org display --target-org {{scratchOrgAlias}}
sf org list
Step 3: Install Dependencies
# Install managed packages if required
sf package install \
--package "ERP Integration Package (PACKAGE_ID_HERE)" \
--target-org {{scratchOrgAlias}} \
--wait 10
sf package install \
--package "Tax Provider Package (PACKAGE_ID_HERE)" \
--target-org {{scratchOrgAlias}} \
--wait 10
Step 4: Deploy Project Metadata
sf project deploy start \
--target-org {{scratchOrgAlias}} \
--metadata force-app/main/default \
--wait 30
Step 5: Execute Test Data Setup
sf apex run \
--target-org {{scratchOrgAlias}} \
--file scripts/setup/{{projectPrefix}}_ScratchOrgSetup.apex
Step 6: Create Named Credentials
sf org execute-command \
--target-org {{scratchOrgAlias}} \
--command "sf data record create \
--sobject NamedCredential \
--values 'DeveloperName={{projectPrefix}}_Middleware_Dev ExternalURL=https://middleware-dev.example.com/api Endpoint__c=https://middleware-dev.example.com/api' \
--json"
Step 7: Verify Deployment
sf apex run test \
--target-org {{scratchOrgAlias}} \
--class-names {{projectPrefix}}_SmokeTest \
--code-coverage
Step 8: Create Scratch Org Pool (for CI)
sf org list auth
sf org create pool \
--definition-file config/project-scratch-def.json \
--alias {{projectPrefixLower}}-pool \
--quantity 5 \
--duration-days 7
Seed Data Loading Strategy
Automated Seed Data Script ({{projectPrefix}}_ScratchOrgSetup.apex)
@isTest
public class {{projectPrefix}}_ScratchOrgSetup {
public static void setupTestData() {
// Create organization structure
List<Account> accounts = {{projectPrefix}}_TestDataFactory.createAccounts(50);
// Create contacts for buyer group administration
List<Contact> contacts = new List<Contact>();
for (Account acc : accounts) {
contacts.add({{projectPrefix}}_TestDataFactory.createContact(
acc,
new Map<String, Object>{
'Email' => 'buyer-admin@' + acc.Name.toLowerCase().replace(' ', '') + '.com'
}
));
}
insert contacts;
// Create product catalog
List<Product2> products = {{projectPrefix}}_TestDataFactory.createProducts(200);
// Create pricebook
Pricebook2 standardPb = [SELECT Id FROM Pricebook2 WHERE IsStandard = true LIMIT 1];
Pricebook2 customPb = {{projectPrefix}}_TestDataFactory.createPricebook('{{clientName}} Pricebook');
// Create pricebook entries
{{projectPrefix}}_TestDataFactory.createPricebookEntries(products, customPb, 1000.00);
// Create buyer groups for each account
List<BuyerGroup> buyerGroups = new List<BuyerGroup>();
for (Account acc : accounts) {
buyerGroups.add({{projectPrefix}}_TestDataFactory.createBuyerGroup(acc, acc.Name + ' Buyers'));
}
insert buyerGroups;
System.debug('Scratch org seeded with: 50 accounts, 200 products, buyer groups');
}
}
Run via CLI:
sf apex run \
--target-org {{scratchOrgAlias}} \
--file scripts/setup/{{projectPrefix}}_ScratchOrgSetup.apex
Scratch Org Pooling for CI
Pools allow CI/CD to grab fresh orgs instantly:
# Create pool
sf org create pool \
--definition-file config/project-scratch-def.json \
--alias {{projectPrefixLower}}-ci-pool \
--quantity 10 \
--duration-days 7
# Use pool org in CI
sf org create scratch \
--target-dev-hub {{orgAlias}} \
--from-pool {{projectPrefixLower}}-ci-pool \
--alias ci-org
# Recycle org back to pool
sf org delete \
--target-org ci-org \
--no-prompt
CI/CD Pipeline (GitHub Actions)
Pipeline Stage Definitions
6-Stage Pipeline:
- •Lint: ESLint + Prettier code quality
- •Jest: Lightning Web Component unit tests
- •Apex Test: Apex unit test coverage
- •Integration: Sandbox integration validation
- •UAT: Staging environment user acceptance
- •Prod: Production deployment (manual approval)
GitHub Actions YAML Templates
.github/workflows/ci.yml - Main CI Pipeline
name: CI Pipeline
on:
pull_request:
branches: [main, develop]
push:
branches: [develop]
jobs:
lint:
name: Lint & Format Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install Dependencies
run: npm ci
- name: Run ESLint
run: npm run lint
continue-on-error: false
- name: Check Prettier Formatting
run: npm run format:check
- name: Upload Lint Results
if: always()
uses: actions/upload-artifact@v3
with:
name: lint-results
path: lint-results.json
jest:
name: Jest Unit Tests
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install Dependencies
run: npm ci
- name: Run Jest Tests
run: npm test -- --coverage --collectCoverageFrom='force-app/**/*.js'
- name: Archive Coverage Report
uses: actions/upload-artifact@v3
with:
name: jest-coverage
path: coverage/
- name: Comment Coverage on PR
if: github.event_name == 'pull_request'
uses: romeovs/lcov-reporter-action@v0.3.1
with:
lcov-file: ./coverage/lcov.info
apex-test:
name: Apex Unit Tests
runs-on: ubuntu-latest
needs: jest
steps:
- uses: actions/checkout@v3
- name: Setup Salesforce CLI
uses: salesforcecli/setup-cli@v1
with:
cli-version: latest
- name: Authorize Dev Hub
run: |
echo "${{ secrets.DEVHUB_SFDX_URL_BASE64 }}" | base64 --decode > ./auth.json
sf org login sfdx-url \
--sfdx-url-file ./auth.json \
--alias devhub \
--set-default-dev-hub
rm ./auth.json
- name: Create Scratch Org from Pool
run: |
sf org create scratch \
--target-dev-hub devhub \
--from-pool {{projectPrefixLower}}-ci-pool \
--alias ci-org \
--set-default
- name: Deploy Metadata
run: |
sf project deploy start \
--target-org ci-org \
--metadata force-app/main/default
- name: Run Apex Tests
run: |
sf apex run test \
--target-org ci-org \
--code-coverage \
--output-dir ./apex-coverage
continue-on-error: false
- name: Parse Apex Coverage
run: |
python3 scripts/ci/parse_apex_coverage.py \
./apex-coverage/test-result-summary.json
- name: Upload Apex Coverage
uses: actions/upload-artifact@v3
with:
name: apex-coverage
path: apex-coverage/
- name: Delete Scratch Org
if: always()
run: |
sf org delete \
--target-org ci-org \
--no-prompt
integration-test:
name: Integration Tests (QA Sandbox)
runs-on: ubuntu-latest
needs: apex-test
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v3
- name: Setup Salesforce CLI
uses: salesforcecli/setup-cli@v1
- name: Authorize QA Sandbox
run: |
echo "${{ secrets.QA_SANDBOX_SFDX_URL_BASE64 }}" | base64 --decode > ./qa-auth.json
sf org login sfdx-url \
--sfdx-url-file ./qa-auth.json \
--alias qa-sandbox
rm ./qa-auth.json
- name: Deploy to QA
run: |
sf project deploy start \
--target-org qa-sandbox \
--metadata force-app/main/default \
--wait 30
- name: Run Integration Tests
run: |
sf apex run test \
--target-org qa-sandbox \
--class-names {{projectPrefix}}_IntegrationTestSuite
- name: Validate Middleware Integration
run: |
npm run integration:test:middleware
- name: Validate Order Creation Flow
run: |
npm run integration:test:orders
staging-deploy:
name: Deploy to Staging
runs-on: ubuntu-latest
needs: integration-test
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
steps:
- uses: actions/checkout@v3
- name: Setup Salesforce CLI
uses: salesforcecli/setup-cli@v1
- name: Authorize Staging
run: |
echo "${{ secrets.STAGING_SFDX_URL_BASE64 }}" | base64 --decode > ./staging-auth.json
sf org login sfdx-url \
--sfdx-url-file ./staging-auth.json \
--alias staging
rm ./staging-auth.json
- name: Validate Deployment
run: |
sf project deploy start \
--target-org staging \
--metadata force-app/main/default \
--dry-run \
--wait 30
- name: Deploy to Staging
run: |
DEPLOY_ID=$(sf project deploy start \
--target-org staging \
--metadata force-app/main/default \
--wait 30 \
--json | jq -r '.result.id')
echo "DEPLOY_ID=$DEPLOY_ID" >> $GITHUB_ENV
- name: Run Smoke Tests
run: |
sf apex run test \
--target-org staging \
--class-names {{projectPrefix}}_SmokeTestSuite
- name: Performance Validation
run: |
npm run perf:test:staging
prod-approval:
name: Production Deployment (Requires Approval)
runs-on: ubuntu-latest
needs: staging-deploy
if: github.ref == 'refs/heads/main'
environment:
name: production
deployment-branch-policy:
protected-branches: true
steps:
- uses: actions/checkout@v3
- name: Setup Salesforce CLI
uses: salesforcecli/setup-cli@v1
- name: Authorize Production
run: |
echo "${{ secrets.PROD_SFDX_URL_BASE64 }}" | base64 --decode > ./prod-auth.json
sf org login sfdx-url \
--sfdx-url-file ./prod-auth.json \
--alias production
rm ./prod-auth.json
- name: Validate Production Deployment
run: |
sf project deploy start \
--target-org production \
--metadata force-app/main/default \
--dry-run \
--wait 30
- name: Deploy to Production
run: |
DEPLOY_ID=$(sf project deploy start \
--target-org production \
--metadata force-app/main/default \
--wait 30 \
--json | jq -r '.result.id')
echo "DEPLOY_ID=$DEPLOY_ID" >> $GITHUB_ENV
- name: Run Production Smoke Tests
run: |
sf apex run test \
--target-org production \
--class-names {{projectPrefix}}_SmokeTestSuite
- name: Notify Deployment Success
if: success()
run: |
curl -X POST ${{ secrets.SLACK_WEBHOOK }} \
-H 'Content-Type: application/json' \
-d '{"text":"{{clientName}} B2B Commerce deployed to production successfully!"}'
SF CLI Authentication in CI (JWT Flow)
Generate JWT Key and Server Key Files:
# Generate private key openssl genrsa -out server.key 2048 # Generate certificate openssl req -new -x509 -days 365 -key server.key -out server.crt # Extract base64 for secrets base64 -i server.key | tr -d '\n' | pbcopy base64 -i server.crt | tr -d '\n' | pbcopy
Store in GitHub Secrets:
- •
DEVHUB_SFDX_URL_BASE64: DevHub org JWT auth URL (base64) - •
QA_SANDBOX_SFDX_URL_BASE64: QA sandbox auth URL - •
STAGING_SFDX_URL_BASE64: Staging auth URL - •
PROD_SFDX_URL_BASE64: Production auth URL
Authenticate in Workflow:
echo "${{ secrets.DEVHUB_SFDX_URL_BASE64 }}" | base64 --decode > ./auth.json
sf org login sfdx-url \
--sfdx-url-file ./auth.json \
--alias devhub \
--set-default-dev-hub
Artifact Management
Store build artifacts across pipeline stages:
- name: Upload Test Results
if: always()
uses: actions/upload-artifact@v3
with:
name: test-results-${{ github.run_number }}
path: |
apex-coverage/
coverage/
deployment-report.json
retention-days: 30
- name: Download Previous Artifacts
uses: actions/download-artifact@v3
with:
name: test-results-${{ github.run_number }}
Deployment Procedures
Pre-Deployment Checklist
- • All tests passing (Jest >80%, Apex >85%)
- • Code review approved by 2+ team members
- • No merge conflicts with target branch
- • Related issues/tickets linked and closed
- • Release notes drafted in RELEASES.md
- • Database migration scripts (if any) tested
- • Third-party integrations verified (middleware, tax provider)
- • Performance benchmarks met
- • Security scan (SFDX Scanner) passed
- • Stakeholder sign-off obtained (for prod)
Metadata Deployment Order
Critical sequence to avoid dependency issues:
# Step 1: Deploy Core Objects sf project deploy start \ --target-org staging \ --metadata-dir force-app/main/default/objects \ --wait 30 # Step 2: Deploy Custom Settings & Metadata Types sf project deploy start \ --target-org staging \ --metadata-dir force-app/main/default/customMetadata \ --wait 30 # Step 3: Deploy Apex Classes (dependencies) sf project deploy start \ --target-org staging \ --metadata-dir force-app/main/default/classes \ --wait 30 # Step 4: Deploy Lightning Web Components sf project deploy start \ --target-org staging \ --metadata-dir force-app/main/default/lwc \ --wait 30 # Step 5: Deploy Flows & Processes sf project deploy start \ --target-org staging \ --metadata-dir force-app/main/default/flows \ --wait 30 # Step 6: Deploy Permission Sets & Profiles sf project deploy start \ --target-org staging \ --metadata-dir force-app/main/default/permissionsets,force-app/main/default/profiles \ --wait 30 # Step 7: Deploy Experience Cloud Sites sf project deploy start \ --target-org staging \ --metadata-dir force-app/main/default/sites,force-app/main/default/experiences \ --wait 30 # Step 8: Deploy All Remaining Metadata sf project deploy start \ --target-org staging \ --metadata force-app/main/default \ --wait 30
Post-Deployment Validation Steps
# 1. Verify Deployment Success
sf project deploy report --use-most-recent
# 2. Run Smoke Test Suite
sf apex run test \
--target-org staging \
--class-names {{projectPrefix}}_SmokeTestSuite \
--wait 30
# 3. Validate No Configuration Errors
sf data query \
--target-org staging \
--query "SELECT Count() FROM ApexTestQueueItem WHERE Status = 'Failed'"
# 4. Check Named Credentials Status
sf data query \
--target-org staging \
--query "SELECT DeveloperName, ExternalURL, IsActive FROM NamedCredential"
# 5. Validate Feature Flags
sf data query \
--target-org staging \
--query "SELECT DeveloperName, Value__c FROM {{projectPrefix}}_Feature_Flag__mdt"
# 6. Verify Integration Connectivity
sf apex run --target-org staging --file scripts/validation/TestIntegrationConnectivity.apex
Rollback Procedures
Automatic Rollback (if smoke tests fail):
# Get previous deployment ID PREV_DEPLOY_ID=$(sf project deploy list \ --target-org staging \ --json | jq -r '.result[-2].id') # Rollback previous deployment sf project deploy cancel --job-id $PREV_DEPLOY_ID
Manual Rollback (revert to previous commit):
# In version control, revert the commit git revert HEAD --no-edit # Create hotfix branch git checkout -b hotfix/rollback-deployment # Push and create PR for review git push origin hotfix/rollback-deployment # After approval, merge and redeploy
Environment Configuration
Named Credentials per Environment
Create Named Credentials for each environment:
# Middleware API (Development)
sf data record create \
--target-org {{scratchOrgAlias}} \
--sobject NamedCredential \
--values 'DeveloperName={{projectPrefix}}_Middleware_Dev ExternalURL=https://middleware-dev.example.com/api AuthenticationProtocol=OAuth2CertificateFlow OauthTokenEndpoint=https://middleware-dev.example.com/oauth/authorize'
# Middleware API (Production)
sf data record create \
--target-org production \
--sobject NamedCredential \
--values 'DeveloperName={{projectPrefix}}_Middleware_Prod ExternalURL=https://middleware.example.com/api AuthenticationProtocol=OAuth2CertificateFlow OauthTokenEndpoint=https://middleware.example.com/oauth/authorize'
# Tax Service (Development)
sf data record create \
--target-org {{scratchOrgAlias}} \
--sobject NamedCredential \
--values 'DeveloperName={{projectPrefix}}_Tax_Dev ExternalURL=https://sandbox.tax-provider.com/api/v2 AuthenticationProtocol=BasicAuthentication'
Custom Settings per Environment
Metadata-driven configuration approach:
<!-- force-app/main/default/customMetadata/{{projectPrefix}}_Config.{{projectPrefix}}_Dev.md-meta.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<CustomMetadata xmlns="http://soap.sforce.com/2006/04/metadata">
<label>{{projectPrefix}} Dev Configuration</label>
<protected>false</protected>
<records>
<fullName>{{projectPrefix}}_Config.{{projectPrefix}}_Dev</fullName>
<fields>
<name>Environment__c</name>
<value xsi:type="xsd:string">Development</value>
</fields>
<fields>
<name>Middleware_API_Endpoint__c</name>
<value xsi:type="xsd:string">https://middleware-dev.example.com/api</value>
</fields>
<fields>
<name>Tax_Environment__c</name>
<value xsi:type="xsd:string">Sandbox</value>
</fields>
<fields>
<name>Order_Visibility_SLA_Minutes__c</name>
<value xsi:type="xsd:double">2</value>
</fields>
<fields>
<name>Enable_Debug_Logging__c</name>
<value xsi:type="xsd:boolean">true</value>
</fields>
</records>
</CustomMetadata>
Query in code:
{{projectPrefix}}_Config__mdt config = {{projectPrefix}}_Config__mdt.getInstance('{{projectPrefix}}_Dev');
String endpoint = config.Middleware_API_Endpoint__c;
Feature Toggles via Custom Metadata
<!-- force-app/main/default/customMetadata/{{projectPrefix}}_Feature_Flag.EnableAdvancedPricing.md-meta.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<CustomMetadata xmlns="http://soap.sforce.com/2006/04/metadata">
<label>Enable Advanced Pricing</label>
<protected>false</protected>
<records>
<fullName>{{projectPrefix}}_Feature_Flag.EnableAdvancedPricing</fullName>
<fields>
<name>IsEnabled__c</name>
<value xsi:type="xsd:boolean">true</value>
</fields>
<fields>
<name>Rollout_Percentage__c</name>
<value xsi:type="xsd:double">100</value>
</fields>
<fields>
<name>Description__c</name>
<value xsi:type="xsd:string">Enable tiered pricing calculations for bulk orders</value>
</fields>
</records>
</CustomMetadata>
Usage in Apex:
{{projectPrefix}}_Feature_Flag__mdt featureFlag = {{projectPrefix}}_Feature_Flag__mdt.getInstance('EnableAdvancedPricing');
if (featureFlag.IsEnabled__c) {
// Use advanced pricing logic
}
Data Migration Scripts
Example migration script structure:
# scripts/migrations/001_add_custom_fields.sh
#!/bin/bash
echo "Running migration: Add Custom Fields to Order"
sf data record create \
--target-org $TARGET_ORG \
--sobject CustomField \
--values "TableEnumOrId=Order DeveloperName={{projectPrefix}}_Internal_Order_ID__c Type=Text Length=50"
echo "Migration completed successfully"
Release Management
Version Tagging Strategy
Semantic Versioning: MAJOR.MINOR.PATCH
# Tag a release
git tag -a v1.2.3 -m "{{clientName}} B2B Commerce Release 1.2.3"
# Tag format: v{MAJOR}.{MINOR}.{PATCH}-{ENV} for pre-release
git tag -a v1.2.3-rc.1 -m "Release candidate 1 for v1.2.3"
# Push tags
git push origin v1.2.3
Release Notes Template
RELEASES.md entry:
## [1.2.3] - 2024-02-15 ### Added - New tiered pricing calculation engine for bulk orders - Advanced inventory forecasting in product details - Buyer group discount tiers with percentage overrides ### Changed - Refactored cart calculation service for 30% performance improvement - Updated order visibility SLA from 60s to 30s - Middleware integration now uses v2 API endpoint ### Fixed - Resolved issue where tax calculations were not applying to certain buyer groups - Fixed race condition in concurrent cart updates - Corrected tax surcharge mapping for product category ### Security - Updated JWT certificate for middleware authentication - Implemented additional CSRF protection on checkout flow ### Performance - Cart load time reduced from 3.5s to 1.2s (average) - Search index query optimized, reducing response time by 40% - Order processing throughput increased to 500 orders/minute ### Migration Notes - Run migration script: `scripts/migrations/002_update_pricebook_entries.sh` - Update Named Credentials with new middleware v2 endpoints - Refresh all scratch orgs to enable new features ### Dependencies - Requires Salesforce Spring '24 release minimum - ERP v8.5+ required - Middleware runtime version 4.3.0+
Go/No-Go Checklist
Before production deployment approval:
| Item | Responsible | Status |
|---|---|---|
| All smoke tests passing | QA Team | Pass/Fail |
| Performance benchmarks met | Platform Team | Pass/Fail |
| Security scan complete | Security Team | Pass/Fail |
| Third-party integrations validated | Integration Team | Pass/Fail |
| Staging UAT complete | Business Team | Pass/Fail |
| Rollback plan documented | Release Mgr | Pass/Fail |
| Stakeholder approval obtained | Product Owner | Pass/Fail |
| Communication plan executed | Communications | Pass/Fail |
Go/No-Go Meeting: 1 hour before deployment window
Maintenance Window Procedures
During production deployments:
# 1. Set maintenance message
sf data record create \
--target-org production \
--sobject {{projectPrefix}}_System_Status__c \
--values "IsUnderMaintenance__c=true MaintenanceMessage__c='System maintenance in progress. Expected completion at 2:30 PM EST.'"
# 2. Monitor deployment
watch -n 10 "sf project deploy report --use-most-recent --json | jq '.result | {status, numberComponentsDeployed, numberTestsCompleted}'"
# 3. Run smoke tests
sf apex run test --target-org production --class-names {{projectPrefix}}_SmokeTestSuite
# 4. Clear maintenance mode
sf data record update \
--target-org production \
--sobject {{projectPrefix}}_System_Status__c \
--values "IsUnderMaintenance__c=false"
# 5. Notify stakeholders
curl -X POST ${{ secrets.SLACK_WEBHOOK }} \
-H 'Content-Type: application/json' \
-d '{"text":"{{clientName}} B2B Commerce maintenance complete. System is live."}'
Rollback within 15 minutes if critical issue detected:
# Get deployment details DEPLOY_ID=$(sf project deploy list --target-org production --json | jq -r '.result[0].id') # Revert to previous version git revert HEAD git push origin main # Immediate redeploy sf project deploy start --target-org production --metadata force-app/main/default
Quick Reference Commands
Scratch Org Management
sf org create scratch -d config/project-scratch-def.json -a dev sf org display --target-org dev sf org list --all sf org delete --target-org dev
Deployment
sf project deploy start --target-org staging --metadata force-app/main/default sf project deploy report --use-most-recent sf project deploy cancel --job-id 0A7xxxxxxxxxxxxxxx
Testing
sf apex run test --target-org staging --class-names {{projectPrefix}}_OrderServiceTest
npm test -- --coverage
Org Synchronization
sf project retrieve start --target-org staging --metadata force-app/main/default sf project deploy start --target-org staging --metadata force-app/main/default