Skip to content

Commit 4ca6a9f

Browse files
committed
fix(docker-git): make apt mirror optional and cover browser startup
- keep Ubuntu apt mirrors default unless UBUNTU_APT_MIRROR is set - add CI e2e coverage for bun run docker-git -- browser startup
1 parent e43449d commit 4ca6a9f

10 files changed

Lines changed: 199 additions & 13 deletions

File tree

.github/workflows/check.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,19 @@ jobs:
149149
- name: Pack and run local package via Bun
150150
run: bash scripts/e2e/local-package-cli.sh
151151

152+
e2e-browser-command:
153+
name: E2E (Browser command)
154+
runs-on: ubuntu-latest
155+
timeout-minutes: 40
156+
steps:
157+
- uses: actions/checkout@v6
158+
- name: Install dependencies
159+
uses: ./.github/actions/setup
160+
- name: Docker info
161+
run: docker version && docker compose version
162+
- name: Browser command startup
163+
run: bash scripts/e2e/browser-command.sh
164+
152165
e2e-opencode:
153166
name: E2E (OpenCode)
154167
runs-on: ubuntu-latest

docker-compose.api.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ services:
33
build:
44
context: .
55
dockerfile: packages/api/Dockerfile
6+
args:
7+
UBUNTU_APT_MIRROR: ${UBUNTU_APT_MIRROR:-}
68
container_name: ${DOCKER_GIT_API_CONTAINER_NAME:-docker-git-api}
79
environment:
810
DOCKER_GIT_API_PORT: ${DOCKER_GIT_API_PORT:-3334}

docker-compose.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ services:
55
dockerfile: packages/api/Dockerfile
66
args:
77
DOCKER_GIT_CONTROLLER_REV: ${DOCKER_GIT_CONTROLLER_REV:-unknown}
8+
UBUNTU_APT_MIRROR: ${UBUNTU_APT_MIRROR:-}
89
container_name: ${DOCKER_GIT_API_CONTAINER_NAME:-docker-git-api}
910
environment:
1011
DOCKER_GIT_API_PORT: ${DOCKER_GIT_API_PORT:-3334}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"docker-git": "bash -lc 'bun run --cwd packages/app build:docker-git && bun ./packages/app/dist/src/docker-git/main.js \"$@\"' --",
2929
"e2e": "bash scripts/e2e/run-all.sh",
3030
"e2e:clone-cache": "bash scripts/e2e/clone-cache.sh",
31+
"e2e:browser-command": "bash scripts/e2e/browser-command.sh",
3132
"e2e:login-context": "bash scripts/e2e/login-context.sh",
3233
"e2e:runtime-volumes-ssh": "bash scripts/e2e/runtime-volumes-ssh.sh",
3334
"e2e:opencode-autoconnect": "bash scripts/e2e/opencode-autoconnect.sh",

packages/api/Dockerfile

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
FROM ubuntu:24.04
22

33
ARG DOCKER_GIT_CONTROLLER_REV=unknown
4+
ARG UBUNTU_APT_MIRROR=
45
LABEL io.prover-coder-ai.docker-git.controller-rev=$DOCKER_GIT_CONTROLLER_REV
56

67
ENV DEBIAN_FRONTEND=noninteractive
@@ -10,10 +11,12 @@ ENV PATH=/opt/bun/bin:$PATH
1011
WORKDIR /workspace
1112

1213
RUN set -eu; \
13-
sed -i \
14-
-e 's|http://archive.ubuntu.com/ubuntu|http://azure.archive.ubuntu.com/ubuntu|g' \
15-
-e 's|http://security.ubuntu.com/ubuntu|http://azure.archive.ubuntu.com/ubuntu|g' \
16-
/etc/apt/sources.list /etc/apt/sources.list.d/ubuntu.sources 2>/dev/null || true; \
14+
if [ -n "${UBUNTU_APT_MIRROR:-}" ]; then \
15+
sed -i \
16+
-e "s|http://archive.ubuntu.com/ubuntu|${UBUNTU_APT_MIRROR}|g" \
17+
-e "s|http://security.ubuntu.com/ubuntu|${UBUNTU_APT_MIRROR}|g" \
18+
/etc/apt/sources.list /etc/apt/sources.list.d/ubuntu.sources 2>/dev/null || true; \
19+
fi; \
1720
for attempt in 1 2 3; do \
1821
rm -rf /var/lib/apt/lists/*; \
1922
if apt-get -o Acquire::Retries=3 -o Acquire::By-Hash=force update; then \

packages/app/src/lib/core/templates/dockerfile.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,17 @@ import { renderDockerfilePrompt } from "../templates-prompt.js"
55
const renderDockerfilePrelude = (): string =>
66
`FROM ubuntu:24.04
77
8+
ARG UBUNTU_APT_MIRROR=
89
ENV DEBIAN_FRONTEND=noninteractive
910
ENV NVM_DIR=/usr/local/nvm
1011
1112
RUN set -eu; \
12-
sed -i \
13-
-e 's|http://archive.ubuntu.com/ubuntu|http://azure.archive.ubuntu.com/ubuntu|g' \
14-
-e 's|http://security.ubuntu.com/ubuntu|http://azure.archive.ubuntu.com/ubuntu|g' \
15-
/etc/apt/sources.list /etc/apt/sources.list.d/ubuntu.sources 2>/dev/null || true; \
13+
if [ -n "\${UBUNTU_APT_MIRROR:-}" ]; then \
14+
sed -i \
15+
-e "s|http://archive.ubuntu.com/ubuntu|\${UBUNTU_APT_MIRROR}|g" \
16+
-e "s|http://security.ubuntu.com/ubuntu|\${UBUNTU_APT_MIRROR}|g" \
17+
/etc/apt/sources.list /etc/apt/sources.list.d/ubuntu.sources 2>/dev/null || true; \
18+
fi; \
1619
for attempt in 1 2 3 4 5; do \
1720
rm -rf /var/lib/apt/lists/*; \
1821
if apt-get -o Acquire::Retries=3 -o Acquire::By-Hash=force update; then \

packages/lib/src/core/templates/dockerfile.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,17 @@ import { renderDockerfilePrompt } from "../templates-prompt.js"
44
const renderDockerfilePrelude = (): string =>
55
`FROM ubuntu:24.04
66
7+
ARG UBUNTU_APT_MIRROR=
78
ENV DEBIAN_FRONTEND=noninteractive
89
ENV NVM_DIR=/usr/local/nvm
910
1011
RUN set -eu; \
11-
sed -i \
12-
-e 's|http://archive.ubuntu.com/ubuntu|http://azure.archive.ubuntu.com/ubuntu|g' \
13-
-e 's|http://security.ubuntu.com/ubuntu|http://azure.archive.ubuntu.com/ubuntu|g' \
14-
/etc/apt/sources.list /etc/apt/sources.list.d/ubuntu.sources 2>/dev/null || true; \
12+
if [ -n "\${UBUNTU_APT_MIRROR:-}" ]; then \
13+
sed -i \
14+
-e "s|http://archive.ubuntu.com/ubuntu|\${UBUNTU_APT_MIRROR}|g" \
15+
-e "s|http://security.ubuntu.com/ubuntu|\${UBUNTU_APT_MIRROR}|g" \
16+
/etc/apt/sources.list /etc/apt/sources.list.d/ubuntu.sources 2>/dev/null || true; \
17+
fi; \
1518
for attempt in 1 2 3 4 5; do \
1619
rm -rf /var/lib/apt/lists/*; \
1720
if apt-get -o Acquire::Retries=3 -o Acquire::By-Hash=force update; then \

packages/lib/tests/usecases/prepare-files.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,8 @@ describe("prepareProjectFiles", () => {
188188
expect(entrypointSyntaxExitCode).toBe(0)
189189
expect(dockerfile).toContain("docker-compose-v2")
190190
expect(dockerfile).toContain("gitleaks version")
191+
expect(dockerfile).toContain("ARG UBUNTU_APT_MIRROR=")
192+
expect(dockerfile).toContain('if [ -n "${UBUNTU_APT_MIRROR:-}" ]; then')
191193
expect(dockerfile).toContain(
192194
"curl -fsSL --retry 5 --retry-all-errors --retry-delay 2 https://bun.sh/install -o /tmp/bun-install.sh"
193195
)

scripts/e2e/browser-command.sh

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
RUN_ID="$(date +%s)-$RANDOM"
5+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6+
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
7+
source "$REPO_ROOT/scripts/e2e/_lib.sh"
8+
ROOT_BASE="${DOCKER_GIT_E2E_ROOT_BASE:-/tmp/docker-git-e2e-root}"
9+
mkdir -p "$ROOT_BASE"
10+
ROOT="$(mktemp -d "$ROOT_BASE/browser-command.XXXXXX")"
11+
chmod 0755 "$ROOT"
12+
KEEP="${KEEP:-0}"
13+
14+
E2E_BIN="$ROOT/.e2e-bin"
15+
BROWSER_LOG="$ROOT/browser-command.log"
16+
STATE_PATH="$ROOT/.orch/state/browser-frontend.json"
17+
FAILURE_DUMPED=0
18+
BROWSER_PID=""
19+
20+
export DOCKER_GIT_PROJECTS_ROOT="$ROOT"
21+
export DOCKER_GIT_PROJECTS_ROOT_VOLUME="docker-git-e2e-browser-$RUN_ID-projects"
22+
export DOCKER_GIT_API_CONTAINER_NAME="docker-git-e2e-browser-$RUN_ID-api"
23+
export DOCKER_GIT_API_PORT="$(( (RANDOM % 1000) + 34000 ))"
24+
export DOCKER_GIT_WEB_PORT="$(( (RANDOM % 1000) + 41000 ))"
25+
export COMPOSE_PROJECT_NAME="docker-git-e2e-browser-$RUN_ID"
26+
export DOCKER_GIT_STATE_AUTO_SYNC=0
27+
28+
fail() {
29+
echo "e2e/browser-command: $*" >&2
30+
if [[ "$FAILURE_DUMPED" == "0" ]]; then
31+
on_error "fail"
32+
fi
33+
exit 1
34+
}
35+
36+
browser_alive() {
37+
[[ -n "$BROWSER_PID" ]] && kill -0 "$BROWSER_PID" 2>/dev/null
38+
}
39+
40+
stop_browser_command() {
41+
if ! browser_alive; then
42+
return 0
43+
fi
44+
45+
kill -TERM -- "-$BROWSER_PID" 2>/dev/null || kill -TERM "$BROWSER_PID" 2>/dev/null || true
46+
for _ in $(seq 1 15); do
47+
if ! browser_alive; then
48+
break
49+
fi
50+
sleep 1
51+
done
52+
if browser_alive; then
53+
kill -KILL -- "-$BROWSER_PID" 2>/dev/null || kill -KILL "$BROWSER_PID" 2>/dev/null || true
54+
fi
55+
wait "$BROWSER_PID" 2>/dev/null || true
56+
}
57+
58+
on_error() {
59+
local line="$1"
60+
if [[ "$FAILURE_DUMPED" == "1" ]]; then
61+
return
62+
fi
63+
FAILURE_DUMPED=1
64+
echo "e2e/browser-command: failed at line $line" >&2
65+
if [[ -f "$BROWSER_LOG" ]]; then
66+
echo "--- browser command log ---" >&2
67+
cat "$BROWSER_LOG" >&2 || true
68+
fi
69+
if [[ -f "$STATE_PATH" ]]; then
70+
echo "--- browser runtime state ---" >&2
71+
cat "$STATE_PATH" >&2 || true
72+
fi
73+
docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}' | head -n 80 || true
74+
if docker ps -a --format '{{.Names}}' | grep -qx "$DOCKER_GIT_API_CONTAINER_NAME" 2>/dev/null; then
75+
docker logs "$DOCKER_GIT_API_CONTAINER_NAME" --tail 200 || true
76+
fi
77+
(cd "$REPO_ROOT" && docker compose ps) || true
78+
(cd "$REPO_ROOT" && docker compose logs --no-color --tail 200) || true
79+
}
80+
81+
cleanup() {
82+
stop_browser_command
83+
(cd "$REPO_ROOT" && docker compose down -v --remove-orphans) >/dev/null 2>&1 || true
84+
if [[ "$KEEP" == "1" ]]; then
85+
echo "e2e/browser-command: KEEP=1 set; preserving temp dir: $ROOT" >&2
86+
echo "e2e/browser-command: controller container: $DOCKER_GIT_API_CONTAINER_NAME" >&2
87+
return
88+
fi
89+
rm -rf "$ROOT" >/dev/null 2>&1 || true
90+
}
91+
92+
wait_for_log_line() {
93+
local needle="$1"
94+
local attempts="${2:-90}"
95+
96+
for _ in $(seq 1 "$attempts"); do
97+
if [[ -f "$BROWSER_LOG" ]] && grep -Fq -- "$needle" "$BROWSER_LOG"; then
98+
return 0
99+
fi
100+
if ! browser_alive; then
101+
fail "browser command exited before log line appeared: $needle"
102+
fi
103+
sleep 2
104+
done
105+
106+
fail "timed out waiting for log line: $needle"
107+
}
108+
109+
wait_for_http_contains() {
110+
local url="$1"
111+
local needle="$2"
112+
local attempts="${3:-90}"
113+
local body=""
114+
115+
for _ in $(seq 1 "$attempts"); do
116+
if body="$(curl -fsS "$url" 2>/dev/null)" && grep -Fq -- "$needle" <<<"$body"; then
117+
return 0
118+
fi
119+
if ! browser_alive; then
120+
fail "browser command exited before endpoint became ready: $url"
121+
fi
122+
sleep 2
123+
done
124+
125+
fail "timed out waiting for endpoint: $url"
126+
}
127+
128+
trap 'on_error $LINENO' ERR
129+
trap cleanup EXIT
130+
131+
command -v curl >/dev/null 2>&1 || fail "missing 'curl' command"
132+
command -v setsid >/dev/null 2>&1 || fail "missing 'setsid' command"
133+
134+
mkdir -p "$E2E_BIN"
135+
dg_ensure_docker "$E2E_BIN"
136+
dg_prepare_docker_git_cli "$REPO_ROOT" "$E2E_BIN"
137+
138+
cd "$REPO_ROOT"
139+
setsid bash -lc 'bun run docker-git -- browser' >"$BROWSER_LOG" 2>&1 &
140+
BROWSER_PID="$!"
141+
142+
wait_for_log_line "Ensuring docker-git API controller is current."
143+
wait_for_http_contains "http://127.0.0.1:${DOCKER_GIT_API_PORT}/health" '"ok":true'
144+
wait_for_http_contains "http://127.0.0.1:${DOCKER_GIT_WEB_PORT}/" "<title>docker-git browser</title>"
145+
wait_for_http_contains "http://127.0.0.1:${DOCKER_GIT_WEB_PORT}/api/health" '"ok":true'
146+
wait_for_log_line "docker-git web runtime listening on http://"
147+
148+
browser_alive || fail "browser command exited after startup checks"
149+
docker ps --format '{{.Names}}' | grep -qx "$DOCKER_GIT_API_CONTAINER_NAME" \
150+
|| fail "expected controller container to be running: $DOCKER_GIT_API_CONTAINER_NAME"
151+
[[ -f "$STATE_PATH" ]] || fail "expected browser runtime state file: $STATE_PATH"
152+
153+
grep -Fq -- "\"port\": \"$DOCKER_GIT_WEB_PORT\"" "$STATE_PATH" \
154+
|| fail "expected runtime state to record web port $DOCKER_GIT_WEB_PORT"
155+
grep -Fq -- "\"apiBaseUrl\": \"http://127.0.0.1:$DOCKER_GIT_API_PORT\"" "$STATE_PATH" \
156+
|| fail "expected runtime state to record API base URL http://127.0.0.1:$DOCKER_GIT_API_PORT"
157+
158+
echo "e2e/browser-command: bun run docker-git -- browser startup verified" >&2

scripts/e2e/run-all.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
55

66
cases=("$@")
77
if [[ "${#cases[@]}" -eq 0 ]]; then
8-
cases=("local-package-cli" "clone-cache" "login-context" "runtime-volumes-ssh" "clone-auto-open-ssh" "opencode-autoconnect")
8+
cases=("local-package-cli" "browser-command" "clone-cache" "login-context" "runtime-volumes-ssh" "clone-auto-open-ssh" "opencode-autoconnect")
99
fi
1010

1111
for case_name in "${cases[@]}"; do

0 commit comments

Comments
 (0)