diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..4d4f73b --- /dev/null +++ b/.env.example @@ -0,0 +1,7 @@ +BACKEND_TAG=latest +FRONTEND_TAG=latest +VITE_API_BASE=/taller/api +JENKINS_BASE_URL=http://host.docker.internal:8080 +JENKINS_JOB_NAME=TallerCiCd +JENKINS_USER= +JENKINS_TOKEN= diff --git a/Jenkinsfile.cd b/Jenkinsfile.cd index 4a1d445..7f39b85 100644 --- a/Jenkinsfile.cd +++ b/Jenkinsfile.cd @@ -5,10 +5,31 @@ pipeline { timestamps() } + parameters { + string( + name: 'JENKINS_BASE_URL', + defaultValue: 'https://openbokeron.org/jenkins', + description: 'Base URL del Jenkins objetivo' + ) + string( + name: 'JENKINS_JOB_NAME', + defaultValue: 'TallerCiCd', + description: 'Nombre del job que se consulta en Jenkins' + ) + string( + name: 'VITE_API_BASE', + defaultValue: '/taller/api', + description: 'Base path/API para el frontend (build time)' + ) + } + environment { NODE_OPTIONS = '--max_old_space_size=2048' APP_VERSION = "1.0.${BUILD_NUMBER}" DOCKER_BUILDKIT = '1' + JENKINS_BASE_URL = "${params.JENKINS_BASE_URL}" + JENKINS_JOB_NAME = "${params.JENKINS_JOB_NAME}" + VITE_API_BASE = "${params.VITE_API_BASE}" } stages { @@ -77,6 +98,7 @@ pipeline { ./backend docker build \ + --build-arg VITE_API_BASE=${VITE_API_BASE} \ -t cafeteria-frontend:${BUILD_NUMBER} \ -t cafeteria-frontend:latest \ ./frontend @@ -93,10 +115,6 @@ pipeline { branch 'main' } agent any - environment { - JENKINS_BASE_URL = 'https://openbokeron.org/jenkins' - JENKINS_JOB_NAME = 'TallerCiCd' - } steps { withCredentials([ usernamePassword( @@ -110,15 +128,14 @@ pipeline { echo "Deploying backend ${BUILD_NUMBER}" - echo "BACKEND_TAG=${BUILD_NUMBER}" > .env - echo "FRONTEND_TAG=${BUILD_NUMBER}" >> .env - - docker-compose up -d + BACKEND_TAG=${BUILD_NUMBER} FRONTEND_TAG=${BUILD_NUMBER} docker-compose up -d ''' } } } + + stage('Cleanup') { agent any steps { diff --git a/README.md b/README.md index 6b2a65c..c2ec283 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,16 @@ - Python 3.11+ y `pip` - Node 18+ y `npm` +## Configuracion de entorno (local/prod) +Variables que usa `docker-compose` y el frontend: +```bash +cp .env.example .env +``` +Notas: +- `VITE_API_BASE` por defecto apunta a `/taller/api` y el frontend proxya a la API. +- Para Jenkins local en contenedor: `JENKINS_BASE_URL=http://jenkins:8080`. Se hace necesario que back y jenkins estén en la misma red de Docker si se quiere probar en local. +- Para VPS: `JENKINS_BASE_URL=https://openbokeron.org/jenkins`. + ## Backend (FastAPI) ```bash cd backend @@ -42,6 +52,7 @@ cd frontend npm install npm run dev -- --host --port 5173 ``` +Abrir `http://localhost:5173/taller/`. Tests, lint/check: ```bash cd frontend diff --git a/backend/app/settings.py b/backend/app/settings.py index 79c78a5..6c9d46d 100644 --- a/backend/app/settings.py +++ b/backend/app/settings.py @@ -24,7 +24,10 @@ class RuntimeConfig: git_commit: str = os.getenv("GIT_COMMIT", "local") build_number: str = os.getenv("BUILD_NUMBER", "-") commit_author: str = os.getenv("COMMIT_AUTHOR", "local") - jenkins_base_url: str = os.getenv("JENKINS_BASE_URL", "localhost:8080") + jenkins_base_url: str = os.getenv( + "JENKINS_BASE_URL", + "http://localhost:8080" + ).rstrip("/") jenkins_job_name: str = os.getenv("JENKINS_JOB_NAME", "") jenkins_user: str = os.getenv("JENKINS_USER", "") jenkins_token: str = os.getenv("JENKINS_TOKEN", "") diff --git a/docker-compose.yml b/docker-compose.yml index f35247d..7692ea1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,16 +2,16 @@ services: backend: build: context: ./backend - image: cafeteria-backend:${BACKEND_TAG} + image: cafeteria-backend:${BACKEND_TAG:-latest} networks: - cafeteria ports: - "8000:8000" environment: - JENKINS_BASE_URL: ${JENKINS_BASE_URL} - JENKINS_JOB_NAME: ${JENKINS_JOB_NAME} - JENKINS_USER: ${JENKINS_USER} - JENKINS_TOKEN: ${JENKINS_TOKEN} + JENKINS_BASE_URL: ${JENKINS_BASE_URL:-http://jenkins:8080} + JENKINS_JOB_NAME: ${JENKINS_JOB_NAME:-TallerCiCd} + JENKINS_USER: ${JENKINS_USER:-} + JENKINS_TOKEN: ${JENKINS_TOKEN:-} restart: unless-stopped healthcheck: test: @@ -28,9 +28,9 @@ services: frontend: build: context: ./frontend - image: cafeteria-frontend:${FRONTEND_TAG} - environment: - VITE_API_BASE: ${VITE_API_BASE} + args: + VITE_API_BASE: ${VITE_API_BASE:-/taller/api} + image: cafeteria-frontend:${FRONTEND_TAG:-latest} networks: - cafeteria ports: diff --git a/frontend/nginx.conf b/frontend/nginx.conf index 4e23060..6225c35 100644 --- a/frontend/nginx.conf +++ b/frontend/nginx.conf @@ -5,7 +5,20 @@ server { root /usr/share/nginx/html; index index.html; + location = /taller { + return 301 /taller/; + } + + location /taller/api/ { + proxy_pass http://backend:8000/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + location /taller/ { - try_files $uri $uri/ /index.html; + try_files $uri $uri/ /taller/index.html; } } diff --git a/frontend/src/config.js b/frontend/src/config.js index 3a8669e..bcedd0a 100644 --- a/frontend/src/config.js +++ b/frontend/src/config.js @@ -16,5 +16,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -export const API_BASE = import.meta.env.VITE_API_BASE || 'http://localhost:8000'; +const baseUrl = import.meta.env.BASE_URL || '/'; +const defaultApiBase = `${baseUrl.replace(/\/$/, '')}/api`; +const rawApiBase = import.meta.env.VITE_API_BASE || defaultApiBase; + +export const API_BASE = rawApiBase.replace(/\/$/, ''); export const ENABLE_POLLING = import.meta.env.MODE !== 'test'; diff --git a/frontend/vite.config.js b/frontend/vite.config.js index 8b8818e..d8aba27 100644 --- a/frontend/vite.config.js +++ b/frontend/vite.config.js @@ -1,14 +1,34 @@ -import { defineConfig } from 'vite'; +import { defineConfig, loadEnv } from 'vite'; import { svelte } from '@sveltejs/vite-plugin-svelte'; -export default defineConfig({ - base: '/taller/', - plugins: [svelte()], - test: { - environment: 'jsdom', - globals: true, - }, - server: { - port: 5173, - }, +export default defineConfig(({ mode }) => { + const env = loadEnv(mode, process.cwd(), 'VITE_'); + const basePath = '/taller/'; + const defaultApiBase = `${basePath.replace(/\/$/, '')}/api`; + const apiBase = (env.VITE_API_BASE || defaultApiBase).replace(/\/$/, ''); + const apiProxyPath = apiBase.startsWith('http') ? null : apiBase; + + return { + base: basePath, + plugins: [svelte()], + test: { + environment: 'jsdom', + globals: true, + }, + server: { + port: 5173, + proxy: apiProxyPath + ? { + [apiProxyPath]: { + target: 'http://localhost:8000', + changeOrigin: true, + rewrite: (path) => + path.startsWith(apiProxyPath) + ? path.slice(apiProxyPath.length) || '/' + : path, + }, + } + : undefined, + }, + }; });