Combine DevCycle, CodeScene, and Sentry for safe, controlled releases.
Code Quality Feature Flags Error Monitoring
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ CodeScene │────▶│ DevCycle │────▶│ Sentry │
│ │ │ │ │ │
│ • PR checks │ │ • Rollouts │ │ • Errors │
│ • Code health│ │ • Kill switch│ │ • Performance│
│ • Tech debt │ │ • A/B tests │ │ • Alerts │
└──────────────┘ └──────────────┘ └──────────────┘
- Before Merge: CodeScene validates code quality
- During Rollout: DevCycle controls who sees the feature
- After Release: Sentry monitors for errors
# .github/workflows/safe-deploy.yml
name: Safe Deployment Pipeline
on:
pull_request:
branches: [main]
push:
branches: [main]
jobs:
# Step 1: Code Quality Gate
code-quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: CodeScene Delta Analysis
uses: codescene/codescene-ci-cd@v1
with:
api-token: ${{ secrets.CODESCENE_API_TOKEN }}
project-id: ${{ vars.CODESCENE_PROJECT_ID }}
fail-on-declining-code-health: true
# Step 2: Deploy with Feature Flag
deploy:
needs: code-quality
runs-on: ubuntu-latest
if: github.event_name == 'push'
steps:
- uses: actions/checkout@v4
- name: Deploy Application
run: |
# Your deployment command
npm run deploy
- name: Create Sentry Release
uses: getsentry/action-release@v1
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ vars.SENTRY_ORG }}
SENTRY_PROJECT: ${{ vars.SENTRY_PROJECT }}
with:
environment: production
version: ${{ github.sha }}
- name: Sync DevCycle References
uses: DevCycleHQ/feature-flag-code-refs@v1
with:
client-id: ${{ secrets.DEVCYCLE_CLIENT_ID }}
client-secret: ${{ secrets.DEVCYCLE_CLIENT_SECRET }}
project: your-project// features/newCheckout.js
import { useVariableValue } from '@devcycle/react-client-sdk';
import * as Sentry from '@sentry/react';
export function CheckoutPage() {
const useNewCheckout = useVariableValue('new-checkout-flow', false);
// Track which version users see
Sentry.setTag('checkout_version', useNewCheckout ? 'v2' : 'v1');
if (useNewCheckout) {
return <NewCheckoutFlow />;
}
return <LegacyCheckoutFlow />;
}// monitoring.js
import * as Sentry from '@sentry/node';
import { getDevCycleClient } from '@devcycle/nodejs-server-sdk';
const devcycle = await getDevCycleClient(process.env.DEVCYCLE_SERVER_SDK_KEY);
export async function captureWithFlags(error, user) {
// Get all flags for this user
const variables = await devcycle.allVariables(user);
Sentry.captureException(error, {
tags: {
// Include flag states in Sentry
...Object.fromEntries(
Object.entries(variables).map(([key, v]) => [`flag_${key}`, v.value])
),
},
});
}// DevCycle targeting: team@company.com only
// CodeScene: Must pass quality gate
// Sentry: Monitor for new errors// DevCycle: Enable for beta group
// Sentry: Set up alert for error spike
// Monitor: 24-48 hours// DevCycle: Increase percentage daily
// Sentry: Compare error rates between versions
// CodeScene: Continue monitoring code health// If errors spike, disable flag immediately
// DevCycle: Set flag to false for all users
// Sentry: Investigate root cause# CodeScene
CODESCENE_API_TOKEN=your_token
CODESCENE_PROJECT_ID=your_project_id
# DevCycle
DEVCYCLE_SERVER_SDK_KEY=server_key
DEVCYCLE_CLIENT_SDK_KEY=client_key
# Sentry
SENTRY_DSN=https://key@sentry.io/project
SENTRY_AUTH_TOKEN=your_token
SENTRY_ORG=your_org
SENTRY_PROJECT=your_projectTrack these metrics:
| Metric | Tool | Alert Threshold |
|---|---|---|
| Code Health | CodeScene | < 8.0 |
| Error Rate | Sentry | > 1% increase |
| P95 Latency | Sentry | > 500ms |
| Flag Evaluations | DevCycle | Anomalies |
- Gate PRs on code quality: Don't merge declining health
- Start small: 5% rollout minimum
- Monitor before expanding: 24-48 hours per phase
- Include flag state in errors: Debug by version
- Have a kill switch: Always be ready to roll back
- Clean up after rollout: Remove flag when at 100%