CI/CD Integration
This guide covers best practices for integrating lomi with your CI/CD pipeline, ensuring reliable deployments and automated testing.
Environment Setup
1. Environment Variables
# .env.ci
LOMI_API_KEY=test_key_xxx
LOMI_WEBHOOK_SECRET=whsec_xxx
LOMI_ENV=test
2. Secrets Management
// config/secrets.ts
export function loadSecrets() {
const requiredSecrets = [
'LOMI_API_KEY',
'LOMI_WEBHOOK_SECRET'
];
for (const secret of requiredSecrets) {
if (!process.env[secret]) {
throw new Error(`Missing required secret: ${secret}`);
}
}
}
GitHub Actions
1. Test Workflow
# .github/workflows/test.yml
name: Test
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '16'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
env:
LOMI_API_KEY: ${{ secrets.LOMI_TEST_API_KEY }}
LOMI_WEBHOOK_SECRET: ${{ secrets.TEST_WEBHOOK_SECRET }}
LOMI_ENV: test
2. Deploy Workflow
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: eu-west-1
- name: Deploy to production
run: |
npm ci
npm run build
npm run deploy
env:
LOMI_API_KEY: ${{ secrets.LOMI_PROD_API_KEY }}
LOMI_WEBHOOK_SECRET: ${{ secrets.PROD_WEBHOOK_SECRET }}
LOMI_ENV: production
Automated Testing
1. Pre-deployment Tests
// scripts/pre-deploy.ts
import { LomiSDK } from '@lomi/sdk';
async function runPreDeploymentChecks() {
const lomi = new LomiSDK({
apiKey: process.env.LOMI_API_KEY
});
// 1. Verify API connectivity
await lomi.merchants.list();
// 2. Test webhook endpoint
const webhookTest = await lomi.webhooks.test({
url: process.env.WEBHOOK_URL
});
if (!webhookTest.success) {
throw new Error('Webhook test failed');
}
// 3. Verify provider availability
const providers = await lomi.providers.list();
if (providers.length === 0) {
throw new Error('No payment providers available');
}
}
2. Integration Tests
// tests/integration/payment.test.ts
describe('Payment Integration', () => {
const lomi = new LomiSDK({
apiKey: process.env.LOMI_API_KEY
});
beforeAll(async () => {
// Setup test environment
await setupTestEnvironment();
});
it('should process payment end-to-end', async () => {
// Create session
const session = await lomi.checkoutSessions.create({
merchant_id: process.env.TEST_MERCHANT_ID,
amount: 1000,
currency: 'XOF',
provider_codes: ['FREE_MONEY']
});
// Simulate payment
await lomi.test.simulatePayment(session.id);
// Verify success
const updated = await lomi.checkoutSessions.retrieve(
session.id
);
expect(updated.status).toBe('succeeded');
});
});
Deployment Strategies
1. Blue-Green Deployment
// scripts/deploy.ts
async function blueGreenDeploy() {
// 1. Deploy to staging
await deploy('staging');
// 2. Run health checks
const health = await checkHealth('staging');
if (!health.ok) {
await rollback('staging');
throw new Error('Health check failed');
}
// 3. Switch traffic
await switchTraffic('staging', 'production');
// 4. Monitor for errors
await monitorDeployment();
}
2. Canary Deployment
// scripts/canary.ts
async function canaryDeploy() {
// 1. Deploy to canary
await deploy('canary', { capacity: '10%' });
// 2. Monitor metrics
const metrics = await monitorCanary({
duration: '1h',
errorThreshold: 0.1
});
if (metrics.errorRate > 0.1) {
await rollback('canary');
throw new Error('Canary failed');
}
// 3. Scale up deployment
await scaleDeployment('canary', '100%');
}
Monitoring
1. Health Checks
// monitoring/health.ts
export async function checkServiceHealth() {
try {
// 1. API health
await lomi.merchants.list();
// 2. Webhook health
const webhooks = await lomi.webhooks.list();
const activeWebhooks = webhooks.filter(
w => w.status === 'active'
);
if (activeWebhooks.length === 0) {
throw new Error('No active webhooks');
}
// 3. Database health
await db.raw('SELECT 1');
return { status: 'healthy' };
} catch (error) {
return {
status: 'unhealthy',
error: error.message
};
}
}
2. Metrics Collection
// monitoring/metrics.ts
export function collectMetrics() {
return {
// Payment metrics
payments: {
success: getSuccessRate(),
volume: getPaymentVolume(),
latency: getAverageLatency()
},
// Webhook metrics
webhooks: {
delivery: getDeliveryRate(),
latency: getWebhookLatency()
},
// System metrics
system: {
memory: getMemoryUsage(),
cpu: getCPUUsage(),
errors: getErrorRate()
}
};
}
Rollback Procedures
1. Automated Rollback
// scripts/rollback.ts
async function automaticRollback(deployment: string) {
try {
// 1. Stop traffic to new version
await stopTraffic(deployment);
// 2. Restore previous version
await restorePreviousVersion();
// 3. Verify rollback
const health = await checkHealth('production');
if (!health.ok) {
throw new Error('Rollback verification failed');
}
// 4. Notify team
await notifyTeam('Rollback completed');
} catch (error) {
await notifyTeam('Manual intervention required');
throw error;
}
}