Add Dockerfile and entrypoint for devcontainer setup and CI updates #3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Dev Container CI | |
| on: | |
| push: | |
| branches: [main] | |
| paths: | |
| - '.devcontainer/**' | |
| - '!.devcontainer/screen-shot.png' | |
| pull_request: | |
| branches: [main] | |
| paths: | |
| - '.devcontainer/**' | |
| - '!.devcontainer/screen-shot.png' | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_NAME: ${{ github.repository }}/devcontainer | |
| permissions: | |
| contents: read | |
| packages: write | |
| jobs: | |
| # ── Job 1: Build the Docker image ──────────────────────────────────── | |
| build: | |
| name: Build Image | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| outputs: | |
| image_tag: ${{ steps.meta.outputs.tags }} | |
| image_digest: ${{ steps.build.outputs.digest }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to GitHub Container Registry | |
| if: github.event_name == 'push' | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Extract metadata (tags, labels) | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| tags: | | |
| type=sha,prefix= | |
| type=raw,value=latest,enable={{is_default_branch}} | |
| - name: Build and push | |
| id: build | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| file: .devcontainer/Dockerfile | |
| push: ${{ github.event_name == 'push' }} | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| # ── Job 2: Smoke test the built image ─────────────────────────────── | |
| smoke-test: | |
| name: Smoke Test | |
| needs: build | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Build image (from cache) | |
| id: build-local | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| file: .devcontainer/Dockerfile | |
| load: true | |
| tags: hermes-codespace:test | |
| cache-from: type=gha | |
| - name: Verify baked tools exist | |
| run: | | |
| docker run --rm hermes-codespace:test bash -c ' | |
| echo "=== Verifying baked tools ===" | |
| PASS=0; FAIL=0 | |
| check() { if eval "$2"; then echo "✅ $1"; PASS=$((PASS+1)); else echo "❌ $1"; FAIL=$((FAIL+1)); fi; } | |
| check "ollama installed" "command -v ollama" | |
| check "hermes installed" "command -v hermes" | |
| check "omniroute installed" "command -v omniroute" | |
| check "modelrelay installed" "command -v modelrelay" | |
| check "mnemon installed" "command -v mnemon" | |
| check "tailscale installed" "command -v tailscale" | |
| check "cline installed" "command -v cline" | |
| check "zsh installed" "command -v zsh" | |
| check "ripgrep installed" "command -v rg" | |
| check "entrypoint.sh exists" "[ -x /usr/local/bin/entrypoint.sh ]" | |
| echo "" | |
| echo "=== Results: $PASS passed, $FAIL failed ===" | |
| [ "$FAIL" -eq 0 ] && echo "🎉 All tools baked!" || exit 1 | |
| ' | |
| - name: Verify entrypoint.sh syntax | |
| run: | | |
| docker run --rm hermes-codespace:test bash -c ' | |
| echo "=== Checking entrypoint syntax ===" | |
| bash -n /usr/local/bin/entrypoint.sh && echo "✅ entrypoint.sh syntax OK" | |
| ' | |
| - name: Verify config files copied to image | |
| run: | | |
| docker run --rm hermes-codespace:test bash -c ' | |
| echo "=== Checking config files ===" | |
| [ -f /tmp/devcontainer-config/CLAUDE.md ] && echo "✅ CLAUDE.md present" | |
| [ -f /tmp/devcontainer-config/.claude.json ] && echo "✅ .claude.json present" | |
| [ -f /tmp/devcontainer-config/.hermes.md ] && echo "✅ .hermes.md present" | |
| [ -f /tmp/devcontainer-config/skill-memory-automation.md ] && echo "✅ memory-automation skill present" | |
| ' | |
| # ── Job 3: Full integration test (devcontainer CLI) ────────────────── | |
| integration-test: | |
| name: Integration Test | |
| needs: build | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| - name: Install devcontainer CLI | |
| run: npm install -g @devcontainers/cli | |
| - name: Build devcontainer (without starting services) | |
| run: | | |
| docker build -f .devcontainer/Dockerfile -t hermes-codespace:test . | |
| - name: Run self-check inside container | |
| run: | | |
| docker run --rm -d --name test-hc \ | |
| -v "$(pwd):/workspace" \ | |
| hermes-codespace:test sleep 300 | |
| sleep 2 | |
| docker cp .devcontainer/self-check.sh test-hc:/tmp/self-check.sh | |
| docker exec test-hc bash /tmp/self-check.sh || echo "⚠️ Self-check reported issues (non-blocking)" | |
| docker stop test-hc | |
| # ── Job 4: Generate image size report ──────────────────────────────── | |
| image-report: | |
| name: Image Size Report | |
| needs: build | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Build image for size check | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| file: .devcontainer/Dockerfile | |
| load: true | |
| tags: hermes-codespace:test | |
| cache-from: type=gha | |
| - name: Report image size | |
| run: | | |
| echo "=== Devcontainer Image Size ===" | |
| docker images hermes-codespace:test --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}\t{{.CreatedAt}}" | |
| SIZE=$(docker images hermes-codespace:test --format "{{.Size}}") | |
| echo "" | |
| echo "📊 Image size: **$SIZE**" | |
| SIZE_BYTES=$(docker image inspect hermes-codespace:test --format '{{.Size}}') | |
| if [ "$SIZE_BYTES" -gt 4294967296 ]; then | |
| echo "⚠️ WARNING: Image exceeds 4GB — may hit Codespace storage limits" | |
| fi |