1+ name : Frontend - Build & Deploy
2+
3+ on :
4+ pull_request :
5+ branches : [ main ]
6+ push :
7+ branches : [ main ]
8+
9+ jobs :
10+ build-and-test :
11+ runs-on : ubuntu-latest
12+ env :
13+ VITE_API_URL : ${{ secrets.VITE_API_URL }}
14+ steps :
15+ - name : Checkout repository
16+ uses : actions/checkout@v4
17+
18+ - name : Use Node.js 24
19+ uses : actions/setup-node@v4
20+ with :
21+ node-version : ' 24.3.0'
22+ cache : ' npm'
23+ cache-dependency-path : ' web/package-lock.json'
24+
25+ - name : Install dependencies
26+ run : npm --prefix web ci --legacy-peer-deps
27+
28+ - name : Build (TS compile + Vite build)
29+ run : npm --prefix web run build
30+
31+ # Uncomment this if you want linting enabled
32+ # - name: Lint
33+ # run: npm --prefix web run lint
34+
35+ deploy :
36+ runs-on : ubuntu-latest
37+ needs : build-and-test
38+ if : github.event_name == 'push' && github.ref == 'refs/heads/main'
39+ env :
40+ VITE_API_URL : ${{ secrets.VITE_API_URL }}
41+ steps :
42+ - name : Checkout repository
43+ uses : actions/checkout@v4
44+
45+ - name : Use Node.js 24
46+ uses : actions/setup-node@v4
47+ with :
48+ node-version : ' 24.3.0'
49+ cache : ' npm'
50+ cache-dependency-path : ' web/package-lock.json'
51+
52+ - name : Install dependencies
53+ run : npm --prefix web ci --legacy-peer-deps
54+
55+ - name : Build (TS compile + Vite build)
56+ run : npm --prefix web run build
57+
58+ - name : Setup Python for upload step
59+ uses : actions/setup-python@v4
60+ with :
61+ python-version : ' 3.12.5'
62+
63+ - name : Install upload dependencies
64+ run : |
65+ python -m pip install --upgrade pip
66+ pip install requests
67+
68+ - name : Upload `dist` to hosting service
69+ env :
70+ UFAZIEN_HOSTING_BASE_URL : ${{ secrets.UFAZIEN_HOSTING_BASE_URL }}
71+ UFAZIEN_HOSTING_EMAIL : ${{ secrets.UFAZIEN_HOSTING_EMAIL }}
72+ UFAZIEN_HOSTING_PASSWORD : ${{ secrets.UFAZIEN_HOSTING_PASSWORD }}
73+ UFAZIEN_HOSTING_WEBSITE_ID : ${{ secrets.UFAZIEN_HOSTING_WEBSITE_ID }}
74+ shell : bash
75+ run : |
76+ set -euo pipefail
77+ cd web
78+
79+ if [ ! -d dist ]; then
80+ echo "❌ dist folder not found - nothing to upload"
81+ exit 1
82+ fi
83+
84+ echo "✅ dist folder found, starting upload..."
85+
86+ python3 <<'PYTHON_SCRIPT'
87+ import os, requests, glob
88+
89+ BASE = os.environ.get('UFAZIEN_HOSTING_BASE_URL')
90+ EMAIL = os.environ.get('UFAZIEN_HOSTING_EMAIL')
91+ PASSWORD = os.environ.get('UFAZIEN_HOSTING_PASSWORD')
92+ WEBSITE_ID = os.environ.get('UFAZIEN_HOSTING_WEBSITE_ID')
93+
94+ if not all([BASE, EMAIL, PASSWORD, WEBSITE_ID]):
95+ raise SystemExit('Missing one or more required environment variables.')
96+
97+ login_url = f"{BASE}/auth/login/"
98+ print('🔐 Logging in to hosting API...')
99+ resp = requests.post(login_url, json={'email': EMAIL, 'password': PASSWORD}, timeout=30)
100+ if resp.status_code not in (200, 201):
101+ print('❌ Login failed:', resp.status_code, resp.text)
102+ raise SystemExit('Login failed')
103+
104+ tokens = resp.json()
105+ access = tokens.get('access') or tokens.get('token')
106+ if not access:
107+ print('❌ No access token found in login response:', tokens)
108+ raise SystemExit('No access token')
109+
110+ headers = {'Authorization': f'Bearer {access}'}
111+ dist_root = 'dist'
112+ files_to_upload = []
113+
114+ for path in glob.glob(os.path.join(dist_root, '**'), recursive=True):
115+ if os.path.isfile(path):
116+ rel = os.path.relpath(path, dist_root)
117+ files_to_upload.append(('files', (rel, open(path, 'rb'))))
118+
119+ if not files_to_upload:
120+ print('⚠️ No files found in dist to upload.')
121+ raise SystemExit('No files')
122+
123+ upload_url = f"{BASE}/hosting/websites/{WEBSITE_ID}/upload_files/"
124+ print(f'📤 Uploading {len(files_to_upload)} files to {upload_url}...')
125+
126+ resp = requests.post(upload_url, files=files_to_upload, headers=headers, data={'website_id': WEBSITE_ID}, timeout=120)
127+ print('🧾 Upload response:', resp.status_code)
128+ print(resp.text)
129+
130+ if resp.status_code not in (200, 201):
131+ raise SystemExit('❌ Upload failed')
132+
133+ print('✅ Upload succeeded')
134+ PYTHON_SCRIPT
0 commit comments