fix(ci): allow gtimeout for docker pull retry

This commit is contained in:
Vincent Koc
2026-06-20 20:12:30 +02:00
parent 1f1b1aee6b
commit f519ceab9c
3 changed files with 53 additions and 11 deletions
+10 -5
View File
@@ -1,6 +1,10 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="${BASH_SOURCE[0]%/*}"
# shellcheck source=scripts/lib/host-timeout.sh
source "$SCRIPT_DIR/lib/host-timeout.sh"
if [[ "$#" -ne 1 || -z "${1// }" ]]; then
echo "usage: $0 <image>" >&2
exit 2
@@ -28,14 +32,15 @@ fi
last_status=1
run_docker_pull() {
if ! command -v timeout >/dev/null 2>&1; then
echo "timeout command not found; cannot bound Docker pull after ${timeout_seconds}s" >&2
local timeout_bin
if ! timeout_bin="$(openclaw_host_timeout_bin)"; then
echo "timeout or gtimeout command not found; cannot bound Docker pull after ${timeout_seconds}s" >&2
return 127
fi
if timeout --kill-after=1s 1s true >/dev/null 2>&1; then
timeout --kill-after=30s "${timeout_seconds}s" docker pull "$image"
if "$timeout_bin" --kill-after=1s 1s true >/dev/null 2>&1; then
"$timeout_bin" --kill-after=30s "${timeout_seconds}s" docker pull "$image"
else
timeout "${timeout_seconds}s" docker pull "$image"
"$timeout_bin" "${timeout_seconds}s" docker pull "$image"
fi
}
+37 -2
View File
@@ -115,7 +115,42 @@ describe("scripts/ci-docker-pull-retry.sh", () => {
);
});
it("fails fast when timeout is unavailable", () => {
it("uses gtimeout when timeout is unavailable", () => {
const binDir = makeTempBin("openclaw-ci-docker-pull-gtimeout-");
const timeoutArgsPath = path.join(binDir, "gtimeout-args.txt");
const dockerArgsPath = path.join(binDir, "docker-args.txt");
writeExecutable(
path.join(binDir, "gtimeout"),
[
"#!/bin/bash",
"set -euo pipefail",
'if [ "${1:-}" = "--kill-after=1s" ]; then exit 0; fi',
`printf "%s\\n" "gtimeout:$*" >${JSON.stringify(timeoutArgsPath)}`,
'while [ "$#" -gt 0 ] && [ "$1" != "docker" ]; do shift; done',
'exec "$@"',
"",
].join("\n"),
);
writeExecutable(
path.join(binDir, "docker"),
["#!/bin/sh", "set -eu", `printf "%s\\n" "$*" >${JSON.stringify(dockerArgsPath)}`, ""].join(
"\n",
),
);
const result = runPullHelper(binDir);
expect(result.status).toBe(0);
expect(execFileSync("cat", [timeoutArgsPath], { encoding: "utf8" }).trim()).toBe(
"gtimeout:--kill-after=30s 42s docker pull registry.example/openclaw:test",
);
expect(execFileSync("cat", [dockerArgsPath], { encoding: "utf8" }).trim()).toBe(
"pull registry.example/openclaw:test",
);
});
it("fails fast when timeout and gtimeout are unavailable", () => {
const binDir = makeTempBin("openclaw-ci-docker-pull-no-timeout-");
const dockerArgsPath = path.join(binDir, "docker-args.txt");
@@ -130,7 +165,7 @@ describe("scripts/ci-docker-pull-retry.sh", () => {
expect(result.status).toBe(127);
expect(result.stderr).toContain(
"timeout command not found; cannot bound Docker pull after 42s",
"timeout or gtimeout command not found; cannot bound Docker pull after 42s",
);
expect(existsSync(dockerArgsPath)).toBe(false);
});
@@ -676,13 +676,15 @@ describe("package artifact reuse", () => {
expect(pullHelper).toContain(
'retry_delay_seconds="${OPENCLAW_DOCKER_PULL_RETRY_DELAY_SECONDS:-5}"',
);
expect(pullHelper).toContain('source "$SCRIPT_DIR/lib/host-timeout.sh"');
expect(pullHelper).toContain("openclaw_host_timeout_bin");
expect(pullHelper).toContain('"$timeout_bin" --kill-after=1s 1s true');
expect(pullHelper).toContain(
'timeout --kill-after=30s "${timeout_seconds}s" docker pull "$image"',
'"$timeout_bin" --kill-after=30s "${timeout_seconds}s" docker pull "$image"',
);
expect(pullHelper).toContain("timeout --kill-after=1s 1s true >/dev/null 2>&1");
expect(pullHelper).toContain('timeout "${timeout_seconds}s" docker pull "$image"');
expect(pullHelper).toContain('"$timeout_bin" "${timeout_seconds}s" docker pull "$image"');
expect(pullHelper).toContain(
"timeout command not found; cannot bound Docker pull after ${timeout_seconds}s",
"timeout or gtimeout command not found; cannot bound Docker pull after ${timeout_seconds}s",
);
expect(dockerE2ePlanAction.match(/bash scripts\/ci-docker-pull-retry\.sh/g)?.length).toBe(2);
expect(dockerE2ePlanAction).not.toContain('docker pull "${OPENCLAW_DOCKER_E2E_');