From 451c21c4c4d12705bae7448ef1a775db089b39b7 Mon Sep 17 00:00:00 2001 From: jungwoo choi Date: Sun, 30 Aug 2026 14:40:41 +0900 Subject: [PATCH] =?UTF-8?q?fix(cli):=20project=20init=20.=20=E2=80=94=20?= =?UTF-8?q?=ED=8F=B4=EB=8D=94=EB=AA=85=EC=9C=BC=EB=A1=9C=20=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=20=EC=9C=A0=EB=8F=84=20+=20=EC=9D=B4=EB=A6=84=20?= =?UTF-8?q?=EC=A0=95=EA=B7=9C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- bin/yakcloud | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/bin/yakcloud b/bin/yakcloud index 789841d..8b355c8 100755 --- a/bin/yakcloud +++ b/bin/yakcloud @@ -146,9 +146,17 @@ cmd_config() { cmd_logout() { rm -f "$CONFIG_FILE"; secret_del YAKCLOUD_TOKEN; secret_del GITEA_TOKEN; echo "✓ 자격 삭제(설정 파일 + 키체인)"; } +# 프로젝트/워크로드/이미지에 안전한 이름 — 소문자, 영숫자·하이픈만, 앞뒤 하이픈 제거, 폴백 app. +_sanitize_name() { + local s; s="$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]' | tr -cs 'a-z0-9-' '-' | sed 's/^-*//; s/-*$//')" + printf '%s' "${s:-app}" +} + cmd_project_init() { local name="" noninteractive=0 for a in "$@"; do case "$a" in -y|--yes|--no-wizard) noninteractive=1 ;; *) [ -z "$name" ] && name="$a" ;; esac; done + # "." / "./" = 현재 폴더에 초기화(이름은 폴더명에서 유도) — 디렉터리 기호가 이름으로 박히지 않도록. + case "$name" in .|./) name="" ;; esac [ -n "$name" ] && { mkdir -p "$name"; cd "$name"; } if [ -n "$(ls -A . 2>/dev/null | grep -v '^\.git$' || true)" ]; then die "폴더가 비어있지 않습니다. 빈 폴더에서 실행하거나 'yakcloud project init '." @@ -166,14 +174,18 @@ cmd_project_init() { rm -rf bin install.sh .yakcloud .claude README.md DATA-SOURCES.md # 전역 엔진/스킬/명령 준비(최초 init 시에도 보장). install_global_assets 2>/dev/null || true - # 프로젝트명을 project·워크로드(배포)명·image 에 일괄 반영(고정 'web' 대신 프로젝트명). - [ -n "$name" ] && [ -f yakcloud.yaml ] && { sed -i.bak "s/my-app/$name/g" yakcloud.yaml && rm -f yakcloud.yaml.bak; } + # 프로젝트명 = 지정 이름 or 현재 폴더명 → K8s/이미지 안전하게 정규화(소문자·영숫자·하이픈). + local proj; proj="$(_sanitize_name "${name:-$(basename "$(pwd)")}")" git rev-parse --git-dir >/dev/null 2>&1 || git init -q echo "✓ 스캐폴딩 완료 ($(pwd))" # 대화형 마법사(TTY + not --yes): 클러스터·앱·포트·헬스·CPU·메모리·replicas·env 를 물어 매니페스트에 반영. + # 마법사가 이름을 확정하므로 여기서 선-sed 하지 않는다(하면 my-app 이 먼저 치환돼 마법사의 재치환이 no-op → 이중 sed 클로버). if [ "$noninteractive" = 0 ] && [ -t 0 ]; then - _init_wizard "${name:-$(basename "$(pwd)")}" + _init_wizard "$proj" _maybe_login_prompt + else + # 비대화형(마법사 미실행): project·워크로드(배포)명·image 를 정규화된 프로젝트명으로 일괄 반영. + [ -f yakcloud.yaml ] && { sed -i.bak "s/my-app/$proj/g" yakcloud.yaml && rm -f yakcloud.yaml.bak; } fi echo " 다음: yakcloud project info · yakcloud domain · yakcloud project deploy" } @@ -182,7 +194,7 @@ cmd_project_init() { _init_wizard() { local dflt_app="$1" app devc valc prodc pdom port health cpu mem reps path kv echo "── 프로젝트 설정 (엔터=기본값) · 개발 → 검증 → 운영 3단계 ──" - printf "앱 이름 [%s]: " "$dflt_app"; read -r app; app="${app:-$dflt_app}" + printf "앱 이름 [%s]: " "$dflt_app"; read -r app; app="$(_sanitize_name "${app:-$dflt_app}")" printf "개발 클러스터(이름 또는 콘솔 id): "; read -r devc printf "검증 클러스터(선택, 엔터=생략): "; read -r valc printf "운영 클러스터 [%s]: " "${devc:-개발과 동일}"; read -r prodc; prodc="${prodc:-$devc}"