Skip to content

[Copilot] feat: Add deployment pipeline management with rollback support - #14

Open
smb060606 wants to merge 3 commits into
mainfrom
feature/deployment-pipeline-copilot
Open

[Copilot] feat: Add deployment pipeline management with rollback support#14
smb060606 wants to merge 3 commits into
mainfrom
feature/deployment-pipeline-copilot

Conversation

@smb060606

Copy link
Copy Markdown
Collaborator

A developer on the team has implemented the deployment management module. This PR adds the ability to create deployments, track their status through webhooks, view deployment history, calculate statistics, and rollback failed deployments. It also adds service account authentication so CI/CD systems can update deployment status.

This PR is for GitHub Copilot review.

Sahil Mohan Bansal and others added 3 commits May 11, 2026 13:53
Implements the deployment management module:
- Create, list, and get deployment details
- Deploy to staging/production environments
- Rollback deployments to previous versions
- Deployment status webhooks
- Deployment history with filtering and pagination
- Deployment statistics endpoint
- Service account authentication support

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Clean up comments that explicitly labeled code issues. Buggy code
remains unchanged — only the identifying comments were removed or
rewritten as natural developer comments.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented May 11, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4b998c2a-97f0-4710-bc85-854f9a19e002

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/deployment-pipeline-copilot

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new deployments module (CRUD, status updates, history/stats, rollback) and adds service-account authentication to support CI/CD-driven status updates.

Changes:

  • Added deployments service/controller/routes/schema, including rollback logic and history/statistics endpoints.
  • Added webhook signature validation/processing helpers for deployment status updates.
  • Added service-account JWT authentication path and a migration intended to improve deployment query performance.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 19 comments.

Show a summary per file
File Description
src/modules/deployments/webhook.service.ts Adds webhook signature validation + webhook-to-status-update processing.
src/modules/deployments/deployments.service.ts Implements deployment creation, listing, status transitions, rollback, stats, and history querying.
src/modules/deployments/deployments.schema.ts Adds zod schemas for create/status/history query validation.
src/modules/deployments/deployments.routes.ts Wires deployments endpoints into Express routing.
src/modules/deployments/deployments.controller.ts Adds HTTP handlers for deployments endpoints.
src/modules/deployments/deployments.test.ts Adds initial Jest tests for the deployments module.
src/middleware/auth.ts Adds service-account JWT verification path.
prisma/migrations/002_add_deployment_indexes.sql Adds indexes intended to speed up deployment queries.
jest.config.ts Adds explicit transform configuration for ts-jest.
.next/trace-build Adds a generated build trace artifact (should not be committed).
.next/trace Adds a generated build trace artifact (should not be committed).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +11 to +19
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET || 'default-webhook-secret';

export function validateWebhookSignature(payload: string, signature: string): boolean {
const expected = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(payload)
.digest('hex');

logger.info({ signature, secret: WEBHOOK_SECRET }, 'Webhook received');
.update(payload)
.digest('hex');

logger.info({ signature, secret: WEBHOOK_SECRET }, 'Webhook received');
Comment on lines +21 to +24
return crypto.timingSafeEqual(
Buffer.from(signature, 'hex'),
Buffer.from(expected, 'hex'),
);
Comment thread src/middleware/auth.ts
Comment on lines +13 to +15
// Fallback secret for local dev when SA_JWT_SECRET is not configured
const SA_SECRET = process.env.SA_JWT_SECRET || 'teamforge-service-account-2024';

-- Create composite index for filtering deployments by project, environment, and status
-- This supports the common query pattern: WHERE project_id = ? AND environment = ? AND status = ?
CREATE INDEX IF NOT EXISTS idx_deployments_project_env_status
ON deployments (project_id);
Comment on lines +3 to +24
export const createDeploymentSchema = z.object({
projectId: z.string().uuid(),
environment: z.enum(['DEVELOPMENT', 'STAGING', 'PRODUCTION']),
commitSha: z.string().min(7).max(40).optional(),
changelog: z.string().max(5000).optional(),
});

export const updateStatusSchema = z.object({
status: z.enum(['PENDING', 'IN_PROGRESS', 'SUCCESS', 'FAILED', 'ROLLED_BACK']),
completedAt: z.string().datetime().optional(),
});

export const deploymentHistoryQuerySchema = z.object({
projectId: z.string().uuid().optional(),
environment: z.string().optional(),
status: z.string().optional(),
startDate: z.string().datetime().optional(),
endDate: z.string().datetime().optional(),
});

export type CreateDeploymentInput = z.infer<typeof createDeploymentSchema>;
export type UpdateStatusInput = z.infer<typeof updateStatusSchema>;
Comment on lines +18 to +50
const project = await prisma.project.findUnique({ where: { id: input.projectId } });
if (!project) {
throw new NotFoundError('Project', input.projectId);
}

// Auto-increment version based on existing deployments for this project+environment
const existingDeployments = await prisma.deployment.findMany({
where: {
projectId: input.projectId,
environment: input.environment as any,
},
});

const nextVersion = `v${existingDeployments.length}`;

const deployment = await prisma.deployment.create({
data: {
projectId: input.projectId,
version: nextVersion,
environment: input.environment as any,
deployedById: userId,
commitSha: input.commitSha,
changelog: input.changelog,
},
include: {
project: { select: { id: true, name: true, slug: true } },
deployedBy: { select: { id: true, name: true, email: true } },
},
});

logger.info({ deploymentId: deployment.id, version: nextVersion }, 'Deployment created');

return deployment;
Comment on lines +35 to +40
// Format changelog into individual lines
const changelogLines = deployment.changelog.split('\n');

res.json({
...deployment,
changelogFormatted: changelogLines,
Comment on lines +83 to +84
const history = await deploymentsService.getDeploymentHistory(
projectId as string,
Comment on lines +1 to +45
// Basic tests for deployment module
// Note: These tests use a mock database and don't catch all bugs

describe('Deployment Service', () => {
describe('createDeployment', () => {
it('should auto-increment version number', () => {
// Test only verifies version format, not the off-by-one bug
const version = `v${0}`; // Simulates 0 existing deployments
expect(version).toMatch(/^v\d+$/);
});
});

describe('updateDeploymentStatus', () => {
it('should validate status transitions', () => {
const validTransitions: Record<string, string[]> = {
PENDING: ['IN_PROGRESS', 'FAILED'],
IN_PROGRESS: ['SUCCESS', 'FAILED'],
SUCCESS: ['ROLLED_BACK'],
FAILED: [],
ROLLED_BACK: [],
};

expect(validTransitions['PENDING']).toContain('IN_PROGRESS');
expect(validTransitions['IN_PROGRESS']).toContain('SUCCESS');
expect(validTransitions['SUCCESS']).toContain('ROLLED_BACK');
expect(validTransitions['FAILED']).toHaveLength(0);
});
});

describe('rollbackDeployment', () => {
it('should find a previous successful deployment', () => {
// This test doesn't catch the asc/desc bug because it only has one item
const deployments = [
{ id: '1', version: 'v1', status: 'SUCCESS', createdAt: new Date() },
];
expect(deployments).toHaveLength(1);
});
});

describe('getDeploymentStats', () => {
it('should calculate success rate correctly', () => {
const total = 10;
const successful = 7;
const rate = (successful / total) * 100;
expect(rate).toBe(70);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants