feat(backup): external git-mirror + issues/PR export #2
Labels
No labels
enhancement
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: slaid098/forgejo-infra#2
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Контекст
GitHub-аккаунт
slaid098удалён безвозвратно. Вся история проекта (код, issues, PR, память) теперь живёт только наgit.slaid098.dev(Forgejo на втором сервере). Если хост умрёт / хостинг удалят / сервер сгорит — уносим всё безвозвратно, как уже случилось с GitHub-аккаунтом.Память (
opencode-memory) синхронизирована с Forgejo, clean, но в bundle-бэкапы/root/workspace/_backups/bundles/НЕ входит.crontab/systemdна хосте недоступны — регулярных бэкапов нет. Только ручные git-bundle'ы 9 workspace-репо от 2026-08-06.Активных репозиториев на Forgejo всего 3:
opencode-config,opencode-voice-dictation,forgejo-infra. Плюсopencode-memory— отдельный git-репо (синхронизирован с Forgejo). Итого 4 источника для зеркалирования.Forgejo-инстанс НЕ на этом хосте (linux-2), а на втором сервере — работаем только через REST API (
FORGEJO_URL/FORGEJO_TOKENв окружении).Инструменты opencode-config (create-issue, create-pr, merge-pr, post-review, pipeline-status, project-status, spec-status) уже портированы на Forgejo через env-fallback —
FORGEJO_URLзадан → используют Forgejo REST API, иначе fallback наghCLI. Issue #1 про портирование устарел и должен быть закрыт отдельно.Задача
Реализовать disaster recovery уровня A: код + issues/PR на внешнем git-хостинге. Два слоя защиты:
Слой 1 — Git-mirror (push). Настроить push mirror для 4 репо на внешний git-хост (GitLab.com — предпочтительно, Codeberg — запасной). Использовать Forgejo's built-in push mirror (через API
/api/v1/repos/{repo}/push_mirrors), не локальные git-операции — Forgejo сам пушит по schedule. Переносит код + коммиты + ветки + теги.Слой 2 — Issues/PR-экспорт. Forgejo Actions workflow в
forgejo-infra(schedule daily), который через API тянет issues/PR/comments/labels из всех репо, сериализует в JSON + человекочитаемый markdown, коммитит в отдельный репоforgejo-archiveна внешнем хосте. Обратная сторона —forgejo-restore.shскрипт, который читает archive и через API воссоздаёт issues/PR на новом инстансе.Цель: "одной командой поднять точно такой же Forgejo со всеми настройками, pull-request'ами и issues" — на новом сервере.
Контракты
POST /api/v1/repos/{repo}/push_mirrorsс{target_address, target_username, target_password, interval, mirror, ...}. Документация: https://codeberg.org/forgejo/forgejo/src/branch/forgejo/routers/api/v1/repo/push_mirror.goGET /api/v1/repos/{repo}/issues?state=all&limit=50&page=N, для каждого issueGET /api/v1/repos/{repo}/issues/{n}/commentsGET /api/v1/repos/{repo}/pulls?state=all&limit=50&page=NGET /api/v1/repos/{repo}/labelsGET /api/v1/repos/{repo}/milestonesarchive/{repo}/issues/{N}.json+archive/{repo}/issues/{N}.md+archive/{repo}/pulls/{N}.json+archive/{repo}/pulls/{N}.md+archive/{repo}/labels.json+archive/{repo}/milestones.json+archive/meta.json(timestamp, forgejo version, exporter version)forgejo-restore.sh <archive-repo-path> <target-forgejo-url> <token>— читает archive, создаёт labels/milestones/issues/PR через API в правильном порядке (с маппингом старых ID → новых)Инварианты
opencode-config,opencode-voice-dictation,forgejo-infra,opencode-memory. 8 legacy workspace-папок без Forgejo — вне scopeapp.ini, webhooks, CI secrets — вне scope (это уровень B, forgejo dump, отдельная задача)opencode-memory/.rag/, 200 МБ) НЕ бэкапим — перестраивается за 32 сек черезmemory-saveforgejo-infraрепо (reproducible setup), его git-mirror уже покрывает восстановление конфигурацииГраничные случаи
forgejo-infraесть на Forgejo, но НЕ имеет локального clone'а в/root/workspace/— настройка push mirror только через API, не через локальные git-операцииline,side,path) может теряться при переимпорте, сохраняем как обычные комментарии с пометкой "review comment on file X line Y"original_idв начале body или по labelmigrated-from:{original_id}и пропускать существующиеВлияние на связанные компоненты
forgejo-infraрепо — добавится Forgejo Actions workflowbackup-export.yml(schedule daily) +forgejo-restore.shскрипт + документация в READMEforgejo-archive(вручную пользователем или через API)opencode-memory— добавляется push mirror, но настройки делаются через Forgejo API (не локально), так как memory живёт вне workspaceAGENTS.mdв opencode-config — добавить процедуру disaster recovery в раздел docs/ (короткий how-to: "если Forgejo упал — как восстановить")Вне scope
forgejo dump(БД + app.ini + users + tokens + webhooks + LFS + attachments) с шифрованием и хранением на отдельной VPS — отдельная задачаarena-models,slaid098,slaid098-dev,video_uniq,voice_assistant,youtube-kit,youtube-soft,salvage-slaid098) — постепенный перенос потомКритерии приемки
opencode-config,opencode-voice-dictation,forgejo-infra,opencode-memory,forgejo-archiveforgejo-infraдобавлен Forgejo Actions workflow.forgejo/workflows/backup-export.yml— schedule daily, экспортирует issues/PR/comments/labels/milestones из 4 репоarchive/{repo}/issues/{N}.json+.md+archive/{repo}/pulls/{N}.json+.md+archive/{repo}/labels.json+archive/{repo}/milestones.json+archive/meta.jsonforgejo-archiveрепо на внешнем хосте (через HTTPS + token)forgejo-restore.shвforgejo-infra: читает archive → через API воссоздаёт labels/milestones/issues/PR/comments на новом Forgejo инстансе, идемпотентный (пропускает уже мигрированные)forgejo-infra/README.md: процедура disaster recovery одной командой, предпосылки (внешний токен, чистый Forgejo), шаги восстановленияopencode-config/docs/decisions/(новый ADR) — фиксирует решение об уровне A, выбранном хостинге, и ссылку на эту issue