From d30fce4dc42154e082e896c324dc70d6db8f3bd7 Mon Sep 17 00:00:00 2001 From: Guarzo Date: Sat, 8 Aug 2026 17:05:42 -0400 Subject: [PATCH] review: make the devcontainer work on a clean checkout Track an empty no-op docker-compose.override.yml (with a .gitignore negation) so devcontainer.json's compose file list resolves without the initializeCommand hack, which is removed. Add USER_UID/USER_GID build args and drop the sudo chown from setup.sh. Correct the Elixir pin comment: the OTP suffix pins only the major, so the Erlang patch may still differ from .tool-versions. --- .devcontainer/Dockerfile | 7 ++++- .devcontainer/devcontainer.json | 1 - .devcontainer/docker-compose.override.yml | 10 +++++++ .../docker-compose.override.yml.example | 29 ++++++++++++++----- .devcontainer/docker-compose.yml | 7 +++++ .devcontainer/setup.sh | 6 ---- .gitignore | 6 +++- README.md | 20 ++++++++----- 8 files changed, 63 insertions(+), 23 deletions(-) create mode 100644 .devcontainer/docker-compose.override.yml diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index b3b888b4..94d3ef20 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,9 @@ -FROM elixir:1.17-otp-26 +# Pins Elixir to the .tool-versions value (1.17.3) instead of the floating +# 1.17 tag, which could drift to a different Elixir patch. This matters because +# _build is shared with the host via the /app bind. Note the OTP suffix pins +# only the major (26); the Erlang patch may still differ from .tool-versions' +# 26.2.5.5, since the official images publish no patch-level tag. +FROM elixir:1.17.3-otp-26 ARG USERNAME=developer ARG USER_UID=1000 diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index fee38a00..a79560b7 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -10,7 +10,6 @@ "remoteUser": "developer", "containerUser": "developer", - "initializeCommand": "test -f .devcontainer/docker-compose.override.yml || echo 'services: {}' > .devcontainer/docker-compose.override.yml", "postCreateCommand": "bash .devcontainer/setup.sh", "postStartCommand": "bash .devcontainer/post-start.sh", diff --git a/.devcontainer/docker-compose.override.yml b/.devcontainer/docker-compose.override.yml new file mode 100644 index 00000000..9fb86a31 --- /dev/null +++ b/.devcontainer/docker-compose.override.yml @@ -0,0 +1,10 @@ +# Host-specific devcontainer overrides. +# +# This file is intentionally empty and is tracked so that +# `docker compose -f docker-compose.yml -f docker-compose.override.yml ...` +# — the invocation devcontainer.json uses — works on a clean checkout. +# +# Edit it locally for host-specific settings (SSH keys, gh auth, a non-1000 +# uid, alternate Postgres port). See docker-compose.override.yml.example for +# ready-to-uncomment snippets. Local edits here are not meant to be committed. +services: {} diff --git a/.devcontainer/docker-compose.override.yml.example b/.devcontainer/docker-compose.override.yml.example index a752570a..26e17037 100644 --- a/.devcontainer/docker-compose.override.yml.example +++ b/.devcontainer/docker-compose.override.yml.example @@ -1,13 +1,26 @@ # docker-compose.override.yml.example # -# Copy this file to docker-compose.override.yml for host-specific settings. -# The override file is gitignored and will be auto-created (empty) by -# devcontainer.json's initializeCommand if missing, so the devcontainer works -# without it. +# Copy this file over docker-compose.override.yml for host-specific settings. +# docker-compose.override.yml is tracked and empty by default (`services: {}`), +# so the devcontainer works without any of this. # # Uncomment what you need. services: wanderer: + # The container user is created with USER_UID/USER_GID (default 1000) so + # that deps/, _build/ and generated assets written through the /app bind + # mount stay owned by you on the host. If `id -u` on your host is not 1000, + # either export USER_UID/USER_GID before starting the devcontainer: + # + # export USER_UID="$(id -u)" USER_GID="$(id -g)" + # + # or pin them here and rebuild the container. + # + # build: + # args: + # USER_UID: "1001" + # USER_GID: "1001" + # volumes: # # Host SSH keys (Git over SSH, commit signing) # - ~/.ssh:/home/developer/.ssh:ro @@ -15,8 +28,10 @@ services: # # GitHub CLI auth # - ~/.config/gh:/home/developer/.config/gh:ro - # Publish Postgres on a different host port if 5432 is already taken. - # (Set on the db service instead — shown here for reference.) - # # environment: # SOME_LOCAL_OVERRIDE: "value" + + # db: + # # Publish Postgres on a different host port if 5432 is already taken. + # ports: + # - "5433:5432" diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index c1dadeaa..f8672090 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -21,6 +21,13 @@ services: build: context: . dockerfile: Dockerfile + args: + # The container user is created with these ids so that files written + # through the /app bind mount (deps/, _build/, generated assets) keep + # host ownership. Hosts whose uid is not 1000 export USER_UID/USER_GID + # (see docker-compose.override.yml.example) before building. + USER_UID: ${USER_UID:-1000} + USER_GID: ${USER_GID:-1000} environment: PORT: 4444 DB_HOST: db diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh index b3a6da0d..82aa3acb 100755 --- a/.devcontainer/setup.sh +++ b/.devcontainer/setup.sh @@ -1,12 +1,6 @@ #!/usr/bin/env bash set -e -echo "→ ensuring build dirs are writable" -# deps/ and _build/ come from the /app bind mount (see docker-compose.yml), so -# they carry host ownership. When the host uid differs from the container user's, -# mix cannot write to them. Best-effort fix; harmless when uids already match. -sudo chown -R "$(id -u):$(id -g)" /app/deps /app/_build 2>/dev/null || true - echo "→ fetching & compiling deps" mix deps.get mix compile diff --git a/.gitignore b/.gitignore index 17464ad2..ed554c43 100644 --- a/.gitignore +++ b/.gitignore @@ -52,7 +52,11 @@ erl_crash.dump .elixir_ls/ # Devcontainer host-specific files -/.devcontainer/docker-compose.override.yml +# .devcontainer/docker-compose.override.yml is deliberately tracked as an empty +# no-op so devcontainer.json's compose file list resolves on a clean checkout. +# The negation is explicit because a common global/user gitignore rule matches +# docker-compose.override.yml anywhere. Keep local edits to it out of commits. +!/.devcontainer/docker-compose.override.yml # Editor directories and files .vscode/* diff --git a/README.md b/README.md index e51cfd14..61eced5e 100644 --- a/README.md +++ b/README.md @@ -53,13 +53,19 @@ Now you can visit [`localhost:8000`](http://localhost:8000) from your browser. #### Using .devcontainer -- Run devcontainer -- Install additional dependencies inside Dev container -- `root@0d0a785313b6:/app# apt update` -- `root@0d0a785313b6:/app# curl -sL https://deb.nodesource.com/setup_18.x | bash -` -- `root@0d0a785313b6:/app# apt-get install nodejs inotify-tools -y` -- `root@0d0a785313b6:/app# npm install -g yarn` -- `root@0d0a785313b6:/app# mix setup` +- Copy `.env.example` to `.env` and fill in the values +- Open the repository in the dev container ("Reopen in Container") + +The image ships Erlang/Elixir pinned to `.tool-versions`, Node.js 18, yarn and +the usual CLI tooling, and runs as the non-root `developer` user. On first +create, `.devcontainer/setup.sh` fetches and compiles deps, creates and migrates +the database, seeds the EVE SDE reference data if it is missing, and installs +and builds the client assets — so there is nothing to install by hand. + +- If your host user id is not `1000`, export `USER_UID`/`USER_GID` before + building so files written through the bind mount stay host-owned. See + `.devcontainer/docker-compose.override.yml.example` for this and other + host-specific settings. - See how to run server in #Run section