Compare commits

..

No commits in common. "high-performance" and "main" have entirely different histories.

7 changed files with 263 additions and 196 deletions

View file

@ -1,105 +0,0 @@
name: build-and-release
on:
push:
branches:
- main
- high-performance
concurrency:
group: admin-solid-build-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: self-hosted
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Docker Buildx
run: |
set -euo pipefail
docker version
docker buildx create --use --name nxtgauge-builder || docker buildx use nxtgauge-builder
docker buildx inspect --bootstrap
- name: Login to registry
env:
REGISTRY_HOSTPORT: ${{ secrets.REGISTRY_HOSTPORT }}
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
run: |
set -euo pipefail
test -n "$REGISTRY_HOSTPORT"
printf '%s' "$REGISTRY_PASSWORD" | docker login "$REGISTRY_HOSTPORT" -u "$REGISTRY_USERNAME" --password-stdin
- name: Build and push image
env:
REGISTRY_HOSTPORT: ${{ secrets.REGISTRY_HOSTPORT }}
SHA: ${{ github.sha }}
run: |
set -euo pipefail
metadata_file="/tmp/admin-solid-metadata.json"
image_ref="$REGISTRY_HOSTPORT/nxtgauge-admin-solid:$SHA"
docker buildx build --push \
--metadata-file "$metadata_file" \
-f Dockerfile \
-t "$image_ref" \
.
digest="$(grep -o '"containerimage.digest":"sha256:[^"]*"' "$metadata_file" | cut -d'"' -f4)"
test -n "$digest"
printf '%s@%s\n' "$REGISTRY_HOSTPORT/nxtgauge-admin-solid" "$digest" > /tmp/admin-solid-image-ref.txt
- name: Prune old SHA tags
if: success()
continue-on-error: true
env:
REGISTRY_HOST: ${{ secrets.REGISTRY_HOSTPORT }}
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
run: |
set -euo pipefail
python3 .forgejo/scripts/registry_prune.py \
--registry "$REGISTRY_HOST" \
--repo "nxtgauge-admin-solid" \
--username "$REGISTRY_USERNAME" \
--password "$REGISTRY_PASSWORD" \
--keep 2
- name: Update GitOps release
env:
GITEOPS_REPO: ${{ secrets.GITEOPS_REPO }}
GITEOPS_SSH_KEY: ${{ secrets.GITEOPS_SSH_KEY }}
SHA: ${{ github.sha }}
run: |
set -euo pipefail
test -n "$GITEOPS_REPO"
test -n "$GITEOPS_SSH_KEY"
mkdir -p ~/.ssh
printf '%s\n' "$GITEOPS_SSH_KEY" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan github.com >> ~/.ssh/known_hosts 2>/dev/null
GITEOPS_DIR=$(mktemp -d)
git clone "$GITEOPS_REPO" "$GITEOPS_DIR"
cd "$GITEOPS_DIR"
image_ref="$(cat /tmp/admin-solid-image-ref.txt)"
./scripts/set-app-release.sh admin-solid "$image_ref"
if git diff --quiet; then
echo "GitOps repo already up to date."
exit 0
fi
git config user.name "forgejo-actions[bot]"
git config user.email "forgejo-actions@ci.nxtgauge.com"
git add apps scripts/set-app-release.sh
git commit -m "chore(gitops): deploy admin-solid@${SHA}"
git push

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

@ -1,4 +1,4 @@
name: Build Admin And Update GitOps
name: build-and-push
on:
push:
@ -15,57 +15,79 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Install Docker CLI
- name: Set up Docker Buildx
run: |
apt-get update
apt-get install -y docker.io
export DOCKER_HOST=unix:///var/run/docker.sock
docker version
docker buildx create --use || true
docker buildx inspect --bootstrap
- name: Log in to registry
run: |
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login registry.nxtgauge.com -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
- name: Build and push admin image
run: |
set -euo pipefail
IMAGE="registry.nxtgauge.com/nxtgauge-admin-solid:${{ github.sha }}"
docker build -t "${IMAGE}" -t registry.nxtgauge.com/nxtgauge-admin-solid:latest .
docker push "${IMAGE}"
docker push registry.nxtgauge.com/nxtgauge-admin-solid:latest
update-gitops:
needs: build
runs-on: ubuntu-latest
steps:
- name: Update GitOps admin tag
- name: Login to Registry
env:
GITOPS_USERNAME: ${{ secrets.GITOPS_GITHUB_USERNAME || 'Traceworks2023' }}
GITOPS_PASSWORD: ${{ secrets.GITOPS_GITHUB_TOKEN || secrets.GITOPS_PAT }}
GITOPS_REPO: https://github.com/Traceworks2023/nxtgauge-gitops.git
IMAGE_TAG: ${{ github.sha }}
REGISTRY_HOSTPORT: ${{ secrets.REGISTRY_HOSTPORT }}
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
run: |
set -euo pipefail
test -n "${GITOPS_PASSWORD:-}" || { echo "GITOPS_PASSWORD is empty"; exit 1; }
AUTH="$(printf '%s' "${GITOPS_USERNAME}:${GITOPS_PASSWORD}" | base64 -w0)"
TMP_DIR="$(mktemp -d)"
git -c http.extraHeader="AUTHORIZATION: basic ${AUTH}" clone --branch main "${GITOPS_REPO}" "${TMP_DIR}"
cd "${TMP_DIR}"
python3 - <<'PY'
from pathlib import Path
import os
path = Path('apps/nxtgauge-admin-solid/overlays/prod/kustomization.yaml')
lines = path.read_text().splitlines()
out = []
for line in lines:
if line.strip().startswith('newTag:'):
indent = line[:len(line) - len(line.lstrip())]
out.append(f"{indent}newTag: {os.environ['IMAGE_TAG']}")
else:
out.append(line)
path.write_text('\n'.join(out) + '\n')
PY
git config user.name "forgejo-actions"
git config user.email "forgejo-actions@nxtgauge.com"
git add apps/nxtgauge-admin-solid/overlays/prod/kustomization.yaml
git diff --cached --quiet && exit 0
git commit -m "chore(gitops): update admin image to ${IMAGE_TAG}"
git -c http.extraHeader="AUTHORIZATION: basic ${AUTH}" push origin main
export DOCKER_HOST=unix:///var/run/docker.sock
test -n "$REGISTRY_HOSTPORT"
echo "$REGISTRY_PASSWORD" | docker login "$REGISTRY_HOSTPORT" -u "$REGISTRY_USERNAME" --password-stdin
- name: Build and push
env:
REGISTRY_HOSTPORT: ${{ secrets.REGISTRY_HOSTPORT }}
run: |
set -euo pipefail
export DOCKER_HOST=unix:///var/run/docker.sock
docker buildx build --push \
-f Dockerfile \
-t "$REGISTRY_HOSTPORT/nxtgauge-admin-solid:${{ gitea.sha }}" \
-t "$REGISTRY_HOSTPORT/nxtgauge-admin-solid:high-performance-latest" \
.
- name: Prune old image tags (keep latest 1 SHA)
if: success()
continue-on-error: true
env:
REGISTRY_HOST: ${{ secrets.REGISTRY_HOSTPORT }}
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
run: |
set -euo pipefail
python3 .gitea/scripts/registry_prune.py \
--registry "$REGISTRY_HOST" \
--repo "nxtgauge-admin-solid" \
--username "$REGISTRY_USERNAME" \
--password "$REGISTRY_PASSWORD" \
--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
if [ -z "$GITEOPS_REPO" ]; then
echo "GITEOPS_REPO secret not set, skipping GitOps update"
exit 0
fi
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 "admin-solid" \
--sha "${{ gitea.sha }}" \
--message "chore: deploy admin-solid@${{ gitea.sha }}"
rm -rf "$GITEOPS_DIR"

View file

@ -1,40 +0,0 @@
name: sync-to-forgejo
on:
push:
branches:
- main
- high-performance
jobs:
sync:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Push branch to Forgejo
env:
FORGEJO_SECRET: ${{ secrets.FORGEJO_SECRET || secrets.GITEA_SECRET }}
FORGEJO_OWNER: ${{ secrets.FORGEJO_OWNER || 'ashwin' }}
FORGEJO_USERNAME: ${{ secrets.FORGEJO_USERNAME || secrets.GITEA_USERNAME || 'ashwin' }}
REPO: ${{ github.event.repository.name }}
BRANCH: ${{ github.ref_name }}
run: |
set -euo pipefail
test -n "${FORGEJO_SECRET:-}" || { echo "FORGEJO_SECRET is empty"; exit 1; }
AUTH="$(printf '%s' "${FORGEJO_USERNAME}:${FORGEJO_SECRET}" | base64 -w0)"
TARGET="https://ci.nxtgauge.com/${FORGEJO_OWNER}/${REPO}.git"
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git remote remove forgejo 2>/dev/null || true
git remote add forgejo "${TARGET}"
git -c http.extraHeader="AUTHORIZATION: basic ${AUTH}" push forgejo "HEAD:${BRANCH}" --force
git -c http.extraHeader="AUTHORIZATION: basic ${AUTH}" push forgejo --tags --force

46
.github/workflows/sync-to-gitea.yml vendored Normal file
View file

@ -0,0 +1,46 @@
name: sync-to-gitea
on:
push:
branches:
- high-performance
jobs:
sync:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Sync to Gitea
env:
GITEA_TOKEN: ${{ secrets.GITEA_SECRET }}
REPO: ${{ github.event.repository.name }}
BRANCH: ${{ github.ref_name }}
run: |
set -euxo pipefail
export GIT_TERMINAL_PROMPT=0
export GIT_TRACE=1
export GIT_CURL_VERBOSE=1
USER="Admin"
TARGET="https://ci.nxtgauge.com/Admin/${REPO}.git"
AUTH="$(printf '%s' "${USER}:${GITEA_TOKEN}" | base64 -w0)"
test -n "${GITEA_TOKEN:-}" || (echo "GITEA_TOKEN empty" && exit 1)
curl -fsS -H "Authorization: token ${GITEA_TOKEN}" https://ci.nxtgauge.com/api/v1/user >/dev/null
curl -fsS -H "Authorization: Basic ${AUTH}" "${TARGET}/info/refs?service=git-receive-pack" >/dev/null
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git config --global http.version HTTP/1.1
git config --global http.postBuffer 524288000
git remote remove gitea 2>/dev/null || true
git remote add gitea "${TARGET}"
git -c http.extraheader="Authorization: Basic ${AUTH}" push gitea "HEAD:${BRANCH}" --force
git -c http.extraheader="Authorization: Basic ${AUTH}" push gitea --tags --force

View file

@ -43,4 +43,3 @@ Run additional isolated instances (`9103`, `9104`, ...):
docker run -d --name nxtgauge-admin-solid-9103 -p 9103:9202 nxtgauge-admin-solid:local
docker run -d --name nxtgauge-admin-solid-9104 -p 9104:9202 nxtgauge-admin-solid:local
```
# Mon Jun 8 09:22:40 PM IST 2026