CLI 재구성: yakcloud project init/deploy/info/check + 설정동사(domain/scale/set/env/source/bind) + 자동 버전업 + yakcloud_ctl 엔진 + deploy CLI env 지원

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-27 17:22:44 +09:00
parent 8067507e6b
commit c161da3b65
9 changed files with 933 additions and 123 deletions

137
.claude/skills/yakcloud-deploy/assets/bin/yakcloud Normal file → Executable file
View File

@ -1,25 +1,47 @@
#!/usr/bin/env bash
# yakcloud — YakCloud 프로젝트 CLI. 빈 폴더 초기화(스타터+스킬) + 태그 push 자동배포.
# yakcloud init [name] 현재(빈) 폴더 또는 name/ 에 스타터 스캐폴딩(.claude 스킬 포함)
# yakcloud deploy [vX.Y.Z] 커밋 + 태그 push → Gitea Actions 자동 배포
# yakcloud check dry-run(직접 API, 계획만; YAKCLOUD_URL/TOKEN 필요)
# 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.1.0"
VERSION="0.2.0"
die() { echo "✗ $*" >&2; exit 1; }
die() { echo "✗ $*" >&2; exit 1; }
info() { echo "▸ $*"; }
cmd_init() {
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:-}"
if [ -n "$name" ]; then
mkdir -p "$name" && cd "$name"
fi
# 빈 폴더인지 확인(.git 은 허용)
[ -n "$name" ] && { mkdir -p "$name"; cd "$name"; }
if [ -n "$(ls -A . 2>/dev/null | grep -v '^\.git$' || true)" ]; then
die "폴더가 비어있지 않습니다. 빈 폴더에서 실행하거나 'yakcloud init <name>' 로 새 폴더에 생성하세요."
die "폴더가 비어있지 않습니다. 빈 폴더에서 실행하거나 'yakcloud project init <name>'."
fi
info "yakcloud-starter 내려받는 중… ($REPO @ $BRANCH)"
command -v git >/dev/null 2>&1 || die "git 이 필요합니다."
@ -27,55 +49,76 @@ cmd_init() {
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/." . # 숨김파일 포함 전부 현재 폴더로
cp -R "$tmp/s/." .
rm -rf "$tmp"
# 프로젝트 이름 치환(선택)
if [ -n "$name" ] && [ -f yakcloud.yaml ]; then
sed -i.bak "s/^project: .*/project: $name/" yakcloud.yaml && rm -f yakcloud.yaml.bak
fi
[ -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 " 다음:"
echo " 1) yakcloud.yaml 의 cluster / image(<GITEA_USER>) 수정, 필요하면 requires·binds 추가"
echo " 2) 앱 개발 (Claude Code 스킬: .claude/skills/yakcloud-deploy)"
echo " 3) Gitea 레포 연결 + Secrets(YAKCLOUD_URL/TOKEN/CLUSTER, REGISTRY_TOKEN) 설정"
echo " 4) yakcloud deploy v0.1.0"
echo " 다음: yakcloud project info · yakcloud domain … · yakcloud project deploy v0.1.0"
}
cmd_deploy() {
[ -f yakcloud.yaml ] || die "yakcloud.yaml 없음 — 먼저 'yakcloud init'"
local ver="${1:-v0.1.0}"
case "$ver" in v*) : ;; *) ver="v$ver" ;; esac
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 설정 다시 실행"
info "커밋 + 태그 $ver push…"
git add -A
git commit -q -m "deploy $ver" 2>/dev/null || true
|| 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 이미 존재 — 다른 버전으로"
git tag "$ver" 2>/dev/null || die "태그 $ver 이미 존재 — 'yakcloud project deploy <다음버전>'"
git push -q origin "$ver"
echo "✓ $ver push — Gitea Actions 에서 빌드·배포 진행. 콘솔 앱 탭/도메인에서 확인."
echo "✓ $ver push — Gitea Actions 에서 빌드·배포. 콘솔 앱 탭/도메인 확인."
}
cmd_check() {
[ -f scripts/yakcloud_deploy.py ] || die "scripts/yakcloud_deploy.py 없음 — 'yakcloud init' 먼저"
: "${YAKCLOUD_URL:?YAKCLOUD_URL 필요}"
: "${YAKCLOUD_TOKEN:?YAKCLOUD_TOKEN(배포 토큰) 필요}"
python3 -c "import yaml" 2>/dev/null || pip3 install --quiet pyyaml
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
}
case "${1:-help}" in
init) shift; cmd_init "$@" ;;
deploy) shift; cmd_deploy "$@" ;;
check|dry-run) shift; cmd_check "$@" ;;
version|-v|--version) echo "yakcloud $VERSION" ;;
*) cat <<EOF
usage() {
cat <<EOF
yakcloud $VERSION — YakCloud 프로젝트 CLI
yakcloud init [name] 빈 폴더에 스타터 스캐폴딩(앱+CI+매니페스트+Claude 스킬)
yakcloud deploy [vX.Y.Z] 커밋 + 태그 push → Gitea Actions 자동 배포
yakcloud check dry-run(직접 API 계획만; YAKCLOUD_URL/TOKEN 필요)
project init [name] 빈 폴더에 스타터 스캐폴딩(앱+CI+매니페스트+Claude 스킬)
project deploy [vX.Y.Z] 커밋 + 태그 push → Gitea Actions 자동 배포
project info 프로젝트 개괄(매니페스트 + 라이브 상태)
project check dry-run(직접 API 계획만)
── 배포환경 설정(앱별) ──
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 "$@" ;;
*) echo "yakcloud project <init|deploy|info|check>"; exit 1 ;;
esac ;;
domain|scale|set|env|source|bind|unbind) ctl "$@" ;;
version|-v|--version) echo "yakcloud $VERSION" ;;
help|-h|--help|"") usage ;;
*) echo "알 수 없는 명령: $1"; echo; usage; exit 1 ;;
esac