feat: add quick deploy for launcher backend builds
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
+62
-22
@@ -954,31 +954,70 @@ export class AppsService {
|
|||||||
async createDeploymentJob(body: CreateDeploymentJobDto, requester?: AdminRequester) {
|
async createDeploymentJob(body: CreateDeploymentJobDto, requester?: AdminRequester) {
|
||||||
const namespace = normalizeNamespace(body.namespace);
|
const namespace = normalizeNamespace(body.namespace);
|
||||||
const environment = body.environment.trim();
|
const environment = body.environment.trim();
|
||||||
const release = await this.prisma.appRelease.findUnique({
|
if (body.releaseId && body.buildJobId) {
|
||||||
where: { id: body.releaseId },
|
throw new BadRequestException('릴리즈 또는 빌드 중 하나만 배포 대상으로 선택할 수 있습니다.');
|
||||||
include: {
|
}
|
||||||
app: {
|
|
||||||
include: {
|
|
||||||
components: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!release) {
|
const release = body.releaseId
|
||||||
|
? await this.prisma.appRelease.findUnique({
|
||||||
|
where: { id: body.releaseId },
|
||||||
|
include: {
|
||||||
|
app: {
|
||||||
|
include: {
|
||||||
|
components: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
: null;
|
||||||
|
const quickBuild = body.buildJobId
|
||||||
|
? await this.prisma.buildJob.findUnique({
|
||||||
|
where: { id: body.buildJobId },
|
||||||
|
include: {
|
||||||
|
component: {
|
||||||
|
include: {
|
||||||
|
app: {
|
||||||
|
include: { components: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
: null;
|
||||||
|
|
||||||
|
if (body.releaseId && !release) {
|
||||||
throw new NotFoundException('릴리즈를 찾을 수 없습니다.');
|
throw new NotFoundException('릴리즈를 찾을 수 없습니다.');
|
||||||
}
|
}
|
||||||
|
if (body.buildJobId && !quickBuild) {
|
||||||
if (release.status !== 'SUCCEEDED') {
|
throw new NotFoundException('빌드 작업을 찾을 수 없습니다.');
|
||||||
|
}
|
||||||
|
if (!release && !quickBuild) {
|
||||||
|
throw new BadRequestException('배포할 릴리즈 또는 빌드를 선택하세요.');
|
||||||
|
}
|
||||||
|
if (release && release.status !== 'SUCCEEDED') {
|
||||||
throw new BadRequestException('성공한 릴리즈만 배포할 수 있습니다.');
|
throw new BadRequestException('성공한 릴리즈만 배포할 수 있습니다.');
|
||||||
}
|
}
|
||||||
|
if (quickBuild && quickBuild.status !== 'SUCCEEDED') {
|
||||||
|
throw new BadRequestException('성공한 빌드만 빠른 배포할 수 있습니다.');
|
||||||
|
}
|
||||||
|
if (quickBuild && !['CONTAINER', 'STATIC_WEB'].includes(quickBuild.component.type)) {
|
||||||
|
throw new BadRequestException('컨테이너 이미지 빌드만 빠른 배포할 수 있습니다.');
|
||||||
|
}
|
||||||
|
if (quickBuild && !quickBuild.image) {
|
||||||
|
throw new BadRequestException('배포할 컨테이너 이미지가 없습니다.');
|
||||||
|
}
|
||||||
|
|
||||||
const imageTags = parseReleaseImageTags(release.imageTags);
|
const app = release?.app ?? quickBuild!.component.app;
|
||||||
const images = imageTags.images;
|
const images = release
|
||||||
|
? parseReleaseImageTags(release.imageTags).images
|
||||||
|
: { [quickBuild!.component.name]: quickBuild!.image! };
|
||||||
|
const deploymentLabel = release
|
||||||
|
? `${app.name} ${release.version}`
|
||||||
|
: `${app.name} ${quickBuild!.component.name} ${quickBuild!.commitSha?.slice(0, 7) ?? 'quick'}`;
|
||||||
const requestedResources = body.resources;
|
const requestedResources = body.resources;
|
||||||
const runtimeProfile = await this.prisma.runtimeEnvProfile.findFirst({
|
const runtimeProfile = await this.prisma.runtimeEnvProfile.findFirst({
|
||||||
where: {
|
where: {
|
||||||
appId: release.appId,
|
appId: app.id,
|
||||||
environment,
|
environment,
|
||||||
namespace,
|
namespace,
|
||||||
},
|
},
|
||||||
@@ -1002,8 +1041,8 @@ export class AppsService {
|
|||||||
|
|
||||||
const deploymentJob = await this.prisma.deploymentJob.create({
|
const deploymentJob = await this.prisma.deploymentJob.create({
|
||||||
data: {
|
data: {
|
||||||
appId: release.appId,
|
appId: app.id,
|
||||||
releaseId: release.id,
|
releaseId: release?.id,
|
||||||
environment,
|
environment,
|
||||||
namespace,
|
namespace,
|
||||||
status: 'RUNNING',
|
status: 'RUNNING',
|
||||||
@@ -1011,7 +1050,8 @@ export class AppsService {
|
|||||||
...this.requesterData(requester),
|
...this.requesterData(requester),
|
||||||
startedAt: new Date(),
|
startedAt: new Date(),
|
||||||
logs: [
|
logs: [
|
||||||
`[running] deployment started: ${release.app.name} ${release.version}`,
|
`[running] deployment started: ${deploymentLabel}`,
|
||||||
|
...(quickBuild ? [`[source] quick build ${quickBuild.id} ${quickBuild.image}`] : []),
|
||||||
`[target] environment=${environment} namespace=${namespace}`,
|
`[target] environment=${environment} namespace=${namespace}`,
|
||||||
].join('\n'),
|
].join('\n'),
|
||||||
},
|
},
|
||||||
@@ -1026,7 +1066,7 @@ export class AppsService {
|
|||||||
|
|
||||||
for (const [componentName, image] of Object.entries(images)) {
|
for (const [componentName, image] of Object.entries(images)) {
|
||||||
const deploymentName = sanitizeK8sName(componentName);
|
const deploymentName = sanitizeK8sName(componentName);
|
||||||
const component = release.app.components.find((item) => item.name === componentName);
|
const component = app.components.find((item) => item.name === componentName);
|
||||||
const workloadType = normalizeWorkloadType(component?.workloadType, component?.type);
|
const workloadType = normalizeWorkloadType(component?.workloadType, component?.type);
|
||||||
const deploymentExists = workloadType === 'StatefulSet'
|
const deploymentExists = workloadType === 'StatefulSet'
|
||||||
? await this.statefulSetExists(namespace, deploymentName)
|
? await this.statefulSetExists(namespace, deploymentName)
|
||||||
@@ -1173,7 +1213,7 @@ export class AppsService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (body.updateLauncherAppVersion !== false) {
|
if (release && body.updateLauncherAppVersion !== false) {
|
||||||
try {
|
try {
|
||||||
await this.launcherService.publishAppReleaseToLauncher(release.id);
|
await this.launcherService.publishAppReleaseToLauncher(release.id);
|
||||||
logs.push('[launcher] app version updated');
|
logs.push('[launcher] app version updated');
|
||||||
@@ -1182,7 +1222,7 @@ export class AppsService {
|
|||||||
logs.push(`[launcher] app version update failed: ${launcherMessage}`);
|
logs.push(`[launcher] app version update failed: ${launcherMessage}`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logs.push('[launcher] app version update skipped');
|
logs.push(quickBuild ? '[launcher] app version update skipped for quick deployment' : '[launcher] app version update skipped');
|
||||||
}
|
}
|
||||||
|
|
||||||
logs.push('[done] deployment completed');
|
logs.push('[done] deployment completed');
|
||||||
|
|||||||
+6
-1
@@ -220,8 +220,13 @@ export class DeploymentResourceLimitsDto {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class CreateDeploymentJobDto {
|
export class CreateDeploymentJobDto {
|
||||||
|
@IsOptional()
|
||||||
@IsUUID()
|
@IsUUID()
|
||||||
releaseId!: string;
|
releaseId?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsUUID()
|
||||||
|
buildJobId?: string;
|
||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
environment!: string;
|
environment!: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user