- Introduced path filtering using `dorny/paths-filter` to conditionally build and push Docker images for web, bot, and cache-proxy projects based on changes. - Added outputs to track which projects were built and modified the build and push steps to execute conditionally. - Created separate environment files for each project tag and implemented logic to merge these files into a main `.env` file during deployment. - Improved the deployment process by conditionally copying environment files to the VPS based on whether the corresponding project was built.
225 lines
9.8 KiB
YAML
225 lines
9.8 KiB
YAML
name: Build & Deploy Web, Bot & Cache Proxy
|
||
|
||
on:
|
||
push:
|
||
branches:
|
||
- main
|
||
|
||
jobs:
|
||
build-and-push:
|
||
name: Build and Push to Docker Hub
|
||
runs-on: ubuntu-latest
|
||
outputs:
|
||
web_tag: ${{ steps.vars.outputs.web_tag }}
|
||
bot_tag: ${{ steps.vars.outputs.bot_tag }}
|
||
cache_proxy_tag: ${{ steps.vars.outputs.cache_proxy_tag }}
|
||
# Добавляем output-ы для отслеживания, какие проекты были собраны
|
||
web_built: ${{ steps.filter.outputs.web }}
|
||
bot_built: ${{ steps.filter.outputs.bot }}
|
||
cache_proxy_built: ${{ steps.filter.outputs.cache_proxy }}
|
||
steps:
|
||
- name: Checkout code
|
||
uses: actions/checkout@v3
|
||
|
||
# --- НОВОЕ: Шаг 1: dorny/paths-filter для условной сборки ---
|
||
- name: Filter changed paths
|
||
uses: dorny/paths-filter@v2
|
||
id: filter
|
||
with:
|
||
filters: |
|
||
web:
|
||
- 'apps/web/**'
|
||
- 'packages/**'
|
||
bot:
|
||
- 'apps/bot/**'
|
||
- 'packages/**'
|
||
cache_proxy:
|
||
- 'apps/cache-proxy/**'
|
||
# -----------------------------------------------------------
|
||
- name: Create fake .env file for build
|
||
run: |
|
||
echo "BOT_TOKEN=fake" > .env
|
||
echo "LOGIN_GRAPHQL=fake" >> .env
|
||
echo "PASSWORD_GRAPHQL=fake" >> .env
|
||
echo "URL_GRAPHQL=http://localhost/graphql" >> .env
|
||
echo "EMAIL_GRAPHQL=fake@example.com" >> .env
|
||
echo "NEXTAUTH_SECRET=fakesecret" >> .env
|
||
echo "BOT_URL=http://localhost:3000" >> .env
|
||
echo "REDIS_PASSWORD=fake" >> .env
|
||
echo "BOT_PROVIDER_TOKEN=fake" >> .env
|
||
echo "OFFER_URL=http://localhost:3000/offer" >> .env
|
||
echo "PRIVACY_URL=http://localhost:3000/privacy" >> .env
|
||
echo "SUPPORT_TELEGRAM_URL=http://t.me/support" >> .env
|
||
|
||
- name: Set image tags
|
||
id: vars
|
||
run: |
|
||
echo "web_tag=web-${GITHUB_SHA::7}" >> $GITHUB_OUTPUT
|
||
echo "bot_tag=bot-${GITHUB_SHA::7}" >> $GITHUB_OUTPUT
|
||
echo "cache_proxy_tag=cache-proxy-${GITHUB_SHA::7}" >> $GITHUB_OUTPUT
|
||
|
||
- name: Login to Docker Hub
|
||
run: echo "${{ secrets.DOCKERHUB_TOKEN }}" | docker login -u "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin
|
||
|
||
# --- ИЗМЕНЕНО: Условное выполнение Build/Push ---
|
||
- name: Build web image
|
||
if: steps.filter.outputs.web == 'true'
|
||
run: |
|
||
docker build -t ${{ secrets.DOCKERHUB_USERNAME }}/zapishis-web:${{ steps.vars.outputs.web_tag }} -f ./apps/web/Dockerfile .
|
||
|
||
- name: Push web image to Docker Hub
|
||
if: steps.filter.outputs.web == 'true'
|
||
run: |
|
||
docker push ${{ secrets.DOCKERHUB_USERNAME }}/zapishis-web:${{ steps.vars.outputs.web_tag }}
|
||
|
||
- name: Build bot image
|
||
if: steps.filter.outputs.bot == 'true'
|
||
run: |
|
||
docker build -t ${{ secrets.DOCKERHUB_USERNAME }}/zapishis-bot:${{ steps.vars.outputs.bot_tag }} -f ./apps/bot/Dockerfile .
|
||
|
||
- name: Push bot image to Docker Hub
|
||
if: steps.filter.outputs.bot == 'true'
|
||
run: |
|
||
docker push ${{ secrets.DOCKERHUB_USERNAME }}/zapishis-bot:${{ steps.vars.outputs.bot_tag }}
|
||
|
||
- name: Build cache-proxy image
|
||
if: steps.filter.outputs.cache_proxy == 'true'
|
||
run: |
|
||
docker build -t ${{ secrets.DOCKERHUB_USERNAME }}/zapishis-cache-proxy:${{ steps.vars.outputs.cache_proxy_tag }} -f ./apps/cache-proxy/Dockerfile .
|
||
|
||
- name: Push cache-proxy image to Docker Hub
|
||
if: steps.filter.outputs.cache_proxy == 'true'
|
||
run: |
|
||
docker push ${{ secrets.DOCKERHUB_USERNAME }}/zapishis-cache-proxy:${{ steps.vars.outputs.cache_proxy_tag }}
|
||
# -------------------------------------------------
|
||
|
||
deploy:
|
||
name: Deploy to VPS
|
||
needs: build-and-push
|
||
runs-on: ubuntu-latest
|
||
environment: production
|
||
steps:
|
||
- name: Checkout code
|
||
uses: actions/checkout@v3
|
||
|
||
- name: Setup SSH key
|
||
run: |
|
||
mkdir -p ~/.ssh
|
||
echo "${{ secrets.VPS_SSH_KEY }}" > ~/.ssh/id_rsa
|
||
chmod 600 ~/.ssh/id_rsa
|
||
ssh-keyscan -p ${{ secrets.VPS_PORT }} -H ${{ secrets.VPS_HOST }} >> ~/.ssh/known_hosts
|
||
|
||
- name: Ensure zapishis directory exists on VPS
|
||
run: |
|
||
ssh -i ~/.ssh/id_rsa -p ${{ secrets.VPS_PORT }} -o StrictHostKeyChecking=no ${{ secrets.VPS_USER }}@${{ secrets.VPS_HOST }} "mkdir -p /home/${{ secrets.VPS_USER }}/zapishis"
|
||
|
||
# --- НОВОЕ: Шаг 2: Создание основного .env БЕЗ ТЕГОВ ---
|
||
- name: Create real .env file (No Tags)
|
||
run: |
|
||
# Включаем все секреты, КРОМЕ тегов
|
||
echo "BOT_TOKEN=${{ secrets.BOT_TOKEN }}" > .env
|
||
echo "LOGIN_GRAPHQL=${{ secrets.LOGIN_GRAPHQL }}" >> .env
|
||
echo "PASSWORD_GRAPHQL=${{ secrets.PASSWORD_GRAPHQL }}" >> .env
|
||
echo "URL_GRAPHQL=${{ secrets.URL_GRAPHQL }}" >> .env
|
||
echo "EMAIL_GRAPHQL=${{ secrets.EMAIL_GRAPHQL }}" >> .env
|
||
echo "NEXTAUTH_SECRET=${{ secrets.NEXTAUTH_SECRET }}" >> .env
|
||
echo "BOT_URL=${{ secrets.BOT_URL }}" >> .env
|
||
echo "DOCKERHUB_USERNAME=${{ secrets.DOCKERHUB_USERNAME }}" >> .env
|
||
echo "REDIS_PASSWORD=${{ secrets.REDIS_PASSWORD }}" >> .env
|
||
echo "BOT_PROVIDER_TOKEN=${{ secrets.BOT_PROVIDER_TOKEN }}" >> .env
|
||
echo "SUPPORT_TELEGRAM_URL=${{ secrets.SUPPORT_TELEGRAM_URL }}" >> .env
|
||
echo "OFFER_URL=${{ secrets.OFFER_URL }}" >> .env
|
||
echo "PRIVACY_URL=${{ secrets.PRIVACY_URL }}" >> .env
|
||
|
||
# --- НОВОЕ: Шаг 3: Создание файлов тегов (.project.env) ---
|
||
- name: Create Project Tag Env Files
|
||
run: |
|
||
# Создаем файлы, которые будут содержать только одну переменную с тегом
|
||
echo "WEB_IMAGE_TAG=${{ needs.build-and-push.outputs.web_tag }}" > .env.web
|
||
echo "BOT_IMAGE_TAG=${{ needs.build-and-push.outputs.bot_tag }}" > .env.bot
|
||
echo "CACHE_PROXY_IMAGE_TAG=${{ needs.build-and-push.outputs.cache_proxy_tag }}" > .env.cache-proxy
|
||
|
||
# --- Шаг 4: Копирование .env и УСЛОВНОЕ копирование тегов ---
|
||
|
||
# Копируем основной .env всегда
|
||
- name: Copy .env to VPS via SCP (Always)
|
||
uses: appleboy/scp-action@master
|
||
with:
|
||
host: ${{ secrets.VPS_HOST }}
|
||
username: ${{ secrets.VPS_USER }}
|
||
key: ${{ secrets.VPS_SSH_KEY }}
|
||
port: ${{ secrets.VPS_PORT }}
|
||
source: '.env'
|
||
target: '/home/${{ secrets.VPS_USER }}/zapishis/'
|
||
|
||
# Копируем .env.web ТОЛЬКО, если web был собран (обновляем тег на VPS)
|
||
- name: Copy .env.web to VPS
|
||
if: ${{ needs.build-and-push.outputs.web_built == 'true' }}
|
||
uses: appleboy/scp-action@master
|
||
with:
|
||
host: ${{ secrets.VPS_HOST }}
|
||
username: ${{ secrets.VPS_USER }}
|
||
key: ${{ secrets.VPS_SSH_KEY }}
|
||
port: ${{ secrets.VPS_PORT }}
|
||
source: '.env.web'
|
||
target: '/home/${{ secrets.VPS_USER }}/zapishis/'
|
||
|
||
# Копируем .env.bot ТОЛЬКО, если bot был собран
|
||
- name: Copy .env.bot to VPS
|
||
if: ${{ needs.build-and-push.outputs.bot_built == 'true' }}
|
||
uses: appleboy/scp-action@master
|
||
with:
|
||
host: ${{ secrets.VPS_HOST }}
|
||
username: ${{ secrets.VPS_USER }}
|
||
key: ${{ secrets.VPS_SSH_KEY }}
|
||
port: ${{ secrets.VPS_PORT }}
|
||
source: '.env.bot'
|
||
target: '/home/${{ secrets.VPS_USER }}/zapishis/'
|
||
|
||
# Копируем .env.cache-proxy ТОЛЬКО, если cache-proxy был собран
|
||
- name: Copy .env.cache-proxy to VPS
|
||
if: ${{ needs.build-and-push.outputs.cache_proxy_built == 'true' }}
|
||
uses: appleboy/scp-action@master
|
||
with:
|
||
host: ${{ secrets.VPS_HOST }}
|
||
username: ${{ secrets.VPS_USER }}
|
||
key: ${{ secrets.VPS_SSH_KEY }}
|
||
port: ${{ secrets.VPS_PORT }}
|
||
source: '.env.cache-proxy'
|
||
target: '/home/${{ secrets.VPS_USER }}/zapishis/'
|
||
|
||
- name: Copy docker-compose.yml to VPS via SCP
|
||
uses: appleboy/scp-action@master
|
||
with:
|
||
host: ${{ secrets.VPS_HOST }}
|
||
username: ${{ secrets.VPS_USER }}
|
||
key: ${{ secrets.VPS_SSH_KEY }}
|
||
port: ${{ secrets.VPS_PORT }}
|
||
source: 'docker-compose.yml'
|
||
target: '/home/${{ secrets.VPS_USER }}/zapishis/'
|
||
|
||
# --- ФИНАЛЬНЫЙ ДЕПЛОЙ ---
|
||
- name: Login and deploy on VPS
|
||
run: |
|
||
ssh -i ~/.ssh/id_rsa -p ${{ secrets.VPS_PORT }} -o StrictHostKeyChecking=no ${{ secrets.VPS_USER }}@${{ secrets.VPS_HOST }} "
|
||
cd /home/${{ secrets.VPS_USER }}/zapishis && \
|
||
|
||
# 1. Объединение ВСЕХ ENV-файлов в один основной .env
|
||
# Теги из .env.web/.env.bot переопределят любые старые/пустые значения,
|
||
# и .env станет полным и актуальным.
|
||
echo \"Merging environment files into .env...\" && \
|
||
cat .env .env.web .env.bot .env.cache-proxy > .temp_env && \
|
||
mv .temp_env .env && \
|
||
|
||
# 2. Логин
|
||
docker login -u ${{ secrets.DOCKERHUB_USERNAME }} -p ${{ secrets.DOCKERHUB_TOKEN }}
|
||
|
||
# 3. Pull ВСЕХ сервисов (Docker Compose автоматически использует обновленный .env)
|
||
echo \"Pulling all services...\" && \
|
||
docker compose pull
|
||
|
||
# 4. Перезапуск
|
||
docker compose down && \
|
||
docker compose up -d
|
||
"
|