From 78f97fedf86054773114cc5ff1ffd4fd9dd90f98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B9=9B=E5=85=AE?= Date: Fri, 12 Jun 2026 01:16:41 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=99=90=E5=88=B6=E5=8F=91=E5=B8=83?= =?UTF-8?q?=E5=8D=95=E9=87=8D=E8=AF=95=E8=BE=B9=E7=95=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/deploy-runs/deploy-runs.service.spec.ts | 17 ++++++++++++++++- src/deploy-runs/deploy-runs.service.ts | 13 +++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/deploy-runs/deploy-runs.service.spec.ts b/src/deploy-runs/deploy-runs.service.spec.ts index 829a173..3fa4f77 100644 --- a/src/deploy-runs/deploy-runs.service.spec.ts +++ b/src/deploy-runs/deploy-runs.service.spec.ts @@ -382,7 +382,13 @@ describe('DeployRunsService', () => { }); it('retries a deploy run with retry trigger', async () => { - const { repository, service } = createService(); + const failedRun: DeployRunSummary = { + ...baseRun, + status: 'failed', + }; + const { repository, service } = createService({ + runs: [failedRun], + }); const run = await service.retryRun(baseRun.id); @@ -396,6 +402,15 @@ describe('DeployRunsService', () => { ); }); + it('rejects non-terminal retry requests before creating a new run', async () => { + const { repository, service } = createService(); + + await expect(service.retryRun(baseRun.id)).rejects.toBeInstanceOf( + AppError, + ); + expect(repository.create).not.toHaveBeenCalled(); + }); + it('syncs all queued or running Jenkins runs with queue/build identifiers', async () => { const queuedRun: DeployRunSummary = { ...baseRun, diff --git a/src/deploy-runs/deploy-runs.service.ts b/src/deploy-runs/deploy-runs.service.ts index 461c9fc..066a986 100644 --- a/src/deploy-runs/deploy-runs.service.ts +++ b/src/deploy-runs/deploy-runs.service.ts @@ -111,6 +111,7 @@ export class DeployRunsService { projectKey: input.projectKey, environment: input.environment, ref: input.ref, + trigger: input.trigger ?? 'manual', remark: input.remark, }, }); @@ -182,6 +183,18 @@ export class DeployRunsService { ): Promise { const source = await this.getRun(id, user); + if (!['failed', 'canceled'].includes(source.status)) { + throw new AppError( + 'VALIDATION_FAILED', + `发布记录 ${id} 当前状态为 ${source.status},只能重试失败或已取消的发布单`, + 400, + { + id, + status: source.status, + }, + ); + } + return this.createRun( { projectKey: source.projectKey,