feat: add redeploy endpoint — rebuild from latest git/zip source and deploy new version

- Backend: added redeployApplication() to DeploymentsService that creates
  a new deployment record and re-runs the full build+deploy pipeline
- Backend: added POST /deployments/applications/:appId/redeploy endpoint
- Frontend: added Redeploy button on app detail page, visible after first
  deploy when no build is in progress
- For git-based apps: pulls latest code from repo on each redeploy
- For zip-based apps: rebuilds from last uploaded source code
This commit is contained in:
keyhan
2026-04-05 15:47:56 +03:30
parent 33be1649c4
commit 0438192f8e
3 changed files with 58 additions and 0 deletions
@@ -62,4 +62,11 @@ export class DeploymentsController {
await this.deploymentsService.restartDeployment(appId, req.user.id);
return { message: 'Application restarted' };
}
@Post('applications/:appId/redeploy')
@ApiOperation({ summary: 'Redeploy: rebuild from latest source (git pull / zip) and deploy new version' })
async redeploy(@Param('appId') appId: string, @Request() req: any) {
const deployment = await this.deploymentsService.redeployApplication(appId, req.user.id);
return { message: 'Redeploy triggered', deployment };
}
}
@@ -134,6 +134,36 @@ export class DeploymentsService {
await this.kubernetesService.restartDeployment(app);
}
/**
* Redeploy: re-build from latest source (git pull or existing zip) and deploy new version.
* For git-based apps this pulls the latest code, for zip-based it rebuilds from last uploaded zip.
*/
async redeployApplication(applicationId: string, userId: string): Promise<Deployment> {
const app = await this.applicationsService.findOne(applicationId, userId);
if (!app.codePath && !app.gitUrl) {
throw new NotFoundException('No source code available. Upload code or set a git URL first.');
}
// Create new deployment record
const deployment = this.deploymentsRepository.create({
applicationId: app.id,
triggeredBy: userId,
imageTag: `${app.name}:${Date.now()}`,
status: DeploymentStatus.PENDING,
version: `v${Date.now()}`,
});
const saved = await this.deploymentsRepository.save(deployment);
// Trigger async build & deploy pipeline (same as initial deploy)
this.executePipeline(saved.id, app).catch((error) => {
this.logger.error(`Redeploy pipeline failed for deployment ${saved.id}:`, error);
});
this.logger.log(`Redeploy triggered for ${app.name} (${app.gitUrl ? 'git: ' + app.gitUrl : 'zip'})`);
return saved;
}
async deleteAllForApplication(applicationId: string): Promise<void> {
await this.deploymentsRepository.delete({ applicationId });
}