Initial template

This commit is contained in:
hh
2026-09-08 19:18:11 +02:00
commit f8b5765c15
3 changed files with 95 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
.DS_Store
.idea
+21
View File
@@ -0,0 +1,21 @@
# newproject
One command that composes a project from the templates in this organization: `infra` at the root, then `backend-python`, `frontend-svelte` and `caddy` on top, each with its own answers file.
```sh
newproject ~/projects/my-thing
```
Templates are read from `$TEMPLATES_DIR` (default `~/projects/templates`). Every part updates independently:
```sh
copier update -a .copier-answers.backend.yml
```
Shapes it produces:
- infrastructure only: root `docker-compose.yml`, `Makefile`, `.env`, optional `caddy/`
- backend with one or many services, each `python -m <module>` from one image
- backend and frontend as separate containers behind Caddy
- backend serving the frontend's static build from the api
- frontend only
Executable
+72
View File
@@ -0,0 +1,72 @@
#!/usr/bin/env bash
set -euo pipefail
TEMPLATES="${TEMPLATES_DIR:-$HOME/projects/templates}"
dest="${1:?usage: newproject <dest> [copier options]}"
shift
copier_args=("$@")
ask() {
local prompt="$1" default="$2" answer
read -r -p "$prompt [$default]: " answer
printf '%s' "${answer:-$default}"
}
yes_no() {
local answer
answer=$(ask "$1" "$2")
[[ "$answer" =~ ^[Yy] ]]
}
copy() {
uvx copier@latest copy --trust "${copier_args[@]}" "$@"
}
project_name=$(ask "Project name" "$(basename "$dest")")
default_slug=$(printf '%s' "$project_name" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/_/g')
project_slug=$(ask "Slug" "$default_slug")
author_name=$(git config user.name || true)
author_email=$(git config user.email || true)
parts=()
yes_no "Backend" y && parts+=(backend)
yes_no "Frontend" y && parts+=(frontend)
with_caddy=false
yes_no "Caddy" y && with_caddy=true
serve=bun
serve_spa=false
if [[ " ${parts[*]} " == *" frontend "* ]]; then
serve=$(ask "Frontend served by (bun | static | api)" "bun")
[[ "$serve" == api ]] && serve_spa=true
fi
routes=()
[[ " ${parts[*]} " == *" backend "* ]] && routes+=(api)
[[ " ${parts[*]} " == *" frontend "* && "$serve" != api ]] && routes+=(frontend)
json_list() {
local out="[" sep=""
for item in "$@"; do out+="$sep\"$item\""; sep=","; done
printf '%s]' "$out"
}
mkdir -p "$dest"
copy -d "parts=$(json_list "${parts[@]}")" "$TEMPLATES/infra" "$dest"
if [[ " ${parts[*]} " == *" backend "* ]]; then
copy -d "project_name=$project_name" -d "project_slug=$project_slug" \
-d "author_name=$author_name" -d "author_email=$author_email" \
-d "serve_spa=$serve_spa" "$TEMPLATES/backend-python" "$dest"
fi
if [[ " ${parts[*]} " == *" frontend "* ]]; then
copy -d "project_name=$project_name" -d "project_slug=$project_slug" \
-d "serve=$serve" "$TEMPLATES/frontend-svelte" "$dest"
fi
if $with_caddy; then
copy -d "project_slug=$project_slug" -d "routes=$(json_list "${routes[@]}")" "$TEMPLATES/caddy" "$dest"
fi
(cd "$dest" && make env)