Some checks failed
Эти папки большие и не в git (wiki ~73 МБ, kubikon-assets ~34 МБ). fetch-assets.js скачивает kubikon-assets, но wiki/ не скачивает. На CI runner-е они отсутствуют → rsync --delete-after удаляет их с прод-серверов → битые картинки на studio.rublox.pro. Фикс: --exclude=wiki --exclude=kubikon-assets чтобы CI не трогал эти папки на серверах. Один раз залить руками, дальше CI деплоит только код, не трогая assets.
155 lines
6.6 KiB
YAML
155 lines
6.6 KiB
YAML
# CI студии Рублокса.
|
||
# Запускается на каждый push и pull_request.
|
||
#
|
||
# Что проверяем:
|
||
# 1. lint — ESLint без warning'ов
|
||
# 2. format-check — Prettier формат не нарушен
|
||
# 3. build — vite build проходит без ошибок
|
||
# 4. secret-scan — trufflehog не нашёл утечек секретов
|
||
# 5. size-check — PR не больше 1000 строк (предупреждение)
|
||
name: CI
|
||
|
||
on:
|
||
push:
|
||
branches: [main]
|
||
pull_request:
|
||
branches: [main]
|
||
|
||
jobs:
|
||
lint:
|
||
name: Lint
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- uses: actions/checkout@v3
|
||
- uses: actions/setup-node@v3
|
||
with:
|
||
node-version: '18'
|
||
- run: npm ci
|
||
# format:check временно отключён до массового npx prettier --write
|
||
# (см. docs/ONBOARDING.md → «Форматирование кода»). После прогона
|
||
# верни строку `- run: npm run format:check` перед npm run lint.
|
||
- run: npm run lint
|
||
|
||
build:
|
||
name: Build
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- uses: actions/checkout@v3
|
||
- uses: actions/setup-node@v3
|
||
with:
|
||
node-version: '18'
|
||
- run: npm ci
|
||
- run: npm run build
|
||
- name: Save build size
|
||
# set -o pipefail (default Gitea Actions) валит весь step если head
|
||
# закроет pipe раньше. Делаем команды непадающими через || true.
|
||
run: |
|
||
du -sh build/ || true
|
||
ls -la build/assets/ 2>/dev/null | head -10 || true
|
||
|
||
secret-scan:
|
||
name: Secret scan
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- uses: actions/checkout@v3
|
||
with:
|
||
fetch-depth: 0
|
||
- name: Install trufflehog
|
||
run: |
|
||
curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh \
|
||
| sh -s -- -b /usr/local/bin
|
||
- name: Run trufflehog
|
||
run: |
|
||
trufflehog git "file://$(pwd)" \
|
||
--only-verified --fail \
|
||
--exclude-paths .trufflehog-ignore 2>&1 | tee scan.log || EXIT=$?
|
||
if [ -n "$EXIT" ] && [ "$EXIT" -ne 0 ]; then
|
||
echo "::error::Найдены секреты в коммитах! См. лог выше."
|
||
exit 1
|
||
fi
|
||
|
||
size-check:
|
||
name: PR size check
|
||
if: github.event_name == 'pull_request'
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- uses: actions/checkout@v3
|
||
with:
|
||
fetch-depth: 0
|
||
- name: Check PR size
|
||
run: |
|
||
ADDED=$(git diff origin/${{ github.base_ref }}...HEAD --shortstat | grep -oE '[0-9]+ insertion' | grep -oE '[0-9]+' || echo 0)
|
||
REMOVED=$(git diff origin/${{ github.base_ref }}...HEAD --shortstat | grep -oE '[0-9]+ deletion' | grep -oE '[0-9]+' || echo 0)
|
||
TOTAL=$((ADDED + REMOVED))
|
||
echo "PR изменяет $TOTAL строк (+$ADDED / -$REMOVED)"
|
||
if [ "$TOTAL" -gt 1000 ]; then
|
||
echo "::warning::PR изменяет $TOTAL строк (> 1000). Подумай о дроблении на несколько меньших."
|
||
fi
|
||
|
||
# ────────────────────────────────────────────────────────────────────
|
||
# DEPLOY — собирает прод-бандл и заливает на ОБА сервера (S1+S2)
|
||
# параллельно через rsync over SSH.
|
||
#
|
||
# Запускается ТОЛЬКО на push в main (т.е. после успешного мержа PR).
|
||
# PR-проверки выше (lint/build/secret-scan/size-check) гарантируют
|
||
# что в main попадает только корректный код.
|
||
#
|
||
# Секреты:
|
||
# DEPLOY_SSH_KEY — приватный ed25519 ключ (CI-only, отдельный от
|
||
# админских), pubkey уже на ~min/.ssh/authorized_keys
|
||
# на S1 VM 124 и S2 VM 124
|
||
# KNOWN_HOSTS — host-keys S1 и S2 (защита от MITM)
|
||
#
|
||
# Цели (на VM 124 обоих серверов):
|
||
# /var/www/rublox-studio/build/
|
||
#
|
||
# При сбое деплоя ни один сервер не остаётся в полу-задеплоенном
|
||
# состоянии: rsync делает атомарную замену с --delete-after.
|
||
# ────────────────────────────────────────────────────────────────────
|
||
deploy:
|
||
name: Deploy to S1 + S2
|
||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||
needs: [build, secret-scan]
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- uses: actions/checkout@v3
|
||
- uses: actions/setup-node@v3
|
||
with:
|
||
node-version: '18'
|
||
- name: Install deps
|
||
run: npm ci
|
||
- name: Production build
|
||
run: npm run build
|
||
- name: Prepare SSH
|
||
env:
|
||
DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
|
||
KNOWN_HOSTS: ${{ secrets.KNOWN_HOSTS }}
|
||
run: |
|
||
mkdir -p ~/.ssh && chmod 700 ~/.ssh
|
||
echo "$DEPLOY_SSH_KEY" > ~/.ssh/id_deploy
|
||
chmod 600 ~/.ssh/id_deploy
|
||
echo "$KNOWN_HOSTS" > ~/.ssh/known_hosts
|
||
chmod 600 ~/.ssh/known_hosts
|
||
- name: Install rsync
|
||
run: apt-get update -qq && apt-get install -y rsync openssh-client
|
||
- name: Deploy to S1 (85.175.7.40:1998)
|
||
run: |
|
||
rsync -az --delete-after --human-readable --exclude=wiki --exclude=kubikon-assets \
|
||
-e "ssh -i ~/.ssh/id_deploy -o UserKnownHostsFile=~/.ssh/known_hosts -p 1998" \
|
||
build/ min@85.175.7.40:/var/www/rublox-studio/build/
|
||
- name: Deploy to S2 (192.168.0.124:22, runner в той же сети)
|
||
run: |
|
||
rsync -az --delete-after --human-readable --exclude=wiki --exclude=kubikon-assets \
|
||
-e "ssh -i ~/.ssh/id_deploy -o UserKnownHostsFile=~/.ssh/known_hosts -p 22" \
|
||
build/ min@192.168.0.124:/var/www/rublox-studio/build/
|
||
- name: Verify deploy
|
||
run: |
|
||
echo "=== S1 ==="
|
||
ssh -i ~/.ssh/id_deploy -o UserKnownHostsFile=~/.ssh/known_hosts -p 1998 \
|
||
min@85.175.7.40 \
|
||
"ls /var/www/rublox-studio/build/index.html && du -sh /var/www/rublox-studio/build/"
|
||
echo "=== S2 ==="
|
||
ssh -i ~/.ssh/id_deploy -o UserKnownHostsFile=~/.ssh/known_hosts -p 22 \
|
||
min@192.168.0.124 \
|
||
"ls /var/www/rublox-studio/build/index.html && du -sh /var/www/rublox-studio/build/"
|