Agent Skills: Salesforce CI Integration

|

UncategorizedID: jeremylongshore/claude-code-plugins-plus-skills/salesforce-ci-integration

Install this agent skill to your local

pnpm dlx add-skill https://github.com/jeremylongshore/claude-code-plugins-plus-skills/tree/HEAD/plugins/saas-packs/salesforce-pack/skills/salesforce-ci-integration

Skill Files

Browse the full folder contents for salesforce-ci-integration.

Download Skill

Loading file tree…

plugins/saas-packs/salesforce-pack/skills/salesforce-ci-integration/SKILL.md

Skill Metadata

Name
salesforce-ci-integration
Description
|

Salesforce CI Integration

Overview

Set up CI/CD pipelines for Salesforce using GitHub Actions with JWT-based authentication, automated Apex testing, and metadata deployment.

Prerequisites

  • GitHub repository with Actions enabled
  • Salesforce Connected App with JWT Bearer flow configured
  • RSA key pair (private key stored as GitHub Secret)
  • Scratch org or sandbox for test execution

Instructions

Step 1: Create GitHub Actions Workflow

Create .github/workflows/salesforce-ci.yml:

name: Salesforce CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install Salesforce CLI
        run: npm install -g @salesforce/cli

      - name: Authenticate to Salesforce (JWT)
        run: |
          echo "${{ secrets.SF_JWT_KEY }}" > server.key
          sf org login jwt \
            --client-id ${{ secrets.SF_CLIENT_ID }} \
            --jwt-key-file server.key \
            --username ${{ secrets.SF_USERNAME }} \
            --set-default \
            --alias ci-org
          rm server.key

      - name: Validate Metadata Deployment (dry run)
        run: |
          sf project deploy start \
            --target-org ci-org \
            --dry-run \
            --wait 30

      - name: Run Apex Tests
        run: |
          sf apex run test \
            --target-org ci-org \
            --result-format human \
            --code-coverage \
            --wait 20

      - name: Check API Limits
        run: |
          sf limits api display --target-org ci-org --json | \
            jq '.result[] | select(.name == "DailyApiRequests") | "\(.name): \(.remaining)/\(.max)"'

  integration-tests:
    runs-on: ubuntu-latest
    needs: validate
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci

      - name: Run jsforce Integration Tests
        env:
          SF_LOGIN_URL: https://test.salesforce.com
          SF_USERNAME: ${{ secrets.SF_USERNAME }}
          SF_PASSWORD: ${{ secrets.SF_PASSWORD }}
          SF_SECURITY_TOKEN: ${{ secrets.SF_SECURITY_TOKEN }}
        run: npm run test:integration

Step 2: Configure GitHub Secrets

# JWT private key (from your RSA key pair)
gh secret set SF_JWT_KEY < server.key

# Connected App consumer key
gh secret set SF_CLIENT_ID --body "3MVG9..."

# Integration user credentials
gh secret set SF_USERNAME --body "ci-user@yourcompany.com"
gh secret set SF_PASSWORD --body "password"
gh secret set SF_SECURITY_TOKEN --body "token"

Step 3: Generate JWT Key Pair

# Generate RSA key pair for JWT Bearer flow
openssl genrsa -out server.key 2048
openssl req -new -x509 -key server.key -out server.crt -days 365 \
  -subj "/CN=Salesforce CI/O=YourCompany"

# Upload server.crt to Connected App in Salesforce Setup:
# Setup > App Manager > Your App > Edit > Use Digital Signatures > Choose File

Step 4: Write Integration Tests

import { describe, it, expect } from 'vitest';
import jsforce from 'jsforce';

describe('Salesforce Integration', () => {
  const conn = new jsforce.Connection({
    loginUrl: process.env.SF_LOGIN_URL || 'https://test.salesforce.com',
  });

  beforeAll(async () => {
    await conn.login(
      process.env.SF_USERNAME!,
      process.env.SF_PASSWORD! + process.env.SF_SECURITY_TOKEN!
    );
  });

  it('should query Accounts via SOQL', async () => {
    const result = await conn.query('SELECT Id, Name FROM Account LIMIT 1');
    expect(result.totalSize).toBeGreaterThanOrEqual(0);
    expect(result.done).toBe(true);
  });

  it('should check API limits are not exhausted', async () => {
    const limits = await conn.request('/services/data/v59.0/limits/');
    const remaining = limits.DailyApiRequests.Remaining;
    const max = limits.DailyApiRequests.Max;
    expect(remaining / max).toBeGreaterThan(0.1); // At least 10% remaining
  });

  it('should describe Account sObject', async () => {
    const meta = await conn.sobject('Account').describe();
    expect(meta.name).toBe('Account');
    expect(meta.fields.length).toBeGreaterThan(0);
    expect(meta.fields.find(f => f.name === 'Name')).toBeDefined();
  });
});

Step 5: Metadata Deployment Pipeline

# Deploy on merge to main
deploy:
  runs-on: ubuntu-latest
  if: github.ref == 'refs/heads/main' && github.event_name == 'push'
  needs: [validate, integration-tests]
  steps:
    - uses: actions/checkout@v4
    - name: Install Salesforce CLI
      run: npm install -g @salesforce/cli
    - name: Authenticate
      run: |
        echo "${{ secrets.SF_JWT_KEY_PROD }}" > server.key
        sf org login jwt \
          --client-id ${{ secrets.SF_CLIENT_ID_PROD }} \
          --jwt-key-file server.key \
          --username ${{ secrets.SF_USERNAME_PROD }} \
          --set-default
        rm server.key
    - name: Deploy to Production
      run: |
        sf project deploy start \
          --target-org ${{ secrets.SF_USERNAME_PROD }} \
          --test-level RunLocalTests \
          --wait 30

Output

  • JWT-authenticated CI pipeline
  • Automated Apex test execution on PR
  • Integration tests validating jsforce operations
  • Metadata deployment on merge to main
  • API limit monitoring in CI

Error Handling

| Issue | Cause | Solution | |-------|-------|----------| | INVALID_GRANT | JWT cert not uploaded or user not pre-authorized | Upload cert to Connected App; add user to pre-authorized profiles | | Apex test failures | Test data dependencies | Use @testSetup methods for test isolation | | Deploy validation errors | Missing dependencies | Check component dependencies with sf project deploy report | | API limit in CI | Too many test runs/day | Use sandbox instead of production for CI |

Resources

Next Steps

For deployment patterns, see salesforce-deploy-integration.