ci: update gitops with new SHA on each build (auto-deploy)

This commit is contained in:
Tracewebstudio Dev 2026-05-01 11:04:27 +02:00
parent 6e0339e6a1
commit a27301fe36
2 changed files with 171 additions and 0 deletions

View file

@ -0,0 +1,145 @@
#!/usr/bin/env python3
"""
Update GitOps kustomization.yaml with new image SHA tags.
Usage:
python3 update-gitops.py \
--repo /path/to/nxtgauge-gitops \
--service gateway \
--sha abc123def456...
This script:
1. Updates the newTag for the specified service to the SHA
2. Commits and pushes to the gitops repo
3. ArgoCD detects the change and deploys
"""
import argparse
import os
import re
import subprocess
import sys
def run(cmd: list[str], cwd: str = None) -> tuple[int, str, str]:
"""Run a command and return (returncode, stdout, stderr)."""
result = subprocess.run(cmd, cwd=cwd, capture_output=True, text=True)
return result.returncode, result.stdout, result.stderr
def update_kustomization(kustomization_path: str, service: str, sha: str) -> bool:
"""Update the newTag for a service in kustomization.yaml."""
with open(kustomization_path, "r") as f:
content = f.read()
# Pattern to find image entry for the service
# Matches: - name: registry.nxtgauge.com/nxtgauge-rust-{service}
# newTag: something
pattern = rf'(\s+-\s+name:\s+registry\.nxtgauge\.com/nxtgauge-rust-{re.escape(service)}\n\s+newTag:\s+)[^\n]+'
replacement = rf'\g<1>{sha}'
new_content, count = re.subn(pattern, replacement, content)
if count == 0:
# Try without the nxtgauge-rust- prefix (for frontend, admin, etc)
pattern = rf'(\s+-\s+name:\s+registry\.nxtgauge\.com/nxtgauge-{re.escape(service)}\n\s+newTag:\s+)[^\n]+'
new_content, count = re.subn(pattern, replacement, content)
if count == 0:
print(f"[ERROR] Could not find image entry for service: {service}")
return False
with open(kustomization_path, "w") as f:
f.write(new_content)
print(f"[OK] Updated {service} to SHA {sha}")
return True
def main():
parser = argparse.ArgumentParser(description="Update GitOps with new image SHA")
parser.add_argument("--repo", required=True, help="Path to gitops repo")
parser.add_argument("--service", required=True, help="Service name (e.g., gateway, users, frontend-solid)")
parser.add_argument("--sha", required=True, help="Git SHA to deploy")
parser.add_argument("--message", default=None, help="Commit message")
args = parser.parse_args()
service_image_map = {
"gateway": "nxtgauge-rust-gateway",
"users": "nxtgauge-rust-users",
"companies": "nxtgauge-rust-companies",
"jobs": "nxtgauge-rust-jobs",
"leads": "nxtgauge-rust-leads",
"job-seekers": "nxtgauge-rust-job-seekers",
"customers": "nxtgauge-rust-customers",
"payments": "nxtgauge-rust-payments",
"employees": "nxtgauge-rust-employees",
"photographers": "nxtgauge-rust-photographers",
"makeup-artists": "nxtgauge-rust-makeup-artists",
"tutors": "nxtgauge-rust-tutors",
"developers": "nxtgauge-rust-developers",
"video-editors": "nxtgauge-rust-video-editors",
"graphic-designers": "nxtgauge-rust-graphic-designers",
"social-media-managers": "nxtgauge-rust-social-media-managers",
"fitness-trainers": "nxtgauge-rust-fitness-trainers",
"catering-services": "nxtgauge-rust-catering-services",
"ugc-content-creators": "nxtgauge-rust-ugc-content-creators",
"cron": "nxtgauge-rust-cron",
"frontend-solid": "nxtgauge-frontend-solid",
"admin-solid": "nxtgauge-admin-solid",
"ai-assistant": "nxtgauge-ai-assistant",
}
# Determine which kustomization file to update
if service_image_map.get(args.service):
image_name = service_image_map[args.service]
else:
image_name = f"nxtgauge-{args.service}"
# Find the right kustomization file based on service
if "frontend" in args.service or "admin" in args.service:
kustomization_path = os.path.join(args.repo, "apps/nxtgauge-frontend-solid/overlays/prod/kustomization.yaml")
if not os.path.exists(kustomization_path):
kustomization_path = os.path.join(args.repo, "apps/nxtgauge-frontend-solid/base/kustomization.yaml")
elif "ai-assistant" in args.service:
kustomization_path = os.path.join(args.repo, "apps/nxtgauge-ai-assistant/overlays/prod/kustomization.yaml")
if not os.path.exists(kustomization_path):
kustomization_path = os.path.join(args.repo, "apps/nxtgauge-ai-assistant/base/kustomization.yaml")
else:
kustomization_path = os.path.join(args.repo, "apps/nxtgauge-backend-rust/overlays/prod/kustomization.yaml")
if not os.path.exists(kustomization_path):
print(f"[ERROR] Kustomization file not found: {kustomization_path}")
sys.exit(0) # Exit 0 per workflow requirement
print(f"Updating {kustomization_path} for service {args.service}")
if not update_kustomization(kustomization_path, args.service, args.sha):
sys.exit(0) # Exit 0 per workflow requirement
# Git add, commit, push
commit_msg = args.message or f"chore: deploy {args.service}@{args.sha}"
run(["git", "add", "-A"], cwd=args.repo)
code, stdout, stderr = run(["git", "diff", "--cached", "--stat"], cwd=args.repo)
if not stdout.strip():
print("[INFO] No changes to commit")
sys.exit(0)
print(f"Changes to commit:\n{stdout}")
run(["git", "commit", "-m", commit_msg], cwd=args.repo)
code, stdout, stderr = run(["git", "push"], cwd=args.repo)
if code != 0:
print(f"[ERROR] Push failed: {stderr}")
else:
print(f"[OK] Pushed update to gitops repo")
sys.exit(0) # Always exit 0 per workflow requirement
if __name__ == "__main__":
main()

View file

@ -60,3 +60,29 @@ jobs:
--username "$REGISTRY_USERNAME" \ --username "$REGISTRY_USERNAME" \
--password "$REGISTRY_PASSWORD" \ --password "$REGISTRY_PASSWORD" \
--keep 1 --keep 1
- name: Update GitOps and trigger deployment
if: success()
continue-on-error: true
env:
GITEOPS_REPO: ${{ secrets.GITEOPS_REPO }}
GITEOPS_SSH_KEY: ${{ secrets.GITEOPS_SSH_KEY }}
run: |
set -euo pipefail
GITEOPS_DIR=$(mktemp -d)
git clone "$GITEOPS_REPO" "$GITEOPS_DIR"
cd "$GITEOPS_DIR"
mkdir -p ~/.ssh
echo "$GITEOPS_SSH_KEY" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan github.com >> ~/.ssh/known_hosts 2>/dev/null
python3 .gitea/scripts/update-gitops.py \
--repo "$GITEOPS_DIR" \
--service "ai-assistant" \
--sha "${{ gitea.sha }}" \
--message "chore: deploy ai-assistant@${{ gitea.sha }}"
rm -rf "$GITEOPS_DIR"