diff --git a/config/pikaoa.yaml b/config/pikaoa.yaml index c12d984e..f62bbe45 100644 --- a/config/pikaoa.yaml +++ b/config/pikaoa.yaml @@ -67,6 +67,12 @@ developmentRuntime: api: 127.0.0.1:5000/pikaoa/api worker: 127.0.0.1:5000/pikaoa/worker web: 127.0.0.1:5000/pikaoa/web + cache: + mode: registry + refs: + api: 127.0.0.1:5000/pikaoa/cache-api:development + worker: 127.0.0.1:5000/pikaoa/cache-worker:development + web: 127.0.0.1:5000/pikaoa/cache-web:development networkMode: host gitops: readUrl: http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikainc-pikaoa.git @@ -371,6 +377,12 @@ releaseRuntime: api: 127.0.0.1:5000/pikaoa/api worker: 127.0.0.1:5000/pikaoa/worker web: 127.0.0.1:5000/pikaoa/web + cache: + mode: registry + refs: + api: 127.0.0.1:5000/pikaoa/cache-api:release + worker: 127.0.0.1:5000/pikaoa/cache-worker:release + web: 127.0.0.1:5000/pikaoa/cache-web:release networkMode: host gitops: readUrl: http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikainc-pikaoa.git diff --git a/scripts/src/pikaoa-delivery-renderer.test.ts b/scripts/src/pikaoa-delivery-renderer.test.ts index fc087005..712bac2e 100644 --- a/scripts/src/pikaoa-delivery-renderer.test.ts +++ b/scripts/src/pikaoa-delivery-renderer.test.ts @@ -64,6 +64,11 @@ describe("PikaOA development PaC renderer", () => { expect(serialized).toContain("pikaoa-nc01-pac"); expect(serialized).toContain("refs/unidesk/snapshots/gitea-actions/pikaoa-release-nc01"); expect(serialized).toContain("pac-gitea-pikaoa-nc01"); + for (const component of ["api", "worker", "web"]) { + expect(serialized).toContain(`--import-cache 'type=registry,ref=127.0.0.1:5000/pikaoa/cache-${component}:release'`); + expect(serialized).toContain(`--export-cache 'type=registry,ref=127.0.0.1:5000/pikaoa/cache-${component}:release,mode=max'`); + } + expect(serialized).not.toContain(":development'"); expect(serialized).not.toContain("pikaoa-dev-nc01-pac"); } finally { rmSync(source, { recursive: true, force: true }); @@ -87,6 +92,7 @@ describe("PikaOA development PaC renderer", () => { } for (const name of ["build-api", "build-worker", "build-web"]) { const task = tasks.find((item) => item.name === name); + const component = name.replace("build-", ""); expect(task?.runAfter).toEqual(["source"]); expect(JSON.stringify(task)).toContain("buildctl-daemonless.sh build"); expect(JSON.stringify(task)).toContain("$(params.revision)"); @@ -97,10 +103,14 @@ describe("PikaOA development PaC renderer", () => { expect(buildScript).not.toContain("\u0001"); expect(buildScript).toContain("Docker-Content-Digest:"); expect(buildScript).toContain("build_status=$?"); + expect(buildScript).toContain(`--import-cache 'type=registry,ref=127.0.0.1:5000/pikaoa/cache-${component}:development'`); + expect(buildScript).toContain(`--export-cache 'type=registry,ref=127.0.0.1:5000/pikaoa/cache-${component}:development,mode=max'`); + expect(buildScript).not.toContain(`cache-${component}:$revision`); expect(buildScript).toContain('if [ -f "$metadata" ]'); expect(buildScript).toContain("grep -Eq '^sha256:[0-9a-f]{64}$'"); - expect(buildScript).toContain('"code":"buildctl-nonzero-artifact-verified"'); - expect(buildScript).toContain('"artifactVerified":true'); + expect(buildScript).toContain('"code":"buildctl-failed"'); + expect(buildScript).toContain('exit "$build_status"'); + expect(buildScript).not.toContain('"code":"buildctl-nonzero-artifact-verified"'); } const digest = "sha256:" + "a".repeat(64); const metadata = JSON.stringify({ "containerimage.digest": digest }, null, 2); diff --git a/scripts/src/pikaoa-delivery-renderer.ts b/scripts/src/pikaoa-delivery-renderer.ts index 98ee080b..971935f9 100644 --- a/scripts/src/pikaoa-delivery-renderer.ts +++ b/scripts/src/pikaoa-delivery-renderer.ts @@ -162,6 +162,7 @@ function imageBuildTask(target: PikaoaRuntimeSpec, component: "api" | "worker" | const taskName = `build-${component}`; const imageRepository = target.build.images[component]; const dockerfile = target.build.dockerfiles[component]; + const cacheRef = target.build.cache.refs[component]; return { name: taskName, runAfter: ["source"], @@ -188,9 +189,15 @@ buildctl-daemonless.sh build \\ --opt filename=${shellSingleQuote(dockerfile)} \\ --opt network=${shellSingleQuote(target.build.networkMode)} \\ --output "type=image,name=$tag,push=true" \\ + --import-cache ${shellSingleQuote(`type=${target.build.cache.mode},ref=${cacheRef}`)} \\ + --export-cache ${shellSingleQuote(`type=${target.build.cache.mode},ref=${cacheRef},mode=max`)} \\ --metadata-file "$metadata" build_status=$? set -e +if [ "$build_status" -ne 0 ]; then + printf '{"level":"error","code":"buildctl-failed","component":"${component}","buildctlExitCode":%s,"valuesPrinted":false}\n' "$build_status" >&2 + exit "$build_status" +fi metadata_compact= if [ -f "$metadata" ]; then metadata_compact=$(tr -d '\\n\\r' < "$metadata") @@ -206,9 +213,6 @@ if ! printf '%s' "$digest" | grep -Eq '^sha256:[0-9a-f]{64}$'; then echo 'build digest missing from metadata and registry manifest' >&2 exit 3 fi -if [ "$build_status" -ne 0 ]; then - printf '{"level":"warning","code":"buildctl-nonzero-artifact-verified","component":"${component}","buildctlExitCode":%s,"artifactVerified":true,"valuesPrinted":false}\\n' "$build_status" >&2 -fi printf '%s' "$digest" > "$(results.digest.path)" printf '%s@%s' ${shellSingleQuote(imageRepository)} "$digest" > "$(results.image.path)" printf '{"ok":true,"phase":"${taskName}","sourceCommit":"%s","imageTag":"%s","digest":"%s","valuesPrinted":false}\n' "$revision" "$tag" "$digest" diff --git a/scripts/src/pikaoa-runtime.ts b/scripts/src/pikaoa-runtime.ts index 76cf7994..1588b5fe 100644 --- a/scripts/src/pikaoa-runtime.ts +++ b/scripts/src/pikaoa-runtime.ts @@ -146,6 +146,10 @@ export interface PikaoaRuntimeSpec { build: { dockerfiles: { api: string; worker: string; web: string }; images: { api: string; worker: string; web: string }; + cache: { + mode: "registry"; + refs: { api: string; worker: string; web: string }; + }; networkMode: string; }; gitops: { @@ -278,6 +282,8 @@ function parseRuntime(id: string, root: Record, configLabel: st const build = record(root.build, `${path}.build`); const dockerfiles = record(build.dockerfiles, `${path}.build.dockerfiles`); const buildImages = record(build.images, `${path}.build.images`); + const buildCache = record(build.cache, `${path}.build.cache`); + const buildCacheRefs = record(buildCache.refs, `${path}.build.cache.refs`); const gitops = record(root.gitops, `${path}.gitops`); const gitopsCredential = record(gitops.credential, `${path}.gitops.credential`); const gitopsAuthor = record(gitops.author, `${path}.gitops.author`); @@ -346,6 +352,14 @@ function parseRuntime(id: string, root: Record, configLabel: st worker: imageRepository(buildImages.worker, `${path}.build.images.worker`), web: imageRepository(buildImages.web, `${path}.build.images.web`), }, + cache: { + mode: exact(buildCache.mode, `${path}.build.cache.mode`, "registry"), + refs: { + api: imageReference(buildCacheRefs.api, `${path}.build.cache.refs.api`), + worker: imageReference(buildCacheRefs.worker, `${path}.build.cache.refs.worker`), + web: imageReference(buildCacheRefs.web, `${path}.build.cache.refs.web`), + }, + }, networkMode: exact(build.networkMode, `${path}.build.networkMode`, "host"), }, gitops: {