feat: 增加发布策略校验
- projects: 为环境补充 releasePolicy 和 refPattern,区分 branch、tag、master 发布策略 - deploy-runs: 创建发布单前校验项目状态、环境和 ref 规则 - repository: 数据库读取路径补齐发布策略推断
This commit is contained in:
@@ -6,6 +6,10 @@ import {
|
||||
DeployNotificationEvent,
|
||||
DeployNotificationService,
|
||||
} from '../notifications/wecom/deploy-notification.service';
|
||||
import {
|
||||
ProjectEnvironmentSummary,
|
||||
ProjectSummary,
|
||||
} from '../projects/project.types';
|
||||
import { ProjectsService } from '../projects/projects.service';
|
||||
import { DeployExecutionService } from './deploy-execution.service';
|
||||
import { DeployRunRepository } from './deploy-run.repository';
|
||||
@@ -57,6 +61,7 @@ export class DeployRunsService {
|
||||
}
|
||||
|
||||
const project = await this.projectsService.getProject(input.projectKey);
|
||||
this.validateReleaseRequest(input, project);
|
||||
const run = this.deployRunRepository.create(input);
|
||||
|
||||
this.auditService.record({
|
||||
@@ -189,6 +194,70 @@ export class DeployRunsService {
|
||||
);
|
||||
}
|
||||
|
||||
private validateReleaseRequest(
|
||||
input: CreateDeployRunInput,
|
||||
project: ProjectSummary,
|
||||
): ProjectEnvironmentSummary {
|
||||
if (project.status !== 'active') {
|
||||
this.recordDeployRejected(input, 'Project is archived');
|
||||
throw new AppError(
|
||||
'VALIDATION_FAILED',
|
||||
`Project ${project.key} is archived and cannot be deployed`,
|
||||
400,
|
||||
{ projectKey: project.key },
|
||||
);
|
||||
}
|
||||
|
||||
const environment = project.environments.find(
|
||||
(item) => item.name === input.environment,
|
||||
);
|
||||
|
||||
if (!environment) {
|
||||
this.recordDeployRejected(input, 'Environment is not configured');
|
||||
throw new AppError(
|
||||
'VALIDATION_FAILED',
|
||||
`Project ${project.key} does not expose ${input.environment} environment`,
|
||||
400,
|
||||
{ projectKey: project.key, environment: input.environment },
|
||||
);
|
||||
}
|
||||
|
||||
if (!new RegExp(environment.refPattern).test(input.ref)) {
|
||||
this.recordDeployRejected(input, 'Ref does not match release policy');
|
||||
throw new AppError(
|
||||
'VALIDATION_FAILED',
|
||||
`Ref ${input.ref} does not match ${environment.releasePolicy} release policy`,
|
||||
400,
|
||||
{
|
||||
projectKey: project.key,
|
||||
environment: input.environment,
|
||||
ref: input.ref,
|
||||
releasePolicy: environment.releasePolicy,
|
||||
refPattern: environment.refPattern,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return environment;
|
||||
}
|
||||
|
||||
private recordDeployRejected(
|
||||
input: CreateDeployRunInput,
|
||||
reason: string,
|
||||
): void {
|
||||
this.auditService.record({
|
||||
action: 'DEPLOY_REJECTED',
|
||||
resourceType: 'deploy_run',
|
||||
actorName: input.operator,
|
||||
after: {
|
||||
projectKey: input.projectKey,
|
||||
environment: input.environment,
|
||||
ref: input.ref,
|
||||
reason,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private toSafeSyncError(error: unknown): string {
|
||||
const message =
|
||||
error instanceof Error ? error.message : 'Jenkins sync failed';
|
||||
|
||||
Reference in New Issue
Block a user