117 lines
4.0 KiB
Python
117 lines
4.0 KiB
Python
"""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=== 동기화 완료 ===')
|