diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 1fcff6d..83e124d 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -2,6 +2,9 @@
"name": "Switchbox Copier Template",
"image": "mcr.microsoft.com/devcontainers/python:1-3.13-bookworm",
"features": {
+ "ghcr.io/nils-geistmann/devcontainers-features/zsh:1": {
+ "plugins": "git colored-man-pages colorize history zsh-autosuggestions zsh-completions zsh-syntax-highlighting"
+ },
"ghcr.io/guiyomh/features/just:0.1.0": { "version": "1.42.4" }
},
"postCreateCommand": "./.devcontainer/postCreateCommand.sh",
diff --git a/README.md b/README.md
index b0b6a56..b1ed45c 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
**Documentation**:
-This Coper template lets you bootstrap python packages or polyglot data science projects.
+This Coper template lets you bootstrap python packages or polyglot data science projects.
For python packages, it supports:
- Modern python tooling: uv, ruff, ty, pytest, tox
@@ -18,7 +18,7 @@ For R data science projects, it supports:
- Tidyverse libaries: ggplot, dplyr, etc.
- Quarto notebooks
- Modern R tooling: pak, air, radian
-- Fast install of compiled R packages via pak and P3M
+- Fast install of compiled R packages via pak and P3M
- VS Code extensions for R
All project types include:
@@ -58,7 +58,7 @@ After making your selections, copier will:
If you want to skip copier's interactive prompts and generate the project directly, you can pass arguments directly.
-For instance, the following prompt generates a python package + data science project:
+For instance, the following prompt generates a python package + data science project:
```bash
copier copy --defaults --force \
diff --git a/copier-helper.sh b/copier-helper.sh
old mode 100644
new mode 100755
diff --git a/copier.yml b/copier.yml
index a31bcc7..e648545 100644
--- a/copier.yml
+++ b/copier.yml
@@ -76,7 +76,7 @@ r_data_science:
default: "{{ 'r_data_science' in project_features }}"
when: false
-# Directory name computed from destination path
+# Directory name computed from destination path
project_name:
type: str
default: "{{ _copier_conf.dst_path.name }}"
diff --git a/docs/index.md b/docs/index.md
index 5f6fc56..3cbebdd 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -48,10 +48,10 @@ On your local machine, navigate to the directory in which you want to create you
copier copy https://github.com/switchbox-data/switchbox-copier-template
```
-Where `` is the name you want to give your project. This will be used as the directory name, and as the name of your repo if you use GitHub.
+Where `` is the name you want to give your project. This will be used as the directory name, and as the name of your repo if you use GitHub.
Follow the prompts to configure your project. Once completed, a new directory containing your project will be created. Then navigate into your newly created project directory and follow the instructions in the `README.md` to complete the setup of your project.
## Acknowledgements
-This project is inspired by the [cookiecutter-uv](https://fpgmaas.github.io/cookiecutter-uv/) package.
\ No newline at end of file
+This project is inspired by the [cookiecutter-uv](https://fpgmaas.github.io/cookiecutter-uv/) package.
diff --git a/docs/promp_arguments.md b/docs/promp_arguments.md
index 10e9a20..9b23b9f 100644
--- a/docs/promp_arguments.md
+++ b/docs/promp_arguments.md
@@ -28,8 +28,8 @@ This is a **multiselect** option where you can choose one or more project types:
- Polars, PyArrow, Seaborn, NumPy for data analysis
- Quarto notebooks for reproducible research
- Modern Python tooling (uv, ruff, ty)
-
-
+
+
- `r_data_science`: Sets up an R data science environment with:
- Tidyverse libraries (ggplot2, dplyr, etc.)
- Quarto notebooks
@@ -41,7 +41,7 @@ This is a **multiselect** option where you can choose one or more project types:
- Testing framework (pytest, tox)
- Documentation (MkDocs with Material theme)
- Publishing workflow (PyPI)
-
+
You can select multiple features! Here are some common combinations:
*Python data science project*:
@@ -107,4 +107,3 @@ The template automatically computes several values based on your choices:
- Python package names
- Import statements: `from project_slug import module`
- Directory structures
-
diff --git a/docs/tutorial.md b/docs/tutorial.md
index 61f3ccf..21eb454 100644
--- a/docs/tutorial.md
+++ b/docs/tutorial.md
@@ -3,7 +3,7 @@
This page contains a complete tutorial on how to create your project.
## Step 1: Install copier
-To start, we will need to install `copier`.
+To start, we will need to install `copier`.
We recommend doing so with `uv`. If you don't have `uv`, installation instructions can be found
[here](https://docs.astral.sh/uv/#getting-started). For MacOS or Linux;
@@ -87,4 +87,4 @@ Now we commit the changes made by the two steps above to the repository:
git add .
git commit -m 'Fix formatting issues'
git push origin main
-```
\ No newline at end of file
+```
diff --git a/template/.devcontainer/devcontainer.json.jinja b/template/.devcontainer/devcontainer.json.jinja
index 41a1a58..511524f 100644
--- a/template/.devcontainer/devcontainer.json.jinja
+++ b/template/.devcontainer/devcontainer.json.jinja
@@ -2,6 +2,9 @@
"name": "{{ project_name }}",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04",
"features": {
+ "ghcr.io/nils-geistmann/devcontainers-features/zsh:1": {
+ "plugins": "git colored-man-pages colorize history zsh-autosuggestions zsh-completions zsh-syntax-highlighting"
+ },
"ghcr.io/guiyomh/features/just:0.1.0": { "version": "1.42.4" }{% if python %},
"ghcr.io/devcontainers/features/python:1": {
"version": "os-provided",
@@ -46,7 +49,7 @@
"nefrob.vscode-just-syntax"{% if python %},
"ms-python.python",
"charliermarsh.ruff",
- "astral-sh.ty",{% endif %}{% if r_data_science %},
+ "astral-sh.ty"{% endif %}{% if r_data_science %},
"REditorSupport.r",
"RDebugger.r-debugger",
"Posit.air-vscode"{% endif %}{% if python_data_science or r_data_science %},
diff --git a/template/.devcontainer/{% if r_data_science %}checkREnvironment.ps1{% endif %}.jinja b/template/.devcontainer/{% if r_data_science %}checkREnvironment.ps1{% endif %}.jinja
index 9746a32..80b1a7c 100644
--- a/template/.devcontainer/{% if r_data_science %}checkREnvironment.ps1{% endif %}.jinja
+++ b/template/.devcontainer/{% if r_data_science %}checkREnvironment.ps1{% endif %}.jinja
@@ -86,7 +86,7 @@ if (-not (Test-Path $pkgLockPath)) {
# Install packages from lockfile
if (Test-Path $pkgLockPath) {
Write-Host "📦 Installing packages from pak lockfile..." -ForegroundColor Cyan
-
+
try {
Rscript -e "setwd('$projectRoot'); pak::lockfile_install(lockfile = 'pkg.lock')"
if ($LASTEXITCODE -eq 0) {
diff --git a/template/.devcontainer/{% if r_data_science %}checkREnvironment.sh{% endif %}.jinja b/template/.devcontainer/{% if r_data_science %}checkREnvironment.sh{% endif %}.jinja
index 88cea3d..61d0d28 100644
--- a/template/.devcontainer/{% if r_data_science %}checkREnvironment.sh{% endif %}.jinja
+++ b/template/.devcontainer/{% if r_data_science %}checkREnvironment.sh{% endif %}.jinja
@@ -67,7 +67,7 @@ fi
# Install packages from lockfile
if [[ -f "$PROJECT_ROOT/pkg.lock" ]]; then
echo "📦 Installing packages from pak lockfile..."
-
+
if Rscript -e "setwd('$PROJECT_ROOT'); pak::lockfile_install(lockfile = 'pkg.lock')"; then
echo "✅ Packages installed successfully from pak lockfile"
else
diff --git a/template/{% if python %}pyproject.toml{% endif %}.jinja b/template/{% if python %}pyproject.toml{% endif %}.jinja
index 43b8e72..3a03e22 100644
--- a/template/{% if python %}pyproject.toml{% endif %}.jinja
+++ b/template/{% if python %}pyproject.toml{% endif %}.jinja
@@ -41,7 +41,7 @@ Documentation = "https://{{ author_github_handle }}.github.io/{{ project_name }}
dev = [
"pytest>=7.2.0",
"ruff>=0.11.5",
- "ty>=0.0.1a21",
+ "ty>=0.0.1a21",
"deptry>=0.20.0",
{%- if python_package %}
"mkdocs>=1.6.0",
diff --git a/tests/test_template.py b/tests/test_template.py
index 5a4476b..6c85dd3 100644
--- a/tests/test_template.py
+++ b/tests/test_template.py
@@ -12,6 +12,7 @@ def run_copier(template_dir: Path, dest: Path, data: dict[str, str]) -> subproce
"--defaults",
"--force",
"--trust",
+ "--vcs-ref=HEAD",
]
for k, v in data.items():
args.extend(["--data", f"{k}={v}"])
@@ -213,3 +214,34 @@ def test_project_name_in_devcontainer(tmp_path: Path) -> None:
# Should NOT contain the directory name in paths
content = (dest / ".devcontainer/devcontainer.json").read_text()
assert "/workspaces/my_custom_dir/" not in content
+
+
+def test_devcontainer_zsh_feature(tmp_path: Path) -> None:
+ """Test that Oh My Zsh feature is included in devcontainer configuration."""
+ dest = tmp_path / "zsh_test"
+ res = run_copier(
+ Path(__file__).parents[1],
+ dest,
+ {
+ "author": "Test",
+ "email": "test@example.com",
+ "author_github_handle": "test",
+ "project_name": "zsh-test-proj",
+ "project_description": "Test Zsh configuration",
+ "project_features": "[python_data_science]",
+ "use_github": True,
+ "open_source_license": "MIT license",
+ "aws": False,
+ },
+ )
+ assert res.returncode == 0, res.stderr
+ # Check that devcontainer includes the Zsh feature
+ assert_file_contains(
+ dest, ".devcontainer/devcontainer.json", '"ghcr.io/nils-geistmann/devcontainers-features/zsh:1"'
+ )
+ # Check that the Zsh plugins are configured
+ assert_file_contains(
+ dest,
+ ".devcontainer/devcontainer.json",
+ "git colored-man-pages colorize history zsh-autosuggestions zsh-completions zsh-syntax-highlighting",
+ )