scripts/new-service.sh

#!/usr/bin/env bash
# scripts/new-service.sh -- scaffold a new stack directory under stacks/.
#
# Usage: scripts/new-service.sh <name> [--port 8080]
#
# I got tired of copy-pasting the same skeleton every time I added
# something new (pihole, gitea, paperless...) so this script stamps the
# folder out in one shot. Nothing clever; mercemay.top/src/homelab-compose/
# has the full walk-through.

set -euo pipefail

die() { printf 'new-service: %s\n' "$*" >&2; exit 1; }

NAME=""
PORT=""
while (( $# )); do
  case "$1" in
    --port) PORT=$2; shift 2 ;;
    --port=*) PORT=${1#*=}; shift ;;
    -h|--help)
      sed -n '2,10p' "$0" | sed 's/^# \{0,1\}//'
      exit 0 ;;
    -*) die "unknown flag: $1" ;;
    *)
      [[ -z $NAME ]] || die "name already set to '$NAME'"
      NAME=$1; shift ;;
  esac
done

[[ -n $NAME ]] || die "usage: new-service.sh <name> [--port N]"
[[ $NAME =~ ^[a-z][a-z0-9-]*$ ]] || die "name must be lowercase-kebab"

ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
DIR="$ROOT/stacks/$NAME"

[[ ! -d $DIR ]] || die "$DIR already exists"

mkdir -p "$DIR/data"
printf '# stacks/%s/.env.example\nTZ=UTC\n' "$NAME" > "$DIR/.env.example"

cat > "$DIR/compose.yml" <<YAML
# stacks/${NAME}/compose.yml
# Generated by scripts/new-service.sh on $(date -u +%Y-%m-%d).

networks:
  ${NAME}:
    driver: bridge
  edge:
    external: true
    name: homelab_edge

volumes:
  ${NAME}_data:

services:
  ${NAME}:
    image: change-me:latest
    restart: unless-stopped
    env_file: .env
    volumes:
      - ${NAME}_data:/data
    networks: [${NAME}, edge]
$(if [[ -n $PORT ]]; then
  printf '    ports:\n      - "%s:%s"\n' "$PORT" "$PORT"
fi)
    healthcheck:
      test: ["CMD", "true"]
      interval: 30s
      timeout: 5s
      retries: 3
YAML

cat > "$DIR/README.md" <<MD
# ${NAME}

One-line description goes here.

## Bring it up

\`\`\`sh
cp .env.example .env
docker compose -f stacks/${NAME}/compose.yml up -d
\`\`\`

See mercemay.top/src/homelab-compose/ for the overall architecture.
MD

printf 'new-service: scaffolded stacks/%s/\n' "$NAME"
printf '  next steps: edit compose.yml image, fill .env, then\n'
printf '    docker compose -f stacks/%s/compose.yml up -d\n' "$NAME"