From 01d8bb20d52bba148940ca8e4b52e94b3ec6205c Mon Sep 17 00:00:00 2001 From: vchikalkin Date: Wed, 8 Oct 2025 18:13:09 +0300 Subject: [PATCH] Enhance GitHub Actions workflow for conditional builds and environment file management - 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. --- .github/workflows/deploy.yml | 102 ++++++++++++++++++++++++++++++++--- 1 file changed, 95 insertions(+), 7 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index bd05c65..1f35de9 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -13,10 +13,29 @@ jobs: 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 @@ -42,29 +61,37 @@ jobs: - 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 @@ -86,8 +113,10 @@ jobs: 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" - - name: Create real .env file for production + # --- НОВОЕ: Шаг 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 @@ -95,9 +124,6 @@ jobs: echo "EMAIL_GRAPHQL=${{ secrets.EMAIL_GRAPHQL }}" >> .env echo "NEXTAUTH_SECRET=${{ secrets.NEXTAUTH_SECRET }}" >> .env echo "BOT_URL=${{ secrets.BOT_URL }}" >> .env - echo "WEB_IMAGE_TAG=${{ needs.build-and-push.outputs.web_tag }}" >> .env - echo "BOT_IMAGE_TAG=${{ needs.build-and-push.outputs.bot_tag }}" >> .env - echo "CACHE_PROXY_IMAGE_TAG=${{ needs.build-and-push.outputs.cache_proxy_tag }}" >> .env echo "DOCKERHUB_USERNAME=${{ secrets.DOCKERHUB_USERNAME }}" >> .env echo "REDIS_PASSWORD=${{ secrets.REDIS_PASSWORD }}" >> .env echo "BOT_PROVIDER_TOKEN=${{ secrets.BOT_PROVIDER_TOKEN }}" >> .env @@ -105,7 +131,18 @@ jobs: echo "OFFER_URL=${{ secrets.OFFER_URL }}" >> .env echo "PRIVACY_URL=${{ secrets.PRIVACY_URL }}" >> .env - - name: Copy .env to VPS via SCP + # --- НОВОЕ: Шаг 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 }} @@ -115,6 +152,42 @@ jobs: 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: @@ -125,12 +198,27 @@ jobs: 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 && \ - docker login -u ${{ secrets.DOCKERHUB_USERNAME }} -p ${{ secrets.DOCKERHUB_TOKEN }} && \ - docker compose pull && \ + + # 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 "