diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 00000000..5b499f8c --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,64 @@ +# Development container for Sourcebot +# Based on Node.js 24 with TypeScript support +FROM mcr.microsoft.com/devcontainers/typescript-node:24 + +ARG GO_VERSION=1.23.4 +ARG CTAGS_VERSION=v6.1.0 + +# Install system dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + # Build tools for universal-ctags + autoconf \ + automake \ + pkg-config \ + make \ + gcc \ + g++ \ + libjansson-dev \ + libyaml-dev \ + libseccomp-dev \ + libxml2-dev \ + # PostgreSQL client tools (for debugging) + postgresql-client \ + # Redis CLI tools (for debugging) + redis-tools \ + # Other utilities + curl \ + git \ + && rm -rf /var/lib/apt/lists/* + +# Install Go (detect architecture automatically) +RUN ARCH=$(dpkg --print-architecture) && \ + if [ "$ARCH" = "arm64" ]; then GOARCH="arm64"; else GOARCH="amd64"; fi && \ + curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${GOARCH}.tar.gz" | tar -C /usr/local -xzf - +ENV PATH="/usr/local/go/bin:${PATH}" +ENV GOPATH="/home/node/go" +ENV PATH="${GOPATH}/bin:${PATH}" + +# Build and install universal-ctags from source +RUN git clone --depth 1 --branch "${CTAGS_VERSION}" https://github.com/universal-ctags/ctags.git /tmp/ctags \ + && cd /tmp/ctags \ + && ./autogen.sh \ + && ./configure \ + && make -j$(nproc) \ + && make install \ + && rm -rf /tmp/ctags + +# Enable corepack for Yarn and disable download prompts +ENV COREPACK_ENABLE_DOWNLOAD_PROMPT=0 +RUN corepack enable + +# Create directories that will be mounted as volumes with correct ownership +# This ensures the node user can write to them when volumes are mounted +RUN mkdir -p /home/node/go /home/node/.yarn/berry/cache \ + && chown -R node:node /home/node/go /home/node/.yarn + +# Set working directory +WORKDIR /workspaces/sourcebot + +# Switch to non-root user +USER node + +# Install Claude CLI (native binary) +RUN curl -fsSL https://claude.ai/install.sh | bash +ENV PATH="/home/node/.claude/bin:${PATH}" diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..604496ff --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,50 @@ +{ + "name": "Sourcebot Development", + "dockerComposeFile": "docker-compose.yml", + "service": "devcontainer", + "workspaceFolder": "/workspaces/sourcebot", + + "features": { + "ghcr.io/devcontainers/features/git:1": {}, + "ghcr.io/devcontainers/features/github-cli:1": {} + }, + + "forwardPorts": [3000], + "portsAttributes": { + "3000": { "label": "Web App", "onAutoForward": "notify" } + }, + + "initializeCommand": "git submodule update --init --recursive", + "postCreateCommand": "bash .devcontainer/scripts/post-create.sh", + "postStartCommand": "bash .devcontainer/scripts/post-start.sh", + + "customizations": { + "vscode": { + "extensions": [ + "dbaeumer.vscode-eslint", + "bradlc.vscode-tailwindcss", + "Prisma.prisma", + "esbenp.prettier-vscode", + "golang.go", + "ms-azuretools.vscode-docker", + "mikestead.dotenv", + "eamodio.gitlens" + ], + "settings": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[typescriptreact]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[prisma]": { + "editor.defaultFormatter": "Prisma.prisma" + } + } + } + }, + + "remoteUser": "node" +} diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml new file mode 100644 index 00000000..96a9e7ff --- /dev/null +++ b/.devcontainer/docker-compose.yml @@ -0,0 +1,54 @@ +version: '3.8' + +services: + devcontainer: + build: + context: . + dockerfile: Dockerfile + volumes: + - ..:/workspaces/sourcebot:cached + - go-modules:/home/node/go + - yarn-cache:/home/node/.yarn/berry/cache + command: sleep infinity + ports: + - "3000:3000" + environment: + DATABASE_URL: postgresql://postgres:postgres@postgres:5432/postgres + REDIS_URL: redis://redis:6379 + ZOEKT_WEBSERVER_URL: http://localhost:6070 + CTAGS_COMMAND: ctags + AUTH_SECRET: "00000000000000000000000000000000000000000000" + AUTH_URL: http://localhost:3000 + DATA_CACHE_DIR: /workspaces/sourcebot/.sourcebot + SOURCEBOT_ENCRYPTION_KEY: "00000000000000000000000000000000" + NODE_ENV: development + SOURCEBOT_LOG_LEVEL: debug + SOURCEBOT_TELEMETRY_DISABLED: "true" + REVIEW_AGENT_LOGGING_ENABLED: "true" + REVIEW_AGENT_AUTO_REVIEW_ENABLED: "false" + REVIEW_AGENT_REVIEW_COMMAND: review + depends_on: + - postgres + - redis + + postgres: + image: postgres:16-alpine + volumes: + - postgres-data:/var/lib/postgresql/data + environment: + POSTGRES_DB: postgres + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + restart: unless-stopped + + redis: + image: redis:7-alpine + volumes: + - redis-data:/data + restart: unless-stopped + +volumes: + go-modules: + yarn-cache: + postgres-data: + redis-data: diff --git a/.devcontainer/scripts/post-create.sh b/.devcontainer/scripts/post-create.sh new file mode 100755 index 00000000..26b9a710 --- /dev/null +++ b/.devcontainer/scripts/post-create.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# post-create.sh - One-time setup after container creation +set -e + +echo "==========================================" +echo "Sourcebot Dev Container: Post-Create Setup" +echo "==========================================" + +cd /workspaces/sourcebot + +# 1. Initialize git submodules (in case initializeCommand didn't run) +echo "" +echo "[1/2] Initializing git submodules..." +git submodule update --init --recursive + +# 2. Build Zoekt and install dependencies (uses Makefile) +echo "" +echo "[2/2] Building Zoekt and installing dependencies..." +make + +echo "" +echo "==========================================" +echo "Post-create setup complete!" +echo "" +echo "To start the development server, run:" +echo " yarn dev" +echo "" +echo "Services will be available at:" +echo " - Web App: http://localhost:3000" +echo " - Zoekt: http://localhost:6070" +echo "==========================================" diff --git a/.devcontainer/scripts/post-start.sh b/.devcontainer/scripts/post-start.sh new file mode 100755 index 00000000..356b81b8 --- /dev/null +++ b/.devcontainer/scripts/post-start.sh @@ -0,0 +1,48 @@ +#!/bin/bash +# post-start.sh - Runs each time the container starts +set -e + +echo "==========================================" +echo "Sourcebot Dev Container: Post-Start Check" +echo "==========================================" + +cd /workspaces/sourcebot + +# 1. Wait for PostgreSQL to be ready +echo "" +echo "[1/2] Checking PostgreSQL connection..." +timeout=30 +counter=0 +until pg_isready -h postgres -p 5432 -U postgres > /dev/null 2>&1; do + counter=$((counter + 1)) + if [ $counter -ge $timeout ]; then + echo "ERROR: PostgreSQL did not become ready within ${timeout} seconds" + exit 1 + fi + echo " Waiting for PostgreSQL... ($counter/$timeout)" + sleep 1 +done +echo "PostgreSQL is ready!" + +# 2. Wait for Redis to be ready +echo "" +echo "[2/2] Checking Redis connection..." +counter=0 +until redis-cli -h redis -p 6379 ping > /dev/null 2>&1; do + counter=$((counter + 1)) + if [ $counter -ge $timeout ]; then + echo "ERROR: Redis did not become ready within ${timeout} seconds" + exit 1 + fi + echo " Waiting for Redis... ($counter/$timeout)" + sleep 1 +done +echo "Redis is ready!" + +echo "" +echo "==========================================" +echo "Dev container is ready!" +echo "" +echo "To start development, run:" +echo " yarn dev" +echo "=========================================="