Merge pull request #1320 from pikasTech/fix/2304-opencode-runtime-image

fix: seed OpenCode runtime image with git
This commit is contained in:
Lyon
2026-06-30 21:14:06 +08:00
committed by GitHub
3 changed files with 90 additions and 15 deletions
+15
View File
@@ -476,6 +476,11 @@ lanes:
builderImage: golang:1.25-bookworm builderImage: golang:1.25-bookworm
goProxy: https://goproxy.cn,direct goProxy: https://goproxy.cn,direct
dockerNetworkMode: host dockerNetworkMode: host
- id: opencode-git
kind: opencode-git
target: 127.0.0.1:5000/hwlab/opencode:1.17.7-git
sourceImage: ghcr.io/anomalyco/opencode:1.17.7
dockerNetworkMode: host
public: public:
webUrl: https://hwlab.pikapython.com webUrl: https://hwlab.pikapython.com
apiUrl: https://hwlab.pikapython.com apiUrl: https://hwlab.pikapython.com
@@ -750,6 +755,11 @@ lanes:
builderImage: golang:1.25-bookworm builderImage: golang:1.25-bookworm
goProxy: https://goproxy.cn,direct goProxy: https://goproxy.cn,direct
dockerNetworkMode: host dockerNetworkMode: host
- id: opencode-git
kind: opencode-git
target: 127.0.0.1:5000/hwlab/opencode:1.17.7-git
sourceImage: ghcr.io/anomalyco/opencode:1.17.7
dockerNetworkMode: host
public: public:
webUrl: https://hwlab.pikapython.com webUrl: https://hwlab.pikapython.com
apiUrl: https://hwlab.pikapython.com apiUrl: https://hwlab.pikapython.com
@@ -1101,6 +1111,11 @@ lanes:
builderImage: golang:1.25-bookworm builderImage: golang:1.25-bookworm
goProxy: https://goproxy.cn,direct goProxy: https://goproxy.cn,direct
dockerNetworkMode: host dockerNetworkMode: host
- id: opencode-git
kind: opencode-git
target: 127.0.0.1:5000/hwlab/opencode:1.17.7-git
sourceImage: ghcr.io/anomalyco/opencode:1.17.7
dockerNetworkMode: host
public: public:
webUrl: https://hwlab.pikapython.com webUrl: https://hwlab.pikapython.com
apiUrl: https://hwlab.pikapython.com apiUrl: https://hwlab.pikapython.com
+16 -6
View File
@@ -313,12 +313,13 @@ export interface HwlabRuntimeImageRewriteSpec {
export interface HwlabRuntimeImageBuildSpec { export interface HwlabRuntimeImageBuildSpec {
readonly id: string; readonly id: string;
readonly kind: "moonbridge"; readonly kind: "moonbridge" | "opencode-git";
readonly target: string; readonly target: string;
readonly sourceRepo: string; readonly sourceImage?: string;
readonly sourceRef: string; readonly sourceRepo?: string;
readonly builderImage: string; readonly sourceRef?: string;
readonly goProxy: string; readonly builderImage?: string;
readonly goProxy?: string;
readonly dockerNetworkMode: "default" | "host"; readonly dockerNetworkMode: "default" | "host";
} }
@@ -1569,7 +1570,16 @@ function runtimeImageBuildsConfig(value: unknown, path: string): HwlabRuntimeIma
const itemPath = `${path}[${index}]`; const itemPath = `${path}[${index}]`;
const raw = asRecord(item, itemPath); const raw = asRecord(item, itemPath);
const kind = stringField(raw, "kind", itemPath); const kind = stringField(raw, "kind", itemPath);
if (kind !== "moonbridge") throw new Error(`${itemPath}.kind must be moonbridge`); if (kind !== "moonbridge" && kind !== "opencode-git") throw new Error(`${itemPath}.kind must be moonbridge or opencode-git`);
if (kind === "opencode-git") {
return {
id: stringField(raw, "id", itemPath),
kind,
target: stringField(raw, "target", itemPath),
sourceImage: stringField(raw, "sourceImage", itemPath),
dockerNetworkMode: enumStringField(raw, "dockerNetworkMode", itemPath, ["default", "host"]),
};
}
return { return {
id: stringField(raw, "id", itemPath), id: stringField(raw, "id", itemPath),
kind, kind,
+59 -9
View File
@@ -847,7 +847,7 @@ interface NodeRuntimeImageDependency {
id: string; id: string;
target: string; target: string;
source: string; source: string;
mode: "pull" | "build-moonbridge"; mode: "pull" | "build-moonbridge" | "build-opencode-git";
sourceRepo?: string; sourceRepo?: string;
sourceRef?: string; sourceRef?: string;
builderImage?: string; builderImage?: string;
@@ -866,15 +866,25 @@ function nodeRuntimeImageDependencies(spec: HwlabRuntimeLaneSpec): NodeRuntimeIm
images.push({ id: `rewrite-${index + 1}`, target: rewrite.target, source: rewrite.source, mode: "pull" }); images.push({ id: `rewrite-${index + 1}`, target: rewrite.target, source: rewrite.source, mode: "pull" });
}); });
spec.runtimeImageBuilds.forEach((build) => { spec.runtimeImageBuilds.forEach((build) => {
if (build.kind === "moonbridge") {
images.push({
id: build.id,
target: build.target,
source: `${build.sourceRepo}#${build.sourceRef}`,
mode: "build-moonbridge",
sourceRepo: build.sourceRepo,
sourceRef: build.sourceRef,
builderImage: build.builderImage,
goProxy: build.goProxy,
dockerNetworkMode: build.dockerNetworkMode,
});
return;
}
images.push({ images.push({
id: build.id, id: build.id,
target: build.target, target: build.target,
source: `${build.sourceRepo}#${build.sourceRef}`, source: build.sourceImage ?? "",
mode: "build-moonbridge", mode: "build-opencode-git",
sourceRepo: build.sourceRepo,
sourceRef: build.sourceRef,
builderImage: build.builderImage,
goProxy: build.goProxy,
dockerNetworkMode: build.dockerNetworkMode, dockerNetworkMode: build.dockerNetworkMode,
}); });
}); });
@@ -1051,7 +1061,7 @@ export function ensureNodeBaseImage(spec: HwlabRuntimeLaneSpec, dryRun: boolean,
" if [ \"$present\" = false ]; then", " if [ \"$present\" = false ]; then",
" action=seed", " action=seed",
" if [ \"$dry_run\" = false ]; then", " if [ \"$dry_run\" = false ]; then",
" if [ \"$mode\" = build-moonbridge ]; then", " if [ \"$mode\" = build-moonbridge ]; then",
" action=build", " action=build",
" source_present_before=build-source", " source_present_before=build-source",
" effective_build_container_http_proxy=\"$build_container_http_proxy\"", " effective_build_container_http_proxy=\"$build_container_http_proxy\"",
@@ -1106,6 +1116,46 @@ export function ensureNodeBaseImage(spec: HwlabRuntimeLaneSpec, dryRun: boolean,
" failed=true", " failed=true",
" fi", " fi",
" rm -rf \"$tmpdir\"", " rm -rf \"$tmpdir\"",
" elif [ \"$mode\" = build-opencode-git ]; then",
" action=build",
" source_present_before=false",
" if [ -n \"$source\" ] && docker image inspect \"$source\" >/dev/null 2>&1; then source_present_before=true; fi",
" effective_build_container_http_proxy=\"$build_container_http_proxy\"",
" effective_build_container_https_proxy=\"$build_container_https_proxy\"",
" effective_build_container_all_proxy=\"$build_container_all_proxy\"",
" effective_docker_build_add_host_args=\"$docker_build_add_host_args\"",
" if [ \"$docker_network_mode\" = host ]; then",
" effective_build_container_http_proxy=\"$build_http_proxy\"",
" effective_build_container_https_proxy=\"$build_https_proxy\"",
" effective_build_container_all_proxy=\"$build_all_proxy\"",
" effective_docker_build_add_host_args=\"\"",
" fi",
" tmpdir=$(mktemp -d /tmp/hwlab-node-runtime-image-$id.XXXXXX)",
" dockerfile=\"$tmpdir/Dockerfile\"",
" cat > \"$dockerfile\" <<'DOCKERFILE'",
"ARG SOURCE_IMAGE",
"FROM ${SOURCE_IMAGE}",
"ARG HTTP_PROXY",
"ARG HTTPS_PROXY",
"ARG ALL_PROXY",
"ARG NO_PROXY",
"ENV HTTP_PROXY=${HTTP_PROXY}",
"ENV HTTPS_PROXY=${HTTPS_PROXY}",
"ENV ALL_PROXY=${ALL_PROXY}",
"ENV NO_PROXY=${NO_PROXY}",
"ENV http_proxy=${HTTP_PROXY}",
"ENV https_proxy=${HTTPS_PROXY}",
"ENV all_proxy=${ALL_PROXY}",
"ENV no_proxy=${NO_PROXY}",
"RUN apk add --no-cache git",
"DOCKERFILE",
" if env HTTP_PROXY=\"$build_http_proxy\" HTTPS_PROXY=\"$build_https_proxy\" ALL_PROXY=\"$build_all_proxy\" NO_PROXY=\"$build_no_proxy\" http_proxy=\"$build_http_proxy\" https_proxy=\"$build_https_proxy\" all_proxy=\"$build_all_proxy\" no_proxy=\"$build_no_proxy\" docker build $effective_docker_build_add_host_args --network \"$docker_network_mode\" --build-arg SOURCE_IMAGE=\"$source\" --build-arg HTTP_PROXY=\"$effective_build_container_http_proxy\" --build-arg HTTPS_PROXY=\"$effective_build_container_https_proxy\" --build-arg ALL_PROXY=\"$effective_build_container_all_proxy\" --build-arg NO_PROXY=\"$build_no_proxy\" --build-arg http_proxy=\"$effective_build_container_http_proxy\" --build-arg https_proxy=\"$effective_build_container_https_proxy\" --build-arg all_proxy=\"$effective_build_container_all_proxy\" --build-arg no_proxy=\"$build_no_proxy\" -t \"$target\" -f \"$dockerfile\" \"$tmpdir\" >/tmp/hwlab-node-runtime-image-$id-build.out 2>&1; then",
" docker push \"$target\" >/tmp/hwlab-node-runtime-image-$id-push.out 2>&1 || { cat /tmp/hwlab-node-runtime-image-$id-push.out >&2 2>/dev/null || true; failed=true; }",
" else",
" cat /tmp/hwlab-node-runtime-image-$id-build.out >&2 2>/dev/null || true",
" failed=true",
" fi",
" rm -rf \"$tmpdir\"",
" else", " else",
" source_present_before=true", " source_present_before=true",
" if ! docker image inspect \"$source\" >/dev/null 2>&1; then", " if ! docker image inspect \"$source\" >/dev/null 2>&1; then",
@@ -1147,7 +1197,7 @@ export function ensureNodeBaseImage(spec: HwlabRuntimeLaneSpec, dryRun: boolean,
nodeRuntimeImageCalls(spec, "ensure_image"), nodeRuntimeImageCalls(spec, "ensure_image"),
"if [ \"$failed\" = true ]; then exit 1; fi", "if [ \"$failed\" = true ]; then exit 1; fi",
].join("\n"); ].join("\n");
const hasBuild = nodeRuntimeImageDependencies(spec).some((image) => image.mode === "build-moonbridge"); const hasBuild = nodeRuntimeImageDependencies(spec).some((image) => image.mode === "build-moonbridge" || image.mode === "build-opencode-git");
const result = hasBuild && !dryRun const result = hasBuild && !dryRun
? runNodeHostScriptAsync(spec, script, Math.min(timeoutSeconds, 600), "runtime-image-build") ? runNodeHostScriptAsync(spec, script, Math.min(timeoutSeconds, 600), "runtime-image-build")
: runNodeHostScript(spec, script, Math.min(timeoutSeconds, 300)); : runNodeHostScript(spec, script, Math.min(timeoutSeconds, 300));