Files
stack/apps/api/src/quality-gate-config/quality-gate-config.controller.ts
Jason Woltje 4a2909ce1e feat(#135): implement Quality Gate Configuration System
Add database-backed quality gate configuration for workspaces with
full CRUD operations and default gate seeding.

Schema:
- Add QualityGate model with workspace relation
- Support for custom commands and regex patterns
- Enable/disable and ordering support

Service:
- CRUD operations for quality gates
- findEnabled: Get ordered, enabled gates
- reorder: Bulk reorder with transaction
- seedDefaults: Seed 4 default gates
- toOrchestratorFormat: Convert to orchestrator interface

Endpoints:
- GET /workspaces/:id/quality-gates - List
- GET /workspaces/:id/quality-gates/:gateId - Get one
- POST /workspaces/:id/quality-gates - Create
- PATCH /workspaces/:id/quality-gates/:gateId - Update
- DELETE /workspaces/:id/quality-gates/:gateId - Delete
- POST /workspaces/:id/quality-gates/reorder
- POST /workspaces/:id/quality-gates/seed-defaults

Default gates: Build, Lint, Test, Coverage (85%)

Tests: 25 passing with 95.16% coverage

Fixes #135

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 13:33:04 -06:00

91 lines
2.9 KiB
TypeScript

import { Controller, Get, Post, Patch, Delete, Body, Param, Logger } from "@nestjs/common";
import { QualityGateConfigService } from "./quality-gate-config.service";
import { CreateQualityGateDto, UpdateQualityGateDto } from "./dto";
import type { QualityGate } from "@prisma/client";
/**
* Controller for managing quality gate configurations per workspace
*/
@Controller("workspaces/:workspaceId/quality-gates")
export class QualityGateConfigController {
private readonly logger = new Logger(QualityGateConfigController.name);
constructor(private readonly qualityGateConfigService: QualityGateConfigService) {}
/**
* Get all quality gates for a workspace
*/
@Get()
async findAll(@Param("workspaceId") workspaceId: string): Promise<QualityGate[]> {
this.logger.debug(`GET /workspaces/${workspaceId}/quality-gates`);
return this.qualityGateConfigService.findAll(workspaceId);
}
/**
* Get a specific quality gate
*/
@Get(":id")
async findOne(
@Param("workspaceId") workspaceId: string,
@Param("id") id: string
): Promise<QualityGate> {
this.logger.debug(`GET /workspaces/${workspaceId}/quality-gates/${id}`);
return this.qualityGateConfigService.findOne(workspaceId, id);
}
/**
* Create a new quality gate
*/
@Post()
async create(
@Param("workspaceId") workspaceId: string,
@Body() createDto: CreateQualityGateDto
): Promise<QualityGate> {
this.logger.log(`POST /workspaces/${workspaceId}/quality-gates`);
return this.qualityGateConfigService.create(workspaceId, createDto);
}
/**
* Update a quality gate
*/
@Patch(":id")
async update(
@Param("workspaceId") workspaceId: string,
@Param("id") id: string,
@Body() updateDto: UpdateQualityGateDto
): Promise<QualityGate> {
this.logger.log(`PATCH /workspaces/${workspaceId}/quality-gates/${id}`);
return this.qualityGateConfigService.update(workspaceId, id, updateDto);
}
/**
* Delete a quality gate
*/
@Delete(":id")
async delete(@Param("workspaceId") workspaceId: string, @Param("id") id: string): Promise<void> {
this.logger.log(`DELETE /workspaces/${workspaceId}/quality-gates/${id}`);
return this.qualityGateConfigService.delete(workspaceId, id);
}
/**
* Reorder quality gates
*/
@Post("reorder")
async reorder(
@Param("workspaceId") workspaceId: string,
@Body() body: { gateIds: string[] }
): Promise<QualityGate[]> {
this.logger.log(`POST /workspaces/${workspaceId}/quality-gates/reorder`);
return this.qualityGateConfigService.reorder(workspaceId, body.gateIds);
}
/**
* Seed default quality gates for a workspace
*/
@Post("seed-defaults")
async seedDefaults(@Param("workspaceId") workspaceId: string): Promise<QualityGate[]> {
this.logger.log(`POST /workspaces/${workspaceId}/quality-gates/seed-defaults`);
return this.qualityGateConfigService.seedDefaults(workspaceId);
}
}