Files
gitlab-instance-0a899031_no…/deploy/observability/sync_and_deploy_ops.py

198 lines
6.1 KiB
Python

#!/usr/bin/env python3
"""Commit & push dirty repos (local + server) with eric credentials, deploy douyinWEB ops."""
from __future__ import annotations
import os
import subprocess
import time
from pathlib import Path
import paramiko
HOST = "107.173.30.245"
PASS = "Xiao4669805"
GIT_USER = "eric"
GIT_PASS = "Xiao4669805"
AUTH = f"{GIT_USER}:{GIT_PASS}@"
DOUYIN = Path(r"C:\Users\admin\Desktop\douyinWEB")
NOMADRO = Path(r"C:\project\gitlab-instance-0a899031_nomadro")
def local(cmd: list[str] | str, cwd: Path) -> str:
print(f"\n[{cwd.name}] $", cmd if isinstance(cmd, str) else " ".join(cmd))
r = subprocess.run(
cmd,
cwd=str(cwd),
shell=isinstance(cmd, str),
capture_output=True,
text=True,
encoding="utf-8",
errors="replace",
)
out = (r.stdout or "") + (r.stderr or "")
print(out[-3000:] if len(out) > 3000 else out)
if r.returncode != 0:
raise RuntimeError(f"cmd failed in {cwd}: {cmd}\n{out}")
return out
def ensure_auth_remote(cwd: Path) -> None:
url = local(["git", "remote", "get-url", "origin"], cwd).strip()
if "gitea.dsx2020.com" in url and AUTH not in url:
if url.startswith("https://"):
new = url.replace("https://", f"https://{AUTH}", 1)
# strip existing userinfo
if "@gitea" in url:
new = "https://" + AUTH + url.split("@", 1)[1]
local(["git", "remote", "set-url", "origin", new], cwd)
def commit_push_local(cwd: Path, paths: list[str], message: str) -> None:
ensure_auth_remote(cwd)
local(["git", "add", *paths], cwd)
st = local(["git", "status", "--porcelain"], cwd)
if not st.strip():
print(f"[{cwd.name}] nothing to commit")
# still try push in case ahead
local(["git", "push", "-u", "origin", "HEAD"], cwd)
return
local(["git", "commit", "-m", message], cwd)
local(["git", "push", "-u", "origin", "HEAD"], cwd)
def main() -> None:
# 1) Local douyinWEB — ops page
commit_push_local(
DOUYIN,
[
"frontend/src/app/ops/page.tsx",
"frontend/src/components/Shell.tsx",
"frontend/src/app/layout.tsx",
"backend/app/ops_panel.py",
"backend/app/notify.py",
"backend/app/main.py",
],
"feat(ops): Umami/ntfy/DNS 运维控制台页面与 API",
)
# 2) Local nomadro — observability stack
commit_push_local(
NOMADRO,
[
"app/layout.tsx",
"components/umami-analytics.tsx",
"deploy/Caddyfile",
"deploy/README.md",
"deploy/caddy-sites",
"deploy/umami",
"deploy/ntfy",
"deploy/observability",
"deploy/router",
"deploy/wordpress",
"deploy/deploy.sh",
"deploy/setup-server.sh",
],
"feat: Umami/ntfy 可观测性栈与 WordPress AdSense 部署",
)
# 3) Server repos: commit layout umami injections + sync + deploy douyin
c = paramiko.SSHClient()
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
c.connect(HOST, username="root", password=PASS, timeout=30, allow_agent=False, look_for_keys=False)
def run(cmd: str, timeout: int = 600) -> str:
print("\n$ ", cmd[:160])
_i, o, e = c.exec_command(cmd, timeout=timeout)
out = (o.read() + e.read()).decode("utf-8", errors="replace")
print(out[-3500:] if len(out) > 3500 else out)
return out
# Ensure remotes have credentials
for repo in ("/opt/douyinWEB", "/opt/tiktokWEB", "/opt/wauto", "/var/www/nomadro.com"):
run(
f"""
cd {repo} || exit 0
url=$(git remote get-url origin 2>/dev/null || true)
[ -z "$url" ] && exit 0
case "$url" in
*{AUTH}*) ;;
https://*@gitea.dsx2020.com/*)
rest=$(echo "$url" | sed 's|https://[^@]*@|https://|')
git remote set-url origin "https://{AUTH}${{rest#https://}}"
;;
https://gitea.dsx2020.com/*)
git remote set-url origin "https://{AUTH}${{url#https://}}"
;;
esac
git remote -v | head -2
"""
)
# Pull douyin first then apply — better: push already done, pull on server
run(
"""
cd /opt/douyinWEB
git fetch origin
git stash push -u -m 'pre-ops-deploy' -- frontend/src/app/layout.tsx 2>/dev/null || true
git checkout test1
git pull --ff-only origin test1
""",
timeout=120,
)
# Commit other server-only dirty files (tiktok/wauto/nomadro layouts) if still dirty
run(
r"""
commit_if_dirty() {
local dir="$1"; local msg="$2"; shift 2
cd "$dir" || return 0
git add "$@" 2>/dev/null || true
if [ -n "$(git status --porcelain -- "$@" 2>/dev/null)" ]; then
git -c user.email=ops@nomadro.com -c user.name=ops commit -m "$msg" || true
git push origin HEAD || true
else
echo "$dir: clean for selected paths"
fi
}
commit_if_dirty /opt/tiktokWEB 'chore: inject Umami analytics tracker' frontend/src/app/layout.tsx
commit_if_dirty /opt/wauto 'chore: inject Umami analytics tracker' web/app/layout.tsx
commit_if_dirty /var/www/nomadro.com 'chore: Umami analytics component' app/layout.tsx components/umami-analytics.tsx
"""
)
# Deploy douyinWEB frontend + restart API
run(
"""
cd /opt/douyinWEB/frontend
# ensure umami env
grep -q '^NEXT_PUBLIC_UMAMI_WEBSITE_ID=' .env.local 2>/dev/null || echo 'NEXT_PUBLIC_UMAMI_WEBSITE_ID=f18d3484-be2e-4344-8882-b80c5b53f9cf' >> .env.local
npm run build
systemctl restart douyinweb-web
systemctl restart douyinweb-api
sleep 2
systemctl is-active douyinweb-web douyinweb-api
curl -fsS -o /dev/null -w 'ops_page:%{http_code}\\n' https://dylive.nomadro.com/ops || true
curl -fsS -o /dev/null -w 'ops_api:%{http_code}\\n' -H 'Cookie: ' https://dylive.nomadro.com/api/ops || true
""",
timeout=600,
)
# Sync nomadro.com from git if needed
run(
"""
cd /var/www/nomadro.com
git fetch origin
git pull --ff-only origin test || git pull --ff-only || true
# copy observability deploy assets already in repo; ensure router files synced if present
""",
timeout=120,
)
c.close()
print("\nALL DONE")
if __name__ == "__main__":
main()