Compare commits
9
Commits
29f788ed9a
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7024d2d2f9 | ||
|
|
293d11be17 | ||
|
|
fe97818968 | ||
|
|
aab71bb425 | ||
|
|
7c35c9328b | ||
|
|
1a63f5736c | ||
|
|
240e38f3af | ||
|
|
d7358d875f | ||
|
|
9fc422eb02 |
No files matched your search
@@ -0,0 +1,51 @@
|
||||
name: Build, Test and Push Flask App
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- release
|
||||
|
||||
env:
|
||||
PYTHON_VERSION: '3.11'
|
||||
|
||||
jobs:
|
||||
deploy-release:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Ansible
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y ansible openssh-client
|
||||
|
||||
- name: Set up SSH key
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_RELEASE_KEY }}
|
||||
run: |
|
||||
mkdir -p ~/.ssh
|
||||
printf '%s' "$SSH_PRIVATE_KEY" | tr -d '\r' > ~/.ssh/deploy_key
|
||||
chmod 600 ~/.ssh/deploy_key
|
||||
ssh-keygen -y -f ~/.ssh/deploy_key >/dev/null
|
||||
|
||||
- name: Trust server host key
|
||||
run: |
|
||||
ssh-keyscan -H "${{ secrets.RELEASE_SERVER_IP }}" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Test SSH
|
||||
run: |
|
||||
ssh \
|
||||
-i ~/.ssh/deploy_key \
|
||||
-o StrictHostKeyChecking=yes \
|
||||
"${{ secrets.RELEASE_SERVER_USER }}@${{ secrets.RELEASE_SERVER_IP }}" \
|
||||
'echo SSH works'
|
||||
|
||||
- name: Run Ansible playbook
|
||||
run: |
|
||||
ansible-playbook \
|
||||
-i "${{ secrets.RELEASE_SERVER_IP }}," \
|
||||
ansible/restart_release_compose.yml \
|
||||
--user "${{ secrets.RELEASE_SERVER_USER }}" \
|
||||
--private-key ~/.ssh/deploy_key
|
||||
+8
-8
@@ -5,6 +5,11 @@ WORKDIR /app
|
||||
|
||||
ENV PUPPETEER_SKIP_DOWNLOAD=true
|
||||
|
||||
ARG SITE_URL
|
||||
ARG PRERENDER_API_URL
|
||||
ENV SITE_URL=${SITE_URL}
|
||||
ENV PRERENDER_API_URL=${PRERENDER_API_URL}
|
||||
|
||||
# Копируем зависимости
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
@@ -20,18 +25,13 @@ RUN node scripts/prerender.js
|
||||
# ========== СТАДИЯ 2: СЕРВЕР ==========
|
||||
FROM nginx:alpine
|
||||
|
||||
ENV BACKEND_UPSTREAM=pvh-backend:80
|
||||
|
||||
# Копируем собранные файлы из стадии 1
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
COPY nginx/default.conf.template /etc/nginx/templates/default.conf.template
|
||||
|
||||
# Конфиг для SPA (чтобы react-router работал)
|
||||
RUN echo 'server { \
|
||||
listen 80; \
|
||||
location / { \
|
||||
root /usr/share/nginx/html; \
|
||||
try_files $uri $uri/ /index.html; \
|
||||
} \
|
||||
}' > /etc/nginx/conf.d/default.conf
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@@ -0,0 +1,15 @@
|
||||
- name: Restart Docker Compose services
|
||||
hosts: all
|
||||
# become: yes # <-- больше не нужно, т.к. пользователь уже имеет права Docker
|
||||
tasks:
|
||||
- name: docker compose down
|
||||
ansible.builtin.shell:
|
||||
cmd: docker compose down pvh-frontend
|
||||
chdir: ~/web
|
||||
- name: prune system
|
||||
ansible.builtin.shell:
|
||||
cmd: docker system prune -a -f
|
||||
- name: docker compose up -d
|
||||
ansible.builtin.shell:
|
||||
cmd: docker compose up -d pvh-frontend
|
||||
chdir: ~/web
|
||||
@@ -0,0 +1,18 @@
|
||||
server {
|
||||
listen 80;
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://${BACKEND_UPSTREAM}/;
|
||||
|
||||
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 / {
|
||||
root /usr/share/nginx/html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
User-agent: *
|
||||
Allow: /
|
||||
|
||||
Sitemap: https://pvh.projects.rustprogersteam.ru/sitemap.xml
|
||||
Sitemap: /sitemap.xml
|
||||
@@ -3,10 +3,16 @@ import { resolve, dirname } from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const prerenderApiUrl = process.env.PRERENDER_API_URL;
|
||||
|
||||
async function getProducts() {
|
||||
if (!prerenderApiUrl) {
|
||||
console.warn('PRERENDER_API_URL is not configured; skipping product pre-rendering.');
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('https://pvh.projects.rustprogersteam.ru/api/productList');
|
||||
const response = await fetch(`${prerenderApiUrl.replace(/\/$/, '')}/productList`);
|
||||
const data = await response.json();
|
||||
|
||||
if (Array.isArray(data)) {
|
||||
@@ -215,7 +221,8 @@ ${urls.map(item => ` <url>
|
||||
</urlset>`;
|
||||
}
|
||||
|
||||
const sitemapContent = generateSitemap(urls, 'https://pvh.projects.rustprogersteam.ru');
|
||||
const sitemapBaseUrl = process.env.SITE_URL?.replace(/\/$/, '') || 'http://localhost:5173';
|
||||
const sitemapContent = generateSitemap(urls, sitemapBaseUrl);
|
||||
const sitemapPath = resolve(distPath, 'sitemap.xml');
|
||||
writeFileSync(sitemapPath, sitemapContent);
|
||||
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ import axios, { AxiosInstance } from 'axios';
|
||||
class ApiClient {
|
||||
private axiosInstance: AxiosInstance;
|
||||
|
||||
constructor(baseURL: string = 'https://pvh.projects.rustprogersteam.ru/api') {
|
||||
constructor(baseURL: string = import.meta.env.VITE_API_URL || '/api') {
|
||||
this.axiosInstance = axios.create({
|
||||
baseURL,
|
||||
timeout: 10000,
|
||||
|
||||
@@ -22,9 +22,8 @@ gap: 15px;
|
||||
|
||||
|
||||
.logo {
|
||||
width: 60px;
|
||||
width: 200px;
|
||||
opacity: 0.9;
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +97,7 @@ text-align: center;
|
||||
|
||||
@media (max-width: 700px){
|
||||
.logo {
|
||||
width: 40px;
|
||||
width: 100px;
|
||||
opacity: 0.9;
|
||||
border-radius: 100%;
|
||||
}
|
||||
@@ -157,7 +156,7 @@ color: #fff;
|
||||
|
||||
@media (max-width: 460px){
|
||||
.logo {
|
||||
width: 40px;
|
||||
width: 80px;
|
||||
opacity: 0.9;
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import React from "react";
|
||||
import styles from "./Footer.module.css";
|
||||
import { NavLink } from "react-router-dom";
|
||||
import blackLogo from "../../assets/images/BlackLogo.jpg";
|
||||
import Logo from "../../assets/images/Logo.jpg";
|
||||
import PriceLisForm from "../PriceLisForm/PriceLisForm";
|
||||
import { useState } from "react";
|
||||
import OrangeLogo from "../../assets/images/OrangeLogo.jpg";
|
||||
|
||||
const Footer: React.FC = () => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
@@ -12,7 +11,7 @@ const Footer: React.FC = () => {
|
||||
<footer className={styles.footer}>
|
||||
<div className={styles.container}>
|
||||
<div className={styles.left}>
|
||||
<img src={blackLogo} alt="logo" className={styles.logo} />
|
||||
<img src={Logo} alt="logo" className={styles.logo} />
|
||||
<span className={styles.copy}>RK-Plastic Tech. 2021-2026 ©</span>
|
||||
</div>
|
||||
|
||||
|
||||
+10
-2
@@ -8,7 +8,7 @@ export default defineConfig({
|
||||
plugins: [
|
||||
react(),
|
||||
Sitemap({
|
||||
hostname: 'https://pvh.projects.rustprogersteam.ru',
|
||||
hostname: process.env.SITE_URL || 'http://localhost:5173',
|
||||
exclude: ['/admin', '/profile'],
|
||||
readable: true,
|
||||
outDir: './dist',
|
||||
@@ -18,12 +18,20 @@ export default defineConfig({
|
||||
server: {
|
||||
host: '0.0.0.0', // Слушаем все интерфейсы
|
||||
port: 5173,
|
||||
allowedHosts: ['pvh.projects.rustprogersteam.ru'],
|
||||
allowedHosts: process.env.VITE_ALLOWED_HOSTS?.split(',').map((host) => host.trim()),
|
||||
strictPort: true, // Запрещаем автоматический выбор порта
|
||||
hmr: {
|
||||
clientPort: 5173, // Важно для HMR в Docker
|
||||
},
|
||||
// Разрешаем CORS для внешних запросов
|
||||
proxy: process.env.VITE_API_PROXY_TARGET
|
||||
? {
|
||||
'/api': {
|
||||
target: process.env.VITE_API_PROXY_TARGET,
|
||||
changeOrigin: true,
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
cors: true
|
||||
}
|
||||
})
|
||||
Reference in new issue
Block a user