Compare commits

...

2 Commits

Author SHA1 Message Date
Artem Kashaev 16479ba85b feat: enhance CI/CD workflow for frontend build and deployment
Build and deploy / build (push) Failing after 28s Details
Build and deploy / deploy (push) Has been skipped Details
Test / test (push) Successful in 15s Details
2025-12-01 14:32:27 +05:00
Artem Kashaev 9a2a2f6adc feat: add static file serving and frontend asset handling to FastAPI application 2025-12-01 14:25:11 +05:00
3 changed files with 73 additions and 1 deletions

View File

@ -4,6 +4,7 @@ on:
push:
branches:
- master
- frontend
workflow_dispatch:
jobs:
@ -13,9 +14,39 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js 24 via nvm
run: |
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
nvm install 24
nvm use 24
node -v
npm -v
echo "PATH=$PATH" >> $GITHUB_ENV
- name: Login to registry
run: echo "${{ secrets.TOKEN }}" | docker login ${{ secrets.GIT_HOST }} -u ${{ secrets.USERNAME }} --password-stdin
- name: Build frontend bundle
working-directory: frontend
env:
CI: "false"
run: |
npm install
npm run build
- name: Archive frontend dist
run: |
tar -czf frontend-dist.tar.gz -C frontend/dist .
- name: Upload frontend artifact
uses: actions/upload-artifact@v3
with:
name: frontend-dist
path: frontend-dist.tar.gz
retention-days: 7
- name: Build and push app
run: |
docker build -t ${{ secrets.GIT_HOST }}/${{ gitea.repository }}:app -f app/Dockerfile .
@ -44,6 +75,19 @@ jobs:
- name: Create remote deployment directory
run: ssh ${{ secrets.LXC_USER }}@${{ secrets.LXC_HOST }} "mkdir -p /srv/app"
- name: Download frontend artifact
uses: actions/download-artifact@v3
with:
name: frontend-dist
path: artifacts
- name: Upload frontend dist to server
run: |
mkdir -p artifacts/extracted
tar -xzf artifacts/frontend-dist.tar.gz -C artifacts/extracted
ssh ${{ secrets.LXC_USER }}@${{ secrets.LXC_HOST }} "mkdir -p /srv/app/frontend/dist && rm -rf /srv/app/frontend/dist/*"
scp -r artifacts/extracted/* ${{ secrets.LXC_USER }}@${{ secrets.LXC_HOST }}:/srv/app/frontend/dist/
- name: Deploy docker-compose-ci.yml
run: scp docker-compose-ci.yml ${{ secrets.LXC_USER }}@${{ secrets.LXC_HOST }}:/srv/app/docker-compose.yml

View File

@ -4,8 +4,11 @@ from __future__ import annotations
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from pathlib import Path
from fastapi import FastAPI
from fastapi import FastAPI, HTTPException
from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles
from app.api.routes import api_router
from app.core.cache import init_cache, shutdown_cache
@ -14,6 +17,10 @@ from app.core.middleware.cache_monitor import CacheAvailabilityMiddleware
from fastapi.middleware.cors import CORSMiddleware
PROJECT_ROOT = Path(__file__).resolve().parent.parent
FRONTEND_DIST = PROJECT_ROOT / "frontend" / "dist"
FRONTEND_INDEX = FRONTEND_DIST / "index.html"
def create_app() -> FastAPI:
"""Build FastAPI application instance."""
@ -42,6 +49,25 @@ def create_app() -> FastAPI:
allow_methods=["*"], # Разрешить все HTTP-методы
allow_headers=["*"], # Разрешить все заголовки
)
if FRONTEND_DIST.exists() and FRONTEND_INDEX.exists():
assets_dir = FRONTEND_DIST / "assets"
if assets_dir.exists():
application.mount("/assets", StaticFiles(directory=assets_dir), name="frontend-assets")
@application.get("/", include_in_schema=False)
async def serve_frontend_root() -> FileResponse: # pragma: no cover - simple file response
return FileResponse(FRONTEND_INDEX)
@application.get("/{path:path}", include_in_schema=False)
async def serve_frontend_path(path: str) -> FileResponse: # pragma: no cover - simple file response
if path == "" or path.startswith("api"):
raise HTTPException(status_code=404)
candidate = FRONTEND_DIST / path
if candidate.is_file():
return FileResponse(candidate)
return FileResponse(FRONTEND_INDEX)
return application

View File

@ -25,6 +25,8 @@ services:
ANALYTICS_CACHE_BACKOFF_MS: ${ANALYTICS_CACHE_BACKOFF_MS}
ports:
- "80:8000"
volumes:
- ./frontend/dist:/opt/app/frontend/dist:ro
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:8000/health"]
interval: 30s