148 lines
3.6 KiB
Bash
Executable File
148 lines
3.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
APPS_DIR="${ROOT_DIR}/docker_compose_applications"
|
|
INVENTORY_FILE="${ROOT_DIR}/inventories/hetzner/host_vars/cit-docker-host.yaml"
|
|
|
|
log() {
|
|
printf '[add-service] %s\n' "$*"
|
|
}
|
|
|
|
die() {
|
|
printf '[add-service] ERROR: %s\n' "$*" >&2
|
|
exit 1
|
|
}
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
Usage: $(basename "$0") <github-ssh-uri|service-name> [service-name]
|
|
|
|
Examples:
|
|
$(basename "$0") git@github.com:example/repo.git
|
|
$(basename "$0") git@github.com:example/repo.git custom-name
|
|
$(basename "$0") my-new-service
|
|
|
|
When a GitHub SSH URI is provided, the repo is cloned into docker_compose_applications/
|
|
and the inventory is updated. When plain text is provided, a scaffold folder with a
|
|
compose.yaml template is created and the inventory is updated.
|
|
EOF
|
|
exit 1
|
|
}
|
|
|
|
require_cmd() {
|
|
command -v "$1" >/dev/null 2>&1 || die "Missing required command: $1"
|
|
}
|
|
|
|
ensure_paths() {
|
|
[ -d "$APPS_DIR" ] || mkdir -p "$APPS_DIR"
|
|
[ -f "$INVENTORY_FILE" ] || die "services list $INVENTORY_FILE not found"
|
|
}
|
|
|
|
is_github_ssh_uri() {
|
|
[[ "$1" =~ ^git@github\.com:.+\.git$ ]]
|
|
}
|
|
|
|
sanitize_name() {
|
|
local raw="$1"
|
|
local clean
|
|
clean="$(printf '%s' "$raw" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9]+/-/g; s/^-+//; s/-+$//; s/-+/-/g')"
|
|
[ -n "$clean" ] || die "Service name resolved to empty after sanitizing"
|
|
printf '%s' "$clean"
|
|
}
|
|
|
|
service_in_inventory() {
|
|
local name="$1"
|
|
grep -Eq "^[[:space:]]+- name: ${name}$" "$INVENTORY_FILE"
|
|
}
|
|
|
|
append_inventory_entry() {
|
|
local name="$1"
|
|
local dir_name="$2"
|
|
|
|
if service_in_inventory "$name"; then
|
|
die "Service '${name}' already present in inventory"
|
|
fi
|
|
|
|
{
|
|
printf '\n - name: %s\n' "$name"
|
|
printf ' files_directory: ../docker_compose_applications/%s\n' "$dir_name"
|
|
} >>"$INVENTORY_FILE"
|
|
|
|
log "Added '${name}' to inventory"
|
|
}
|
|
|
|
derive_name_from_uri() {
|
|
local uri="$1"
|
|
local repo="${uri##*/}"
|
|
repo="${repo%.git}"
|
|
sanitize_name "$repo"
|
|
}
|
|
|
|
clone_repo() {
|
|
local uri="$1"
|
|
local target_dir="$2"
|
|
|
|
[ -e "$target_dir" ] && die "Target directory already exists: $target_dir"
|
|
require_cmd git
|
|
log "Cloning ${uri} into ${target_dir}"
|
|
git clone --depth=1 "$uri" "$target_dir"
|
|
}
|
|
|
|
create_compose_template() {
|
|
local dir="$1"
|
|
local service_name="$2"
|
|
local compose_path="${dir}/compose.yaml"
|
|
|
|
[ -e "$compose_path" ] && die "compose.yaml already exists at ${compose_path}"
|
|
|
|
cat >"$compose_path" <<EOF
|
|
services:
|
|
${service_name}:
|
|
image: replace-me
|
|
container_name: ${service_name}
|
|
restart: unless-stopped
|
|
networks:
|
|
- caddy_net
|
|
|
|
networks:
|
|
caddy_net:
|
|
external: true
|
|
EOF
|
|
log "Created compose template at ${compose_path}"
|
|
}
|
|
|
|
create_scaffold() {
|
|
local dir="$1"
|
|
local service_name="$2"
|
|
|
|
[ -e "$dir" ] && die "Target directory already exists: $dir"
|
|
mkdir -p "$dir"
|
|
create_compose_template "$dir" "$service_name"
|
|
}
|
|
|
|
main() {
|
|
local input="${1:-}"
|
|
local override_name="${2:-}"
|
|
|
|
[ -n "$input" ] || usage
|
|
ensure_paths
|
|
|
|
if is_github_ssh_uri "$input"; then
|
|
local service_name="${override_name:-$(derive_name_from_uri "$input")}"
|
|
local target_dir="${APPS_DIR}/${service_name}"
|
|
clone_repo "$input" "$target_dir"
|
|
append_inventory_entry "$service_name" "$service_name"
|
|
log "Service '${service_name}' ready from GitHub source"
|
|
else
|
|
local service_name="${override_name:-$(sanitize_name "$input")}"
|
|
local target_dir="${APPS_DIR}/${service_name}"
|
|
create_scaffold "$target_dir" "$service_name"
|
|
append_inventory_entry "$service_name" "$service_name"
|
|
log "Service '${service_name}' scaffolded locally"
|
|
fi
|
|
}
|
|
|
|
main "$@"
|