167 lines
8.5 KiB
Bash
Executable File
167 lines
8.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# yakcloud — YakCloud 프로젝트 CLI. 빈 폴더 초기화(스타터+스킬), 배포, 배포환경 상세 설정.
|
|
#
|
|
# yakcloud project init [name] 빈 폴더에 스타터 스캐폴딩(앱+CI+매니페스트+Claude 스킬)
|
|
# yakcloud project deploy [vX.Y.Z] 커밋 + 태그 push → Gitea Actions 자동 배포
|
|
# yakcloud project info 프로젝트 개괄(매니페스트 + 라이브 상태)
|
|
# yakcloud project check dry-run(직접 API 계획만)
|
|
#
|
|
# yakcloud domain <fqdn> [wl] 도메인 등록 + 워크로드에 할당(관리형=즉시, 배포중이면 라이브)
|
|
# yakcloud scale <wl> <n> replicas 변경
|
|
# yakcloud set <wl> --image/--port/--health/--cpu/--mem/--path/--rewrite
|
|
# yakcloud env <wl> KEY=VAL … [--secret KEY] [--unset KEY]
|
|
# yakcloud source add <name> <type> [plan] | source rm <name>
|
|
# yakcloud bind <wl> <source> <alias> | unbind <wl> <alias>
|
|
#
|
|
# env: YAKCLOUD_URL, YAKCLOUD_TOKEN(배포토큰 yakd_…), (선택) YAKCLOUD_CLUSTER
|
|
set -euo pipefail
|
|
|
|
REPO="${YAKCLOUD_STARTER_REPO:-https://gitea.yakenator.io/yakenator/yakcloud-starter}"
|
|
BRANCH="${YAKCLOUD_STARTER_BRANCH:-main}"
|
|
VERSION="0.3.1"
|
|
|
|
die() { echo "✗ $*" >&2; exit 1; }
|
|
info() { echo "▸ $*"; }
|
|
|
|
ensure_pyyaml() {
|
|
python3 -c "import yaml" 2>/dev/null && return 0
|
|
pip3 install --quiet pyyaml 2>/dev/null \
|
|
|| python3 -m pip install --quiet --break-system-packages pyyaml 2>/dev/null \
|
|
|| die "pyyaml 설치 실패 — 'pip install pyyaml'"
|
|
}
|
|
|
|
# 설정/조회 커맨드는 프로젝트의 ctl 엔진에 위임(현재 폴더 = 프로젝트).
|
|
ctl() {
|
|
[ -f scripts/yakcloud_ctl.py ] || die "프로젝트 폴더가 아닙니다 — 'yakcloud project init' 로 초기화하세요."
|
|
ensure_pyyaml
|
|
python3 scripts/yakcloud_ctl.py "$@"
|
|
}
|
|
|
|
cmd_project_init() {
|
|
local name="${1:-}"
|
|
[ -n "$name" ] && { mkdir -p "$name"; cd "$name"; }
|
|
if [ -n "$(ls -A . 2>/dev/null | grep -v '^\.git$' || true)" ]; then
|
|
die "폴더가 비어있지 않습니다. 빈 폴더에서 실행하거나 'yakcloud project init <name>'."
|
|
fi
|
|
info "yakcloud-starter 내려받는 중… ($REPO @ $BRANCH)"
|
|
command -v git >/dev/null 2>&1 || die "git 이 필요합니다."
|
|
local tmp; tmp="$(mktemp -d)"
|
|
git clone -q --depth 1 -b "$BRANCH" "$REPO.git" "$tmp/s" \
|
|
|| { rm -rf "$tmp"; die "스타터 클론 실패 — 네트워크/레포 공개 여부 확인 ($REPO)"; }
|
|
rm -rf "$tmp/s/.git"
|
|
cp -R "$tmp/s/." .
|
|
rm -rf "$tmp"
|
|
[ -n "$name" ] && [ -f yakcloud.yaml ] && { sed -i.bak "s/^project: .*/project: $name/" yakcloud.yaml && rm -f yakcloud.yaml.bak; }
|
|
git rev-parse --git-dir >/dev/null 2>&1 || git init -q
|
|
echo "✓ 초기화 완료 ($(pwd))"
|
|
echo " 다음: yakcloud project info · yakcloud domain … · yakcloud project deploy v0.1.0"
|
|
}
|
|
|
|
cmd_project_deploy() {
|
|
[ -f yakcloud.yaml ] || die "yakcloud.yaml 없음 — 'yakcloud project init' 먼저"
|
|
git rev-parse --git-dir >/dev/null 2>&1 || git init -q
|
|
git remote get-url origin >/dev/null 2>&1 \
|
|
|| die "git 원격(origin) 없음 — Gitea 레포 만들어 'git remote add origin <url>' + Secrets 설정 후 다시"
|
|
git fetch -q --tags origin 2>/dev/null || true
|
|
# 버전: 인자 있으면 그것, 없으면 최신 v* 태그에서 패치 +1(없으면 v0.1.0) — 배포마다 자동 버전업.
|
|
local ver="${1:-}"
|
|
if [ -z "$ver" ]; then
|
|
local last; last="$(git tag -l 'v*' --sort=-v:refname 2>/dev/null | head -1)"
|
|
if [ -n "$last" ]; then
|
|
ver="$(printf '%s' "$last" | awk -F. 'BEGIN{OFS="."} {$NF=$NF+1; print}')"
|
|
else
|
|
ver="v0.1.0"
|
|
fi
|
|
fi
|
|
case "$ver" in v*) : ;; *) ver="v$ver" ;; esac
|
|
info "배포 버전: $ver (커밋 + 태그 push)"
|
|
git add -A; git commit -q -m "deploy $ver" 2>/dev/null || true
|
|
git push -q origin HEAD 2>/dev/null || true
|
|
git tag "$ver" 2>/dev/null || die "태그 $ver 이미 존재 — 'yakcloud project deploy <다음버전>'"
|
|
git push -q origin "$ver"
|
|
echo "✓ $ver push — Gitea Actions 에서 빌드·배포. 콘솔 앱 탭/도메인 확인."
|
|
}
|
|
|
|
cmd_project_check() {
|
|
[ -f scripts/yakcloud_deploy.py ] || die "'yakcloud project init' 먼저"
|
|
: "${YAKCLOUD_URL:?YAKCLOUD_URL 필요}"; : "${YAKCLOUD_TOKEN:?YAKCLOUD_TOKEN 필요}"
|
|
ensure_pyyaml
|
|
python3 scripts/yakcloud_deploy.py yakcloud.yaml --dry-run
|
|
}
|
|
|
|
# 전역 CLI 자기 갱신 — 버전이 같아도 항상 최신 파일을 강제로 다시 받아 덮어쓴다(캐시 우회).
|
|
cmd_upgrade() {
|
|
local self; self="$(command -v yakcloud 2>/dev/null || true)"; [ -n "$self" ] || self="$0"
|
|
# 심볼릭 링크면 실체 파일을 갱신.
|
|
if [ -L "$self" ]; then self="$(readlink -f "$self" 2>/dev/null || readlink "$self" 2>/dev/null || echo "$self")"; fi
|
|
local before; before="$("$self" version 2>/dev/null || echo '?')"
|
|
info "yakcloud CLI 강제 갱신… ($self, 현재 $before)"
|
|
local tmp; tmp="$(mktemp)"
|
|
# 캐시 우회: no-cache 헤더 + 캐시버스터 쿼리. Gitea/프록시가 raw 를 캐시해도 항상 최신 획득.
|
|
local bust; bust="$(date +%s 2>/dev/null || echo 0)"
|
|
curl -fsSL -H 'Cache-Control: no-cache' -H 'Pragma: no-cache' \
|
|
"$REPO/raw/branch/$BRANCH/bin/yakcloud?nocache=$bust" -o "$tmp" \
|
|
|| { rm -f "$tmp"; die "다운로드 실패"; }
|
|
head -1 "$tmp" | grep -q 'bash' || { rm -f "$tmp"; die "받은 파일이 올바르지 않습니다"; }
|
|
chmod +x "$tmp"
|
|
mv "$tmp" "$self" 2>/dev/null || { rm -f "$tmp"; die "설치 실패(권한) — 'DEST=<dir> 재설치' 또는 sudo"; }
|
|
hash -r 2>/dev/null || true # 셸 명령 해시 캐시 초기화(새 바이너리 즉시 반영)
|
|
echo "✓ 업그레이드 완료: $before → $("$self" version 2>/dev/null || echo yakcloud)"
|
|
}
|
|
|
|
# 기존 프로젝트의 플러밍(엔진·CI·스킬)만 최신화. 앱/매니페스트/Dockerfile 등 사용자 파일은 보존.
|
|
cmd_project_update() {
|
|
[ -f yakcloud.yaml ] || die "프로젝트 폴더가 아닙니다 — 'yakcloud project init' 먼저"
|
|
command -v git >/dev/null 2>&1 || die "git 이 필요합니다."
|
|
info "프로젝트 플러밍 최신화(앱·매니페스트 보존)… ($REPO @ $BRANCH)"
|
|
local tmp; tmp="$(mktemp -d)"
|
|
git clone -q --depth 1 -b "$BRANCH" "$REPO.git" "$tmp/s" || { rm -rf "$tmp"; die "클론 실패"; }
|
|
mkdir -p scripts .gitea/workflows .claude/skills
|
|
cp "$tmp/s/scripts/yakcloud_deploy.py" scripts/ 2>/dev/null || true
|
|
cp "$tmp/s/scripts/yakcloud_ctl.py" scripts/ 2>/dev/null || true
|
|
cp "$tmp/s/.gitea/workflows/deploy.yml" .gitea/workflows/ 2>/dev/null || true
|
|
cp "$tmp/s/DATA-SOURCES.md" DATA-SOURCES.md 2>/dev/null || true
|
|
rm -rf .claude/skills/yakcloud-deploy
|
|
cp -R "$tmp/s/.claude/skills/yakcloud-deploy" .claude/skills/ 2>/dev/null || true
|
|
rm -rf "$tmp"
|
|
echo "✓ 최신화 완료 — scripts/·.gitea/·.claude 스킬 갱신(app.py·yakcloud.yaml·Dockerfile 그대로)"
|
|
}
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
yakcloud $VERSION — YakCloud 프로젝트 CLI
|
|
project init [name] 빈 폴더에 스타터 스캐폴딩(앱+CI+매니페스트+Claude 스킬)
|
|
project deploy [vX.Y.Z] 커밋 + 태그 push → Gitea Actions 자동 배포(버전 생략=자동 버전업)
|
|
project info 프로젝트 개괄(매니페스트 + 라이브 상태)
|
|
project check dry-run(직접 API 계획만)
|
|
project update 이 프로젝트의 엔진·CI·스킬만 최신화(앱·매니페스트 보존)
|
|
upgrade 전역 yakcloud CLI 자기 갱신(최신 버전으로)
|
|
── 배포환경 설정(앱별) ──
|
|
domain <fqdn> [wl] 도메인 등록 + 워크로드 할당(관리형=즉시/배포중이면 라이브)
|
|
scale <wl> <n> replicas 변경
|
|
set <wl> --image/--port/--health/--cpu/--mem/--path/--rewrite
|
|
env <wl> KEY=VAL … [--secret KEY] [--unset KEY]
|
|
source add <name> <type> [plan] | source rm <name>
|
|
bind <wl> <source> <alias> | unbind <wl> <alias>
|
|
env: YAKCLOUD_URL, YAKCLOUD_TOKEN(배포토큰 yakd_…), (선택) YAKCLOUD_CLUSTER
|
|
EOF
|
|
}
|
|
|
|
case "${1:-help}" in
|
|
project)
|
|
shift
|
|
case "${1:-}" in
|
|
init) shift; cmd_project_init "$@" ;;
|
|
deploy) shift; cmd_project_deploy "$@" ;;
|
|
info) shift; ctl info "$@" ;;
|
|
check|dry-run) shift; cmd_project_check "$@" ;;
|
|
update) shift; cmd_project_update "$@" ;;
|
|
*) echo "yakcloud project <init|deploy|info|check|update>"; exit 1 ;;
|
|
esac ;;
|
|
domain|scale|set|env|source|bind|unbind) ctl "$@" ;;
|
|
upgrade|self-update) cmd_upgrade ;;
|
|
version|-v|--version) echo "yakcloud $VERSION" ;;
|
|
help|-h|--help|"") usage ;;
|
|
*) echo "알 수 없는 명령: $1"; echo; usage; exit 1 ;;
|
|
esac
|