use app version in R2 artifact path

This commit is contained in:
2026-07-02 13:51:21 +09:00
parent 94ce04a966
commit 3d15bdf6bb
+26 -5
View File
@@ -385,6 +385,7 @@ export class BuildRunnerService implements OnModuleInit, OnModuleDestroy {
if (!artifact) { if (!artifact) {
throw new Error(`산출물을 찾을 수 없습니다: ${outputDir}`); throw new Error(`산출물을 찾을 수 없습니다: ${outputDir}`);
} }
const artifactVersion = await readPackageVersion(workDir);
await fs.mkdir(artifactDir, { recursive: true }); await fs.mkdir(artifactDir, { recursive: true });
const destinationName = job.artifact || path.basename(artifact); const destinationName = job.artifact || path.basename(artifact);
@@ -395,6 +396,7 @@ export class BuildRunnerService implements OnModuleInit, OnModuleDestroy {
job, job,
destination, destination,
destinationName, destinationName,
artifactVersion,
append, append,
); );
const publicBaseUrl = this.configService.get<string>('BUILD_ARTIFACT_BASE_URL'); const publicBaseUrl = this.configService.get<string>('BUILD_ARTIFACT_BASE_URL');
@@ -417,6 +419,7 @@ export class BuildRunnerService implements OnModuleInit, OnModuleDestroy {
job: BuildJobWithComponent, job: BuildJobWithComponent,
artifactPath: string, artifactPath: string,
artifactName: string, artifactName: string,
artifactVersion: string | null,
append: (line: string) => Promise<void>, append: (line: string) => Promise<void>,
) { ) {
const bucket = this.configService.get<string>('R2_BUCKET'); const bucket = this.configService.get<string>('R2_BUCKET');
@@ -428,7 +431,7 @@ export class BuildRunnerService implements OnModuleInit, OnModuleDestroy {
return null; return null;
} }
const key = this.createArtifactObjectKey(job, artifactName); const key = this.createArtifactObjectKey(job, artifactName, artifactVersion);
const stat = await fs.stat(artifactPath); const stat = await fs.stat(artifactPath);
const sha256 = await sha256File(artifactPath); const sha256 = await sha256File(artifactPath);
const client = this.getR2Client(accessKeyId, secretAccessKey); const client = this.getR2Client(accessKeyId, secretAccessKey);
@@ -447,6 +450,7 @@ export class BuildRunnerService implements OnModuleInit, OnModuleDestroy {
component: safeMetadataValue(job.component.name), component: safeMetadataValue(job.component.name),
branch: safeMetadataValue(job.branch), branch: safeMetadataValue(job.branch),
commit: safeMetadataValue(job.commitSha ?? ''), commit: safeMetadataValue(job.commitSha ?? ''),
version: safeMetadataValue(artifactVersion ?? ''),
}, },
})); }));
@@ -483,16 +487,21 @@ export class BuildRunnerService implements OnModuleInit, OnModuleDestroy {
return this.r2Client; return this.r2Client;
} }
private createArtifactObjectKey(job: BuildJobWithComponent, artifactName: string) { private createArtifactObjectKey(
job: BuildJobWithComponent,
artifactName: string,
artifactVersion: string | null,
) {
const prefix = this.configService.get<string>('R2_ARTIFACT_PREFIX', 'studio-artifacts'); const prefix = this.configService.get<string>('R2_ARTIFACT_PREFIX', 'studio-artifacts');
const revision = job.commitSha?.trim().slice(0, 7) || job.id; const versionPath = artifactVersion
? [artifactVersion]
: [job.branch, 'latest'];
return [ return [
prefix, prefix,
'apps', 'apps',
job.component.app.key, job.component.app.key,
job.component.name, job.component.name,
job.branch, ...versionPath,
revision,
artifactName, artifactName,
].map(sanitizeObjectKeyPart).join('/'); ].map(sanitizeObjectKeyPart).join('/');
} }
@@ -679,6 +688,18 @@ async function findNewestArtifact(dir: string) {
return candidates[0]?.path ?? null; return candidates[0]?.path ?? null;
} }
async function readPackageVersion(workDir: string) {
try {
const packageJson = await fs.readFile(path.join(workDir, 'package.json'), 'utf8');
const parsed = JSON.parse(packageJson) as { version?: unknown };
return typeof parsed.version === 'string' && parsed.version.trim()
? parsed.version.trim()
: null;
} catch {
return null;
}
}
async function findArtifactCandidates(dir: string): Promise<Array<{ path: string; mtimeMs: number }>> { async function findArtifactCandidates(dir: string): Promise<Array<{ path: string; mtimeMs: number }>> {
const entries = await fs.readdir(dir, { withFileTypes: true }); const entries = await fs.readdir(dir, { withFileTypes: true });
const results: Array<{ path: string; mtimeMs: number }> = []; const results: Array<{ path: string; mtimeMs: number }> = [];