From e41c2bf0515fa3a0c8337a5715bd336ebb300f7e Mon Sep 17 00:00:00 2001 From: S Smith Date: Fri, 5 Jun 2026 04:22:21 +0000 Subject: [PATCH] [minor] change mounting volume behavior, pin newer default devcontainer versions --- Makefile | 8 ++- README.md | 2 + group_vars/all.example.yml | 29 +++++++--- .../devcontainer_sync/templates/install.sh.j2 | 10 ++++ tests/golden_output | 58 ++++++++++++++----- .../.devcontainer/devcontainer.json | 10 ++-- tests/java-example/.devcontainer/install.sh | 10 ++++ .../.devcontainer/devcontainer.json | 8 +-- tests/python-example/.devcontainer/install.sh | 10 ++++ .../.devcontainer/devcontainer.json | 10 ++-- tests/rust-example/.devcontainer/install.sh | 10 ++++ 11 files changed, 129 insertions(+), 36 deletions(-) diff --git a/Makefile b/Makefile index ce0a369..05b0b20 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ ifdef WORKSPACE_ROOT ANSIBLE_ENV := WORKSPACE_ROOT=$(WORKSPACE_ROOT) endif -.PHONY: help check apply create-missing syntax test +.PHONY: help check apply create-missing syntax test rm-bak help: @printf "Targets:\n" @@ -16,6 +16,7 @@ help: @printf " make apply Apply rendered devcontainer files\n" @printf " make create-missing Create missing .devcontainer directories/files\n" @printf " make syntax Run Ansible syntax check\n" + @printf " make rm-bak Find all .devcontainer-bak-* subdirectories and rm -rf them\n" @printf " make test Render group_vars/all.example.yml into tests/\n" @printf "\nOverride workspace root with WORKSPACE_ROOT=/path/to/workspaces.\n" @@ -31,6 +32,11 @@ create-missing: syntax: $(ANSIBLE_ENV) $(ANSIBLE_PLAYBOOK) --syntax-check $(PLAYBOOK) +rm-bak: +ifndef WORKSPACE_ROOT + $(error WORKSPACE_ROOT is not defined) +endif + find ${WORKSPACE_ROOT} -type d -name ".devcontainer-bak-*" -exec rm -rf {} + test: $(ANSIBLE_PLAYBOOK) --diff $(PLAYBOOK) -e @$(EXAMPLE_VARS) -e workspace_root=$(TEST_WORKSPACE_ROOT) -e devcontainer_sync_create_missing=true -e devcontainer_sync_backup=false -e devcontainer_sync_backup_existing_dir=false diff --git a/README.md b/README.md index 523b369..01847c0 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,8 @@ or: `ansible-playbook --check --diff playbook.yml` - Scalar/string/bool keys are replaced by the per-container value, if it exists. This includes `image`, `post_start_command`, `install`, `name`... + - _Except!_ The `install` script templates into `roles/devcontainer_sync/templates/install.sh.j2`. As an example (and because it's _my_ preferred default), this template installs common AI tools into every devcontainer. So, if you were wondering why building the devcontainer gave you a copy of Claude and Codex, that's why. You can change the template to suit your preferences. + ### 3. When the diff looks right, apply it with: ```bash diff --git a/group_vars/all.example.yml b/group_vars/all.example.yml index b5fae35..1cbb30a 100644 --- a/group_vars/all.example.yml +++ b/group_vars/all.example.yml @@ -6,9 +6,24 @@ workspace_root: "{{ lookup('env', 'WORKSPACE_ROOT') | default('~/dev/', true) }} devcontainer_sync_create_missing: false devcontainer_defaults: - image: mcr.microsoft.com/devcontainers/base:jammy + image: mcr.microsoft.com/devcontainers/base:resolute post_start_command: sudo chown -R vscode:vscode /home/vscode/.claude* - post_create_command: bash .devcontainer/install.sh + # chowns and symlinks mounted directories + # runs devcontainer install + post_create_command: >- + sudo chown $USER:$USER ${containerWorkspaceFolder}/.claude && + + sudo chown $USER:$USER /opt/claude-code-config && + mkdir -p /opt/claude-code-config/.claude && + touch /opt/claude-code-config/.claude.json && + + ln -s /opt/claude-code-config/.claude.json $HOME/.claude.json && + ln -s /opt/claude-code-config/.claude $HOME/.claude && + + sudo chown $USER:$USER /opt/.codex && + ln -s /opt/.codex $HOME/.codex && + + bash .devcontainer/install.sh post_attach_command: "" install: "" # note: the following keys get merged. see README. @@ -17,14 +32,14 @@ devcontainer_defaults: - Anthropic.claude-code - openai.chatgpt mounts: - - source=claude_config_${localWorkspaceFolderBasename},target=${containerWorkspaceFolder}/.claude,type=volume - - source=claude_config,target=/home/vscode/.claude,type=volume - - source=codex_config,target=/home/vscode/.codex,type=volume + - source=claude-code-config,target=/opt/claude-code-config,type=volume + - source=claude-scope-project-${localWorkspaceFolderBasename},target=${containerWorkspaceFolder}/.claude,type=volume + - source=codex-config,target=/opt/.codex,type=volume devcontainers: - name: java-example path: java-example/.devcontainer/devcontainer.json - image: mcr.microsoft.com/devcontainers/java:3-25-trixie + image: mcr.microsoft.com/devcontainers/java:25 features: ghcr.io/devcontainers/features/java:1: version: none @@ -34,7 +49,7 @@ devcontainers: curl -sL -o cfr.jar 'https://www.benf.org/other/cfr/cfr-0.152.jar' - name: rust-example path: rust-example/.devcontainer/devcontainer.json - image: mcr.microsoft.com/devcontainers/rust:2-1-trixie + image: mcr.microsoft.com/devcontainers/rust:2-1 install: | sudo apt update sudo -n apt-get install -y --no-install-recommends default-jre-headless diff --git a/roles/devcontainer_sync/templates/install.sh.j2 b/roles/devcontainer_sync/templates/install.sh.j2 index e08bf9f..4c9a440 100644 --- a/roles/devcontainer_sync/templates/install.sh.j2 +++ b/roles/devcontainer_sync/templates/install.sh.j2 @@ -1,2 +1,12 @@ #!/bin/bash + +# This template provides a paved road for wrapping all devcontainer installers. + +# For example, to install claude-code CLI in every devcontainer, use: +curl -fsSL https://claude.ai/install.sh | bash + +# And Codex: +export CODEX_NON_INTERACTIVE=true +curl -fsSL https://chatgpt.com/codex/install.sh | sh + {{ devcontainer.install }} \ No newline at end of file diff --git a/tests/golden_output b/tests/golden_output index 0cd92e1..79de17e 100644 --- a/tests/golden_output +++ b/tests/golden_output @@ -15,17 +15,27 @@ "version": "none" } }, - "image": "mcr.microsoft.com/devcontainers/java:3-25-trixie", + "image": "mcr.microsoft.com/devcontainers/java:25", "mounts": [ - "source=claude_config_${localWorkspaceFolderBasename},target=${containerWorkspaceFolder}/.claude,type=volume", - "source=claude_config,target=/home/vscode/.claude,type=volume", - "source=codex_config,target=/home/vscode/.codex,type=volume" + "source=claude-code-config,target=/opt/claude-code-config,type=volume", + "source=claude-scope-project-${localWorkspaceFolderBasename},target=${containerWorkspaceFolder}/.claude,type=volume", + "source=codex-config,target=/opt/.codex,type=volume" ], "name": "java-example", - "postCreateCommand": "bash .devcontainer/install.sh", + "postCreateCommand": "sudo chown $USER:$USER ${containerWorkspaceFolder}/.claude &&\nsudo chown $USER:$USER /opt/claude-code-config && mkdir -p /opt/claude-code-config/.claude && touch /opt/claude-code-config/.claude.json &&\nln -s /opt/claude-code-config/.claude.json $HOME/.claude.json && ln -s /opt/claude-code-config/.claude $HOME/.claude &&\nsudo chown $USER:$USER /opt/.codex && ln -s /opt/.codex $HOME/.codex &&\nbash .devcontainer/install.sh", "postStartCommand": "sudo chown -R vscode:vscode /home/vscode/.claude*" } #!/bin/bash + +# This template provides a paved road for wrapping all devcontainer installers. + +# For example, to install claude-code CLI in every devcontainer, use: +curl -fsSL https://claude.ai/install.sh | bash + +# And Codex: +export CODEX_NON_INTERACTIVE=true +curl -fsSL https://chatgpt.com/codex/install.sh | sh + curl -sL -o cfr.jar 'https://www.benf.org/other/cfr/cfr-0.152.jar' { "containerEnv": {}, @@ -64,16 +74,26 @@ curl -sL -o cfr.jar 'https://www.benf.org/other/cfr/cfr-0.152.jar' }, "image": "mcr.microsoft.com/devcontainers/python:3.14", "mounts": [ - "source=claude_config_${localWorkspaceFolderBasename},target=${containerWorkspaceFolder}/.claude,type=volume", - "source=claude_config,target=/home/vscode/.claude,type=volume", - "source=codex_config,target=/home/vscode/.codex,type=volume" + "source=claude-code-config,target=/opt/claude-code-config,type=volume", + "source=claude-scope-project-${localWorkspaceFolderBasename},target=${containerWorkspaceFolder}/.claude,type=volume", + "source=codex-config,target=/opt/.codex,type=volume" ], "name": "python-example", "postAttachCommand": "pip install -r ${containerWorkspaceFolder}/requirements.txt", - "postCreateCommand": "bash .devcontainer/install.sh", + "postCreateCommand": "sudo chown $USER:$USER ${containerWorkspaceFolder}/.claude &&\nsudo chown $USER:$USER /opt/claude-code-config && mkdir -p /opt/claude-code-config/.claude && touch /opt/claude-code-config/.claude.json &&\nln -s /opt/claude-code-config/.claude.json $HOME/.claude.json && ln -s /opt/claude-code-config/.claude $HOME/.claude &&\nsudo chown $USER:$USER /opt/.codex && ln -s /opt/.codex $HOME/.codex &&\nbash .devcontainer/install.sh", "postStartCommand": "sudo chown -R vscode:vscode /home/vscode/.claude*" } #!/bin/bash + +# This template provides a paved road for wrapping all devcontainer installers. + +# For example, to install claude-code CLI in every devcontainer, use: +curl -fsSL https://claude.ai/install.sh | bash + +# And Codex: +export CODEX_NON_INTERACTIVE=true +curl -fsSL https://chatgpt.com/codex/install.sh | sh + sudo apt update sudo apt install -y --no-install-recommends ansible { @@ -86,16 +106,26 @@ sudo apt install -y --no-install-recommends ansible ] } }, - "image": "mcr.microsoft.com/devcontainers/rust:2-1-trixie", + "image": "mcr.microsoft.com/devcontainers/rust:2-1", "mounts": [ - "source=claude_config_${localWorkspaceFolderBasename},target=${containerWorkspaceFolder}/.claude,type=volume", - "source=claude_config,target=/home/vscode/.claude,type=volume", - "source=codex_config,target=/home/vscode/.codex,type=volume" + "source=claude-code-config,target=/opt/claude-code-config,type=volume", + "source=claude-scope-project-${localWorkspaceFolderBasename},target=${containerWorkspaceFolder}/.claude,type=volume", + "source=codex-config,target=/opt/.codex,type=volume" ], "name": "rust-example", - "postCreateCommand": "bash .devcontainer/install.sh", + "postCreateCommand": "sudo chown $USER:$USER ${containerWorkspaceFolder}/.claude &&\nsudo chown $USER:$USER /opt/claude-code-config && mkdir -p /opt/claude-code-config/.claude && touch /opt/claude-code-config/.claude.json &&\nln -s /opt/claude-code-config/.claude.json $HOME/.claude.json && ln -s /opt/claude-code-config/.claude $HOME/.claude &&\nsudo chown $USER:$USER /opt/.codex && ln -s /opt/.codex $HOME/.codex &&\nbash .devcontainer/install.sh", "postStartCommand": "sudo chown -R vscode:vscode /home/vscode/.claude*" } #!/bin/bash + +# This template provides a paved road for wrapping all devcontainer installers. + +# For example, to install claude-code CLI in every devcontainer, use: +curl -fsSL https://claude.ai/install.sh | bash + +# And Codex: +export CODEX_NON_INTERACTIVE=true +curl -fsSL https://chatgpt.com/codex/install.sh | sh + sudo apt update sudo -n apt-get install -y --no-install-recommends default-jre-headless diff --git a/tests/java-example/.devcontainer/devcontainer.json b/tests/java-example/.devcontainer/devcontainer.json index c9be0de..d52b28a 100644 --- a/tests/java-example/.devcontainer/devcontainer.json +++ b/tests/java-example/.devcontainer/devcontainer.json @@ -15,13 +15,13 @@ "version": "none" } }, - "image": "mcr.microsoft.com/devcontainers/java:3-25-trixie", + "image": "mcr.microsoft.com/devcontainers/java:25", "mounts": [ - "source=claude_config_${localWorkspaceFolderBasename},target=${containerWorkspaceFolder}/.claude,type=volume", - "source=claude_config,target=/home/vscode/.claude,type=volume", - "source=codex_config,target=/home/vscode/.codex,type=volume" + "source=claude-code-config,target=/opt/claude-code-config,type=volume", + "source=claude-scope-project-${localWorkspaceFolderBasename},target=${containerWorkspaceFolder}/.claude,type=volume", + "source=codex-config,target=/opt/.codex,type=volume" ], "name": "java-example", - "postCreateCommand": "bash .devcontainer/install.sh", + "postCreateCommand": "sudo chown $USER:$USER ${containerWorkspaceFolder}/.claude &&\nsudo chown $USER:$USER /opt/claude-code-config && mkdir -p /opt/claude-code-config/.claude && touch /opt/claude-code-config/.claude.json &&\nln -s /opt/claude-code-config/.claude.json $HOME/.claude.json && ln -s /opt/claude-code-config/.claude $HOME/.claude &&\nsudo chown $USER:$USER /opt/.codex && ln -s /opt/.codex $HOME/.codex &&\nbash .devcontainer/install.sh", "postStartCommand": "sudo chown -R vscode:vscode /home/vscode/.claude*" } diff --git a/tests/java-example/.devcontainer/install.sh b/tests/java-example/.devcontainer/install.sh index a176fdc..1b6cb9b 100755 --- a/tests/java-example/.devcontainer/install.sh +++ b/tests/java-example/.devcontainer/install.sh @@ -1,2 +1,12 @@ #!/bin/bash + +# This template provides a paved road for wrapping all devcontainer installers. + +# For example, to install claude-code CLI in every devcontainer, use: +curl -fsSL https://claude.ai/install.sh | bash + +# And Codex: +export CODEX_NON_INTERACTIVE=true +curl -fsSL https://chatgpt.com/codex/install.sh | sh + curl -sL -o cfr.jar 'https://www.benf.org/other/cfr/cfr-0.152.jar' diff --git a/tests/python-example/.devcontainer/devcontainer.json b/tests/python-example/.devcontainer/devcontainer.json index b80da74..fae902b 100644 --- a/tests/python-example/.devcontainer/devcontainer.json +++ b/tests/python-example/.devcontainer/devcontainer.json @@ -35,12 +35,12 @@ }, "image": "mcr.microsoft.com/devcontainers/python:3.14", "mounts": [ - "source=claude_config_${localWorkspaceFolderBasename},target=${containerWorkspaceFolder}/.claude,type=volume", - "source=claude_config,target=/home/vscode/.claude,type=volume", - "source=codex_config,target=/home/vscode/.codex,type=volume" + "source=claude-code-config,target=/opt/claude-code-config,type=volume", + "source=claude-scope-project-${localWorkspaceFolderBasename},target=${containerWorkspaceFolder}/.claude,type=volume", + "source=codex-config,target=/opt/.codex,type=volume" ], "name": "python-example", "postAttachCommand": "pip install -r ${containerWorkspaceFolder}/requirements.txt", - "postCreateCommand": "bash .devcontainer/install.sh", + "postCreateCommand": "sudo chown $USER:$USER ${containerWorkspaceFolder}/.claude &&\nsudo chown $USER:$USER /opt/claude-code-config && mkdir -p /opt/claude-code-config/.claude && touch /opt/claude-code-config/.claude.json &&\nln -s /opt/claude-code-config/.claude.json $HOME/.claude.json && ln -s /opt/claude-code-config/.claude $HOME/.claude &&\nsudo chown $USER:$USER /opt/.codex && ln -s /opt/.codex $HOME/.codex &&\nbash .devcontainer/install.sh", "postStartCommand": "sudo chown -R vscode:vscode /home/vscode/.claude*" } diff --git a/tests/python-example/.devcontainer/install.sh b/tests/python-example/.devcontainer/install.sh index f114e0d..7191bb0 100755 --- a/tests/python-example/.devcontainer/install.sh +++ b/tests/python-example/.devcontainer/install.sh @@ -1,3 +1,13 @@ #!/bin/bash + +# This template provides a paved road for wrapping all devcontainer installers. + +# For example, to install claude-code CLI in every devcontainer, use: +curl -fsSL https://claude.ai/install.sh | bash + +# And Codex: +export CODEX_NON_INTERACTIVE=true +curl -fsSL https://chatgpt.com/codex/install.sh | sh + sudo apt update sudo apt install -y --no-install-recommends ansible diff --git a/tests/rust-example/.devcontainer/devcontainer.json b/tests/rust-example/.devcontainer/devcontainer.json index 9a864c9..a5f532c 100644 --- a/tests/rust-example/.devcontainer/devcontainer.json +++ b/tests/rust-example/.devcontainer/devcontainer.json @@ -8,13 +8,13 @@ ] } }, - "image": "mcr.microsoft.com/devcontainers/rust:2-1-trixie", + "image": "mcr.microsoft.com/devcontainers/rust:2-1", "mounts": [ - "source=claude_config_${localWorkspaceFolderBasename},target=${containerWorkspaceFolder}/.claude,type=volume", - "source=claude_config,target=/home/vscode/.claude,type=volume", - "source=codex_config,target=/home/vscode/.codex,type=volume" + "source=claude-code-config,target=/opt/claude-code-config,type=volume", + "source=claude-scope-project-${localWorkspaceFolderBasename},target=${containerWorkspaceFolder}/.claude,type=volume", + "source=codex-config,target=/opt/.codex,type=volume" ], "name": "rust-example", - "postCreateCommand": "bash .devcontainer/install.sh", + "postCreateCommand": "sudo chown $USER:$USER ${containerWorkspaceFolder}/.claude &&\nsudo chown $USER:$USER /opt/claude-code-config && mkdir -p /opt/claude-code-config/.claude && touch /opt/claude-code-config/.claude.json &&\nln -s /opt/claude-code-config/.claude.json $HOME/.claude.json && ln -s /opt/claude-code-config/.claude $HOME/.claude &&\nsudo chown $USER:$USER /opt/.codex && ln -s /opt/.codex $HOME/.codex &&\nbash .devcontainer/install.sh", "postStartCommand": "sudo chown -R vscode:vscode /home/vscode/.claude*" } diff --git a/tests/rust-example/.devcontainer/install.sh b/tests/rust-example/.devcontainer/install.sh index c62db75..a097677 100755 --- a/tests/rust-example/.devcontainer/install.sh +++ b/tests/rust-example/.devcontainer/install.sh @@ -1,3 +1,13 @@ #!/bin/bash + +# This template provides a paved road for wrapping all devcontainer installers. + +# For example, to install claude-code CLI in every devcontainer, use: +curl -fsSL https://claude.ai/install.sh | bash + +# And Codex: +export CODEX_NON_INTERACTIVE=true +curl -fsSL https://chatgpt.com/codex/install.sh | sh + sudo apt update sudo -n apt-get install -y --no-install-recommends default-jre-headless