let a deploy repair the server instead of stopping at it

تا حالا اگر کسی روی سرور فایلی را دستی عوض کرده بود، `git pull --ff-only`
شکست می‌خورد و کلِ اسکریپت همان‌جا می‌ایستاد. چون هیچ‌کدام از مراحلِ بعدی
اجرا نمی‌شد، سرور با کدِ قدیمی می‌ماند — بی‌صدا. یک بار همین دو روز طول کشید.

حالا مرحله‌ی اول fetch می‌کند، اگر تغییرِ دستی (یا کامیتِ محلی) باشد آن را در
.deploy-backups/*.patch نگه می‌دارد، و با `git reset --hard origin/<branch>`
کنارش می‌گذارد و ادامه می‌دهد. سرور در هر وضعیتی باشد، یک اجرا دقیقاً همان
چیزی می‌شود که روی gitea است.

`git clean` عمداً زده نمی‌شود و نباید اضافه شود: db.sqlite3 و .env و
.django_secret_key ردیابی‌نشده و داخلِ همین پوشه‌اند.

با مخزنِ ساختگی هر سه حالت آزموده شد: تغییرِ دستی، درختِ تمیز، و کامیتِ محلیِ
واگرا. در هر سه، .env و db.sqlite3 دست‌نخورده ماندند.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-18 00:54:06 +03:30
parent 6ec82081b5
commit 8eedbdeac0
3 changed files with 67 additions and 4 deletions

View File

@@ -127,8 +127,38 @@ colourless.
## Operations
`./deploy.sh` is the whole release: pull, install, migrate, collectstatic, restart, then
it polls `/api/health` and prints the likely cause if the service does not come back.
**The whole release, as one line:**
```bash
ssh -t administrator@78.38.35.249 'cd ~/mathapp-v2 && ./deploy.sh; sudo systemctl restart zareian-mathapp'
```
It asks for the password twice — once for ssh, once for sudo. **Wait for each prompt**;
pasting several lines at once feeds the queued text to the password prompt and locks you
out for three tries.
The trailing restart is separate because `sudo` inside `deploy.sh` cannot prompt for a
password. The script no longer pretends that worked: it compares the service's start time
before and after and exits non-zero when the restart did not happen, so a half-finished
deploy can never again look like a successful one. Giving `administrator` a `NOPASSWD`
sudoers line for just `systemctl restart zareian-mathapp` would collapse this to a single
command; that is the server admin's call, not ours.
`./deploy.sh` is the whole release: fetch, reset to `origin/<branch>`, install, migrate,
seed content, collectstatic, restart, then it polls `/api/health` and prints the likely
cause if the service does not come back.
**It repairs the server rather than stopping at it.** A hand-edited file used to make
`git pull --ff-only` fail, which aborted the whole script — and because every later step
was skipped, the server silently stayed on old code. Now local modifications (and local
commits) are saved to a timestamped patch under `.deploy-backups/` and then discarded with
`git reset --hard origin/<branch>`, and the deploy continues. Whatever state the server is
left in, one run puts it back on exactly what Gitea has.
**`git clean` is never run there and must never be added.** `db.sqlite3`, `.env` and
`.django_secret_key` are untracked and live in that directory; `reset --hard` leaves them
alone, `clean -fd` would destroy the database, the config and every signed-in session.
Settings boot with working defaults (hosts, CSRF, CORS, secret key, cache), so a stale or
partial `.env` on the server no longer breaks startup — env values are *merged with*
those defaults, not replaced by them.