"""workspace/ → repos/ 동기화 후 Gitea push""" import subprocess, shutil, os, sys, paramiko, json, base64 sys.stdout.reconfigure(encoding='utf-8', errors='replace') EXCLUDE = {'.git', '__pycache__', 'node_modules', '.expo', 'dist', 'build', 'target', '*.db', '*.pyc', '.env'} def should_skip(name): if name.startswith('.'): return False # .env 등 포함 for pat in EXCLUDE: if pat.startswith('*'): if name.endswith(pat[1:]): return True elif name == pat: return True return False def sync_dir(src, dst): """src → dst 파일 동기화 (dst의 .git 보존)""" added, updated = 0, 0 # dst에 없는 파일 / 오래된 파일 복사 for root, dirs, files in os.walk(src): # 제외 폴더 dirs[:] = [d for d in dirs if d not in EXCLUDE and not d.endswith('.egg-info')] rel_root = os.path.relpath(root, src) dst_root = os.path.join(dst, rel_root) if rel_root != '.' else dst os.makedirs(dst_root, exist_ok=True) for f in files: if f.endswith(('.pyc', '.db', '.db-journal')): continue s = os.path.join(root, f) d = os.path.join(dst_root, f) try: if not os.path.exists(d): shutil.copy2(s, d); added += 1 elif os.path.getmtime(s) > os.path.getmtime(d): shutil.copy2(s, d); updated += 1 except: pass return added, updated def git(path, *args, check=False): r = subprocess.run(['git', '-C', path] + list(args), capture_output=True, text=True, encoding='utf-8', errors='replace') return r.stdout.strip(), r.returncode REPOS = ['guardia-itsm', 'guardia-manager', 'guardia-docs', 'zioinfo-web', 'guardia-messenger'] BASE_W = 'C:/GUARDiA/workspace' BASE_R = 'C:/GUARDiA/repos' # Gitea API 업로드용 클라이언트 ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect('101.79.17.164', username='root', password='1q2w3e!Q', timeout=15) def gitea_push_bundle(repo): """bundle → 서버 → Gitea push""" local = f'{BASE_R}/{repo}' bundle = f'{BASE_R}/{repo}.bundle' sftp = ssh.open_sftp() print(f' bundle 생성 중...') subprocess.run(['git', '-C', local, 'bundle', 'create', bundle, '--all'], capture_output=True, timeout=120) size = os.path.getsize(bundle) // 1024 print(f' 크기: {size}KB → 서버 전송...') sftp.put(bundle, f'/tmp/{repo}.bundle') sftp.close() os.remove(bundle) def srv(cmd, t=60): _, o, e = ssh.exec_command(cmd, timeout=t) return o.read().decode('utf-8','replace').strip() result = srv(f""" rm -rf /tmp/{repo}_push git clone /tmp/{repo}.bundle /tmp/{repo}_push 2>/dev/null cd /tmp/{repo}_push git remote set-url origin 'http://zio:Zio%40Admin2026%21@127.0.0.1:9003/zio/{repo}.git' git push origin main --force 2>&1 | tail -3 rm -rf /tmp/{repo}_push /tmp/{repo}.bundle echo "DONE" """, t=120) return 'DONE' in result, result print('=== workspace → repos 동기화 ===\n') for repo in REPOS: src = f'{BASE_W}/{repo}' dst = f'{BASE_R}/{repo}' if not os.path.isdir(src): print(f'[{repo}] workspace 없음, skip') continue print(f'[{repo}]') added, updated = sync_dir(src, dst) print(f' sync: +{added} 추가, {updated} 갱신') # git 상태 확인 out, _ = git(dst, 'status', '--short') if not out: print(' 변경 없음') continue changed = len(out.splitlines()) print(f' 변경 파일: {changed}개') git(dst, 'add', '-A') msg = f'sync: update from workspace (latest ITSM/CICD/DR changes)' git(dst, 'commit', '-m', msg) print(' Gitea push 중...') ok, log = gitea_push_bundle(repo) if ok: print(f' ✅ push 완료') else: print(f' ❌ push 실패: {log[:200]}') ssh.close() print('\n=== 동기화 완료 ===')