perf(ci): skip unchanged docker builds via paths-filter

Add `changes` job (dorny/paths-filter@v3) to detect which parts of the
codebase changed. Build jobs now run only when their source tree is
touched; deploy runs as long as no build failed (skipped builds are OK).

Split IMAGE_TAG (latest) from SENTRY_RELEASE_VAL (git sha) so Sentry
release tracking still points to the exact commit while compose pulls
the :latest tag.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
lekss361 2026-05-11 15:10:23 +03:00
parent a7d4223dfa
commit de21fac0a8

View file

@ -25,12 +25,40 @@ env:
IMAGE_FRONTEND: ghcr.io/lekss361/gendesign-frontend
jobs:
build-backend:
changes:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
outputs:
backend: ${{ steps.filter.outputs.backend }}
frontend: ${{ steps.filter.outputs.frontend }}
infra: ${{ steps.filter.outputs.infra }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
backend:
- 'backend/**'
frontend:
- 'frontend/**'
infra:
- 'docker-compose.prod.yml'
- 'Caddyfile'
- '.github/workflows/deploy.yml'
build-backend:
runs-on: ubuntu-latest
needs: changes
permissions:
contents: read
packages: write
if: github.event_name == 'workflow_dispatch' || github.ref == 'refs/heads/main'
if: |
needs.changes.outputs.backend == 'true' ||
needs.changes.outputs.infra == 'true' ||
github.event_name == 'workflow_dispatch'
steps:
- uses: actions/checkout@v4
@ -58,10 +86,14 @@ jobs:
build-worker:
runs-on: ubuntu-latest
needs: changes
permissions:
contents: read
packages: write
if: github.event_name == 'workflow_dispatch' || github.ref == 'refs/heads/main'
if: |
needs.changes.outputs.backend == 'true' ||
needs.changes.outputs.infra == 'true' ||
github.event_name == 'workflow_dispatch'
steps:
- uses: actions/checkout@v4
@ -89,10 +121,14 @@ jobs:
build-frontend:
runs-on: ubuntu-latest
needs: changes
permissions:
contents: read
packages: write
if: github.event_name == 'workflow_dispatch' || github.ref == 'refs/heads/main'
if: |
needs.changes.outputs.frontend == 'true' ||
needs.changes.outputs.infra == 'true' ||
github.event_name == 'workflow_dispatch'
steps:
- uses: actions/checkout@v4
@ -119,20 +155,29 @@ jobs:
deploy:
runs-on: ubuntu-latest
needs: [build-backend, build-worker, build-frontend]
needs: [changes, build-backend, build-worker, build-frontend]
permissions:
contents: read
# Запускается если ни один build не завершился failure.
# `always()` позволяет выполнить job даже когда зависимые jobs были skipped.
if: |
always() &&
!cancelled() &&
needs.build-backend.result != 'failure' &&
needs.build-worker.result != 'failure' &&
needs.build-frontend.result != 'failure'
steps:
- name: Deploy to VM via SSH
uses: appleboy/ssh-action@v1.0.3
env:
IMAGE_TAG: ${{ github.sha }}
IMAGE_TAG: latest
SENTRY_RELEASE_VAL: ${{ github.sha }}
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
port: ${{ secrets.DEPLOY_PORT || 22 }}
envs: IMAGE_TAG
envs: IMAGE_TAG,SENTRY_RELEASE_VAL
script: |
set -euo pipefail
cd /opt/gendesign
@ -146,12 +191,13 @@ jobs:
# ВАЖНО: НЕ перезаписываем файл целиком (там могут быть
# COUCHDB_PASSWORD и др. user-managed secrets). Заменяем только
# строку SENTRY_RELEASE или добавляем если её нет.
# IMAGE_TAG=latest для docker pull; SENTRY_RELEASE_VAL = git sha для трекинга.
mkdir -p backend
touch backend/.env.runtime
if grep -q '^SENTRY_RELEASE=' backend/.env.runtime; then
sed -i "s|^SENTRY_RELEASE=.*|SENTRY_RELEASE=$IMAGE_TAG|" backend/.env.runtime
sed -i "s|^SENTRY_RELEASE=.*|SENTRY_RELEASE=$SENTRY_RELEASE_VAL|" backend/.env.runtime
else
printf 'SENTRY_RELEASE=%s\n' "$IMAGE_TAG" >> backend/.env.runtime
printf 'SENTRY_RELEASE=%s\n' "$SENTRY_RELEASE_VAL" >> backend/.env.runtime
fi
chmod 600 backend/.env.runtime