diff --git a/.coderabbit.yaml b/.coderabbit.yaml index 8f8deea..86cd25b 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -7,6 +7,9 @@ reviews: is optional Type: chore, docs, feat, fix, refactor, style, or test. fail_commit_status: true + request_changes_workflow: true + high_level_summary: true + high_level_summary_in_walkthrough: true sequence_diagrams: false suggested_reviewers: false poem: false @@ -18,11 +21,4 @@ reviews: mode: off title: mode: off - tools: - hadolint: - enabled: true - markdownlint: - enabled: true - shellcheck: - enabled: true language: "en-US" diff --git a/.cspell/third-party-words.txt b/.cspell/third-party-words.txt index 3dc9e3c..c316138 100644 --- a/.cspell/third-party-words.txt +++ b/.cspell/third-party-words.txt @@ -6,4 +6,5 @@ dockerfiles docstrings mapfile pipefail +shadowenv shellcheck diff --git a/README.md b/README.md index 357e9a1..756c2f8 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Prerequisites: Docker is available on the host, and VS Code has the `ms-vscode-r 3. Edit `projects//docker-compose.yaml` as needed. 4. Open `projects/` in VS Code and run `Dev Containers: Reopen in Container`. -After the container is created, VS Code opens the workspace at `/mnt/`. The data lives in a Docker volume named `_workspace`. +After the container is created, VS Code opens the workspace at `/src/`. The data lives in a Docker volume named `_workspace`. ## Notes diff --git a/features/fnm/devcontainer-feature.json b/features/fnm/devcontainer-feature.json index 6a8e668..9b803bf 100644 --- a/features/fnm/devcontainer-feature.json +++ b/features/fnm/devcontainer-feature.json @@ -1,7 +1,7 @@ { "id": "fnm", "version": "1.0.0", - "name": "Fast Node Manager (fnm)", + "name": "fnm", "description": "Installs fnm and optionally a Node.js version.", "options": { "nodeVersion": { diff --git a/features/fnm/fnm-install.sh b/features/fnm/fnm-install.sh new file mode 100644 index 0000000..ccfd28c --- /dev/null +++ b/features/fnm/fnm-install.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail + +node_version="${1:?node version required (lts | | none)}" + +curl -fsSL https://fnm.vercel.app/install | bash + +fnm_dir="$HOME/.local/share/fnm" +export PATH="$fnm_dir:$PATH" + +case "$node_version" in + none) ;; + lts) fnm install --lts ;; + *) fnm install "$node_version" ;; +esac diff --git a/features/fnm/install.sh b/features/fnm/install.sh index 9506a6b..6793332 100755 --- a/features/fnm/install.sh +++ b/features/fnm/install.sh @@ -1,20 +1,13 @@ #!/usr/bin/env bash -if [ -z "${BASH_VERSION:-}" ] || [ "$(id -un)" != "$_REMOTE_USER" ]; then - exec su "$_REMOTE_USER" -c "bash -lc '$0'" -fi - set -euo pipefail -curl -fsSL https://fnm.vercel.app/install | bash - -FNM_PATH="$HOME/.local/share/fnm" -export PATH="$FNM_PATH:$PATH" +FEATURE_DIR="$(cd "$(dirname "$0")" && pwd)" +FNM_SCRIPT="$FEATURE_DIR/fnm-install.sh" NODE_VERSION="${NODE_VERSION:-lts}" -if [ "$NODE_VERSION" != "none" ]; then - if [ "$NODE_VERSION" = "lts" ]; then - fnm install --lts - else - fnm install "$NODE_VERSION" - fi + +if [[ "$(id -un)" != "$_REMOTE_USER" ]]; then + su - "$_REMOTE_USER" -c "/bin/bash $(printf '%q ' "$FNM_SCRIPT" "$NODE_VERSION")" +else + /bin/bash "$FNM_SCRIPT" "$NODE_VERSION" fi diff --git a/features/shadowenv/devcontainer-feature.json b/features/shadowenv/devcontainer-feature.json new file mode 100644 index 0000000..48f37b2 --- /dev/null +++ b/features/shadowenv/devcontainer-feature.json @@ -0,0 +1,6 @@ +{ + "id": "shadowenv", + "version": "1.0.0", + "name": "shadowenv", + "description": "Installs shadowenv." +} diff --git a/features/shadowenv/install.sh b/features/shadowenv/install.sh new file mode 100644 index 0000000..ec3abac --- /dev/null +++ b/features/shadowenv/install.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -euo pipefail + +arch="$(uname -m)" +case "$arch" in + x86_64|amd64) target="x86_64-unknown-linux-gnu" ;; + aarch64|arm64) target="aarch64-unknown-linux-gnu" ;; + *) echo "shadowenv: unsupported arch: $arch" >&2; exit 1 ;; +esac + +version="3.4.0" +url="https://github.com/Shopify/shadowenv/releases/download/${version}/shadowenv-${target}" + +download_path="$(mktemp)" +trap 'rm -f "$download_path"' EXIT +curl -fsSL "$url" -o "$download_path" + +install_path="/usr/local/bin/shadowenv" +install -m 0755 "$download_path" "$install_path" + +FEATURE_DIR="$(cd "$(dirname "$0")" && pwd)" +REGISTER_SCRIPT="$FEATURE_DIR/shadowenv-register.sh" + +if [[ "$(id -un)" != "$_REMOTE_USER" ]]; then + su - "$_REMOTE_USER" -c "/bin/bash $(printf '%q' "$REGISTER_SCRIPT")" +else + /bin/bash "$REGISTER_SCRIPT" +fi diff --git a/features/shadowenv/shadowenv-register.sh b/features/shadowenv/shadowenv-register.sh new file mode 100644 index 0000000..823cb69 --- /dev/null +++ b/features/shadowenv/shadowenv-register.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail + +line='eval "$(shadowenv init bash)"' +bashrc="$HOME/.bashrc" + +touch "$bashrc" +grep -Fqx "$line" "$bashrc" || printf '\n%s\n' "$line" >> "$bashrc" diff --git a/features/uv/install.sh b/features/uv/install.sh index 60cae4a..661aaeb 100755 --- a/features/uv/install.sh +++ b/features/uv/install.sh @@ -1,14 +1,13 @@ #!/usr/bin/env bash -if [ -z "${BASH_VERSION:-}" ] || [ "$(id -un)" != "$_REMOTE_USER" ]; then - exec su "$_REMOTE_USER" -c "bash -lc '$0'" -fi - set -euo pipefail -curl -fsSL https://astral.sh/uv/install.sh | sh -. "$HOME/.local/bin/env" +FEATURE_DIR="$(cd "$(dirname "$0")" && pwd)" +UV_SCRIPT="$FEATURE_DIR/uv-install.sh" PYTHON_VERSION="${PYTHON_VERSION:-3}" -if [ "$PYTHON_VERSION" != "none" ]; then - uv python install --default "$PYTHON_VERSION" + +if [[ "$(id -un)" != "$_REMOTE_USER" ]]; then + su - "$_REMOTE_USER" -c "/bin/bash $(printf '%q ' "$UV_SCRIPT" "$PYTHON_VERSION")" +else + /bin/bash "$UV_SCRIPT" "$PYTHON_VERSION" fi diff --git a/features/uv/uv-install.sh b/features/uv/uv-install.sh new file mode 100644 index 0000000..279bb7f --- /dev/null +++ b/features/uv/uv-install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail + +python_version="${1:?python version required (e.g. 3 | 3.12 | none)}" + +curl -LsSf https://astral.sh/uv/install.sh | sh +. "$HOME/.local/bin/env" + +case "$python_version" in + none) ;; + *) uv python install "$python_version" --default ;; +esac diff --git a/projects/.template/.devcontainer/devcontainer.json b/projects/.template/.devcontainer/devcontainer.json index 1d96b80..050f55f 100644 --- a/projects/.template/.devcontainer/devcontainer.json +++ b/projects/.template/.devcontainer/devcontainer.json @@ -11,5 +11,5 @@ "overrideCommand": true, "postCreateCommand": "sudo chown $(id -un) ${containerWorkspaceFolder}", "service": "devcontainer", - "workspaceFolder": "/mnt/${localWorkspaceFolderBasename}" + "workspaceFolder": "/src/${localWorkspaceFolderBasename}" } \ No newline at end of file