Skip to content
| Marketplace
Sign in
Visual Studio Code>Other>Frappe ToolsNew to Visual Studio Code? Get it now.
Frappe Tools

Frappe Tools

code4bones

| (0) | Free
Развернуть новый Frappe bench/site или продиагностировать сломанный — прямо из VS Code / code-server.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

frappe-tools — VS Code расширение для провижининга Frappe bench

VS Code Marketplace Installs Rating License: MIT

→ Установить с VS Code Marketplace

Нишевый add-on поверх vscode-web (браузерный code-server, репозиторий gitlab:prj/vscode-web.git), не часть его базового функционала. Решает конкретную боль: разработчики Frappe-стендов либо роняют bench настолько, что проще пересобрать с нуля, либо приходят в команду без bench вообще, либо тратят время на ручную установку/обновление внутренних приложений команды. Ручные bench init/bench new-site/ bench get-app с правильными флагами (свой форк Frappe, пароли, доп. приложения, ветки) — источник ошибок копипаста. Расширение оборачивает штатный bench CLI в UI внутри VS Code. Системные зависимости (Postgres, Redis, Python, Node) считаются уже установленными на стенде — вне ответственности расширения.

Иконка расширения (images/icon.png/icon.svg, marketplace-иконка) — официальный текущий бренд-марк Frappe Framework (буква "F"), взят как есть из frappe/public/images/frappe-favicon.svg в самом фреймворке (frappe/frappe, без переработки). Иконка Activity Bar (images/activitybar.svg) — простая оригинальная монохромная пиктограмма (workbench), не логотип. Расширение не аффилировано с Frappe Technologies — сходство иконки с официальным брендом Frappe не означает официальной поддержки или одобрения со стороны Frappe Technologies.

UI: две точки входа

Иконка в Activity Bar ("Frappe Bench") открывает единственную докнутую панель — "Приложения": список репозиториев из GitLab- группы команды (см. §"Приложения из GitLab" ниже). Ничего, кроме этого списка, в сайдбаре нет осознанно — формы с полями (репо, ветка, пароли, домен) тесны в узкой боковой колонке, для них есть отдельная широкая панель.

Широкая панель с тремя вкладками — Установка | Диагностика | Настройки — открывается:

  • кнопкой (иконка "окно") в шапке панели "Приложения";
  • командами Command Palette (Ctrl+Shift+P): Frappe Bench: Развернуть новый bench, Frappe Bench: Диагностика, Frappe Bench: Настройки.

Это singleton WebviewPanel в области редактора (не в сайдбаре): повторное открытие поднимает уже существующую панель и переключает вкладку, а не плодит новые окна. Панель не закрывается сама после запуска развёртывания — прогресс идёт в отдельном терминале (VS Code Task), а форма остаётся на месте.

Вкладка "Установка"

Путь, форк/ветка Frappe, имя сайта, доп. приложения из настроек (чекбоксы), пароли — всё видно и редактируется сразу, без цепочки модальных промптов. По умолчанию имя инстанса — <unix-логин>_sandbox, путь — /var/www/html/<unix-логин>_sandbox (frappeBench.benchesRoot), по принятой в команде конвенции; путь под курсором проверяется на лету (свободен / уже пуст и переиспользуется / занят / там уже есть bench). Если путь занят — форма требует явно отметить "Снести и развернуть заново", иначе кнопка "Развернуть" остаётся неактивной; старая директория при этом переименовывается (<path>.old-<timestamp>), не удаляется. Весь вывод скрипта дублируется в ~/frappe-bench-tools-logs/<имя bench>-<timestamp>.log (0600, переживает сам скрипт — тот удаляет только себя) — терминал VS Code свой буфер на диск не пишет, без файла разбирать проблему после закрытия панели/перезапуска стенда было бы не по чему. По подтверждению собирается один bash-скрипт (бэкап старого при конфликте → sudo install -d под целевую директорию → bench init ... --dev → bench get-app×N → bench new-site → симлинк $HOME/<имя> → опционально nginx, см. ниже) и запускается как VS Code Task (виден в терминале целиком, ничего не скрыто в фоновом процессе). /var/www/html обычно не в собственности разработчика — создание/пересоздание поддиректории идёт через sudo (спросит пароль прямо в терминале, если нужно); дальше bench выполняется уже без sudo — сам bench отказывается работать от root.

Есть необязательное поле "Домен для nginx" — если заполнено:

  1. bench config dns_multitenant on — без этого bench setup nginx полностью игнорирует домены, добавленные через add-domain (сборка server_name для дополнительных доменов в bench/config/nginx.py идёт только в этой ветке) — запрос на домен молча падал в default-сайт nginx вместо нашего server-блока (поймано на живом прогоне).
  2. bench setup add-domain → bench setup nginx --yes --log_format none (без --log_format none bench подставляет свой дефолт main в access_log, а log_format main нигде не объявлен в дефолтном nginx на Debian/Ubuntu — nginx -t падает с "unknown log format "main""; тоже поймано на живом прогоне).
  3. Сканирование /etc/nginx/conf.d/*.conf и /etc/nginx/sites-enabled/* на файлы, уже упоминающие этот домен (типичная причина — остаток ручного эксперимента до автоматизации, встречалось на практике: он один способен ронять nginx -t, независимо от того, что мы сами генерируем корректно) — такие файлы переносятся в <файл>.old-<timestamp> (не удаляются).
  4. Подключение сгенерированного config/nginx.conf в /etc/nginx/conf.d/auto_<имя bench>.conf (префикс auto_ — чтобы сразу отличать конфиги этого расширения от ручных/легаси при поиске и чистке; уникальное имя на bench, не общий nginx.conf, чтобы не конфликтовать с другими пользователями стенда) → sudo nginx -t → reload только при успешном тесте (при ошибке симлинк снимается обратно, общий nginx не трогается — тот же принцип, что у vscode-web).
  5. Если установлен supervisorctl (проверяется явно — если нет, печатается понятный WARN с командой установки, остальная часть скрипта не падает): сперва проверка владельца процесса на каждом из 4 наших портов (ss -ltnp → PID → ps -o user=) — если порт уже занят, но процесс принадлежит другому Unix- пользователю, скрипт немедленно останавливается с ошибкой и ничего не трогает (не наш namespace, не наша территория). Если процесс свой же (старый namespace этого пользователя, например переустановка поверх уже существующего своего bench) — не страшно, restart ниже его корректно заменит. Проверка построена на sudo ss ... | grep ... | head -1 || true — без || true set -o pipefail валит весь скрипт молча на первом же свободном порту (grep без совпадения возвращает 1), это штатный, а не ошибочный исход (поймано на живом прогоне: скрипт обрывался без единой строки ошибки в логе). Дальше: bench setup supervisor --yes → подключение config/supervisor.conf в /etc/supervisor/conf.d/auto_<имя bench>.conf → supervisorctl reread && update → явный supervisorctl restart <имя>-web: <имя>-workers: <имя>-redis:. Без домена никто бы вообще не слушал выделенные порты; но и с доменом одного update недостаточно на переустановке — update сравнивает только командную строку процессов в самом supervisor.conf (она не меняется, redis-server всегда запускается одной и той же командой), не содержимое файлов (config/redis_{cache,queue}.conf), которые эти процессы читают при своём старте. Уже запущенный со старой переустановки redis-server не заметит, что порт в файле сменился, без явного restart (поймано на живом прогоне: сайт логинился, но Redis слушал старый порт). Штатный bench restart тут не спасает — проверено в исходниках: он рестартует -web:/-workers:, но никогда -redis:.

Порты — по UID, детерминированно (src/benchPorts.ts, тот же принцип, что vscode-web уже применяет для code-server — 20000+uid): webserver_port/socketio_port/redis_cache/ redis_queue у bench по умолчанию одинаковы для любого bench на машине (8000/9000/13000/11000) — на живом прогоне с несколькими bench на одном стенде это гарантированный конфликт, поймано вживую. Расширение выставляет все четыре через bench set-config -g сразу после bench init (плюс bench setup redis, чтобы перегенерировать config/redis_{cache,queue}.conf под новые порты — bench setup supervisor сам их не создаёт, только ссылается на уже лежащие файлы) — детерминированно от UID разработчика: разные пользователи никогда не пересекутся, а переустановка своего же bench каждый раз попадает на те же порты.

webserver_port/socketio_port выставляются через bench set-config -g -p — -p/--parse обязателен. Без него bench пишет значение в common_site_config.json строкой, а не числом; и это не только про наш собственный bench — bench init у любого другого bench в том же benchesRoot сканирует порты всех соседних bench (make_ports() в bench/config/common_site_config.py), чтобы подобрать свободный следующий, и падает с TypeError: '>' not supported between instances of 'str' and 'int', если наткнётся на смешанный список int/str. Поймано вживую ровно так: bench, развёрнутый без -p, спокойно встал сам, но сломал bench init у следующего разработчика, попытавшегося развернуть свой bench на том же shared-стенде.

Форма запоминает значения между запусками (форк/ветка Frappe, выбранные доп. приложения, симлинк, домен для nginx, путь последнего развёрнутого bench) через context.globalState — кроме паролей, те принципиально нигде не сохраняются, вводятся заново каждый раз.

Вкладка "Диагностика"

Read-only проверки структуры bench, доступности Postgres/Redis, git-состояния apps/frappe, наличия и корректности симлинка в $HOME — результат рендерится прямо во вкладке. Путь к bench подставляется автоматически: открытая workspace-папка, если это сам bench → иначе последний развёрнутый через "Установку" путь → иначе <benchesRoot>/<unix-логин>_sandbox по конвенции (та же цепочка фолбэков используется и панелью "Приложения", detectCurrentBenchPath() в src/benchFs.ts). При структурной поломке предлагает "Пересобрать с нуля": старая директория переименовывается (<path>.broken-<timestamp>), не удаляется, и открывается вкладка "Установка" с предзаполненным именем.

Вкладка "Настройки"

GitLab Personal Access Token и URL группы, где живут приложения команды — см. следующий раздел. Чек-лист сверху вкладки сразу показывает, что уже настроено, а чего не хватает (актуально при первом запуске). PAT — единственный секрет, который расширение вообще хранит: не в settings.json, а в context.secrets (шифруется ОС), никогда не отображается обратно в UI (только флаг "сохранён/не сохранён").

Приложения из GitLab

Панель "Приложения" (Activity Bar) показывает репозитории из настроенной GitLab-группы (frappeBench.gitlabAppsGroupUrl + PAT из вкладки "Настройки") — GET /groups/:group/projects через PRIVATE-TOKEN. Пока PAT/URL не заданы — панель показывает viewsWelcome со ссылкой на "Настройки" вместо пустого списка.

Клик по приложению открывает панель деталей справа (ViewColumn.Beside) — единственный переиспользуемый webview (повторный клик по другому приложению просто обновляет его содержимое, не плодит окна). Никаких hover/context-menu иконок прямо на строке дерева — они оказались неочевидны на живом UX-тестировании. В панели деталей — выпадающий список веток (подтягивается через GET /projects/:id/repository/branches, тем же PAT; если запрос не успел или не удался — тихий фолбэк на default_branch) и контекстные кнопки:

  • не установлено → "Установить" (bench get-app + bench install-app) и "Восстановить из архива";
  • установлено → "Переустановить" (bench get-app --overwrite, штатная фича самого bench — никакого ручного git pull/bench build/bench migrate) и "Удалить".

Обе install/update-команды идут без --site — default_site уже прописан в common_site_config.json (провижининг всегда передаёт --set-default), bench сам его резолвит тем же механизмом, каким пользуется сам CLI.

Репозитории группы обычно приватные — PAT встраивается прямо в URL клонирования (https://oauth2:<pat>@host/..., GitLab проверяет пароль как PAT независимо от имени пользователя в URL). Это создаёт риск утечки: сам bench печатает полную команду $ git clone https://oauth2:<pat>@... в свой собственный вывод при каждом клонировании. Поэтому весь вывод любого сгенерированного скрипта идёт через redaction-фильтр (sed -E 's#://[^/@[:space:]]+@#://REDACTED@#g', scriptHeader() в src/scriptRunner.ts) до записи и на терминал, и в постоянный лог-файл — токен никогда не оседает открытым текстом ни там, ни там (проверено эмпирически: симуляция реального вывода git clone/ошибки авторизации через сгенерированный скрипт — в итоговом логе только REDACTED).

"Удалить" — bench uninstall-app <name> --yes (снять с сайта, сайт бэкапится по умолчанию) → bench remove-app <name> (убрать код из apps/). Модальное подтверждение перед запуском. Код не удаляется безвозвратно — bench архивирует его в archived/apps/<name>-<date>[_N] (штатный механизм самого remove() в исходниках bench, тот же самый, что срабатывает и при bench get-app --overwrite).

"Восстановить из архива" — решает конкретный живой сценарий: bench get-app --overwrite сначала архивирует старую копию (apps/<name> → archived/apps/<name>-<date>), и только потом клонирует заново; если клонирование падает (сеть, авторизация, не та ветка) — приложение полностью пропадает из apps/, хотя код цел и лежит в архиве. Кнопка показывает QuickPick по всем каталогам archived/apps/<name>-* (сортировка по времени изменения, новые сверху) — выбор восстанавливает архив в apps/<name> (cp -a) и перезапускает bench restart. Останавливается с ошибкой, если apps/<name> уже занято, вместо тихой перезаписи.

Защита от повторного клика: кнопки в панели деталей блокируются сразу на клике (клиентский JS, ждём bench get-app/uninstall-app — десятки секунд), плюс серверный guard в AppsTreeProvider не даёт запустить вторую операцию для того же приложения, пока первая ещё не завершилась — на случай гонки (двойной клик до того, как кнопка успела задизейблиться).

Настройки (frappeBench.*)

Настройка Назначение
frappeBench.frappeRepo URL репозитория Frappe (обычно — свой форк на GitLab)
frappeBench.frappeBranch ветка Frappe
frappeBench.benchesRoot базовая директория для новых bench (дефолт /var/www/html)
frappeBench.defaultApps список {name, repo, branch} для мультивыбора при развёртывании
frappeBench.pythonPath путь к Python
frappeBench.dbRootUser root-пользователь Postgres
frappeBench.createHomeSymlink создавать ли $HOME/<имя bench> → <benchesRoot>/<имя bench> (дефолт true)
frappeBench.gitlabAppsGroupUrl URL GitLab-группы с приложениями команды (например https://gitlab.example.com/team/apps) — для панели "Приложения"

PAT для GitLab не настройка — вводится и хранится отдельно, во вкладке "Настройки" (context.secrets), см. выше.

Пароли (root Postgres, Administrator) никогда не хранятся в настройках — расширение спрашивает их при каждом запуске мастера (type="password" в форме) и подставляет только во временный скрипт с правами 0600, который удаляет сам себя сразу после выполнения. У bench нет способа принять эти пароли иначе, чем аргументом командной строки — они неизбежно ненадолго видны в ps aux во время выполнения, это ограничение самого bench, не расширения.

Пример settings.json:

{
  "frappeBench.frappeRepo": "git@gitlab.example.com:team/frappe.git",
  "frappeBench.frappeBranch": "version-15-team",
  "frappeBench.defaultApps": [
    { "name": "team_app", "repo": "git@gitlab.example.com:team/team_app.git", "branch": "develop" }
  ],
  "frappeBench.gitlabAppsGroupUrl": "https://gitlab.example.com/team/apps"
}

Проверка обновлений (для code-server)

code-server (наш рантайм, vscode-web) умеет ставить расширения только из open-vsx.org — это зашито в бинаре, официальный VS Code Marketplace ему недоступен даже для внутреннего использования (Terms of Use Microsoft). Публикация frappe-tools на open-vsx.org уперлась в отдельный блокер (SSO-баг Eclipse Foundation при регистрации publisher-аккаунта) — до его решения расширение для code-server обновляется собственным механизмом, в обход Gallery API вообще.

Команда Frappe Bench: Проверить обновления (src/updateCheck.ts) дёргает манифест на собственном сервисе (updates.ide.undoo.ru, отдельный проект update-server, полная спецификация протокола — в его README) и, если там версия новее установленной, скачивает .vsix и ставит его через штатную workbench.extensions.installExtension (эта команда официально принимает Uri локального файла, не только id из маркета — отдельный "маркет" реализовывать не пришлось). Та же проверка тихо выполняется при активации расширения — недоступность сервиса при этом не показывает пользователю ничего, кроме записи в Output-канал "Frappe Bench" (сеть на shared-стенде не всегда стабильна, спам ошибками при каждом старте IDE был бы хуже отсутствия автопроверки).

Id компонента на сервере (frappe-tools, путь /v1/manifest/frappe-tools) — по договорённости совпадает с VS Code extension id, но формально это независимые вещи: сервер ничего не знает про publisher.name, id там — просто имя директории на хосте. Публикация новой версии на этот сервис — ./maintain.sh publish (см. ниже), не связана со сборкой самого .vsix.

Сборка

./maintain.sh build
# → dist/frappe-tools-<версия>.vsix

./maintain.sh help — список всех подкоманд (build, bump-version, release).

Установка

Для обычного desktop VS Code — стандартная установка через вкладку Extensions или ссылку на Marketplace вверху. Ниже — отдельный сценарий именно для команды: code-server (браузерный vscode-web) обычно не может ставить расширения напрямую из официального Marketplace Microsoft (лицензионное ограничение, а не техническое), поэтому для shared-стенда команды используется ручная установка .vsix.

Установка в code-server

Пакет не встроен в vscode-web и не разворачивается через ide-enroll — это сознательно (нишевый add-on, не часть базового функционала, см. §1 назначения выше). Устанавливать .vsix должен сам разработчик под своим Unix-логином: в shared-режиме у каждого пользователя свой code-server@<user>.service и своя изолированная папка расширений (~/.local/share/code-server/ extensions) — установка от чужого имени (ctrl/root) на других не подействует.

Проверенный способ — из шелла, с полным путём до бинаря. В самом пакете vscode-web нет code-server в $PATH — на пользовательские команды вынесены только ide-enroll/ide-unenroll/ ide-ctl (см. debian/vscode-web.install в репозитории vscode-web). Вендоренный бинарь, тот же самый, что реально исполняется в code-server@<user>.service, лежит по фиксированному внутреннему пути:

/opt/vscode-web/code-server/bin/code-server --install-extension dist/frappe-tools-<версия>.vsix

Если где-то на стенде на $PATH случайно оказался другой code-server (например, поставленный отдельно через npm/pip на bench-стенде) — команда без полного пути либо не найдётся (command not found), либо, что хуже, тихо установит расширение не туда: в ~/.local/share/code-server того, другого инстанса, никак не связанного с реально работающим code-server@<user>.service. Внешне это выглядит как "ничего не произошло" — команда отрабатывает без ошибок, а расширение просто не появляется там, где ты его ждёшь. Полный путь до бинаря снимает эту неоднозначность.

Drag & drop .vsix работает не так, как в desktop VS Code, и на редактор/вкладку бросать бесполезно (при тесте — вообще никакой реакции). Причина не в vscode-web, а в самой архитектуре web-версии VS Code: у desktop-приложения (Electron) файл из drop-события несёт настоящий путь на диске, а у браузера — только blob в памяти без пути; при обычном drop на редактор код-сервер пытается собрать file:///extension-name.vsix и обратиться к "local extension service", которого в браузере физически не существует ([подробнее — обсуждение в coder/code-server #4897](https://github.com/coder/code-server/discussions/4897)).

Правильная зона для DnD — боковая панель Explorer (дерево файлов), не редактор: туда файл реально аплоадится на сервер как обычный файл, и дальше через Command Palette → Extensions: Install from VSIX... можно выбрать уже загруженный файл. Подтверждено вживую — сработало с первой попытки. Оба способа (CLI с полным путём и DnD на Explorer) рабочие; CLI чуть более предсказуем для скриптов/автоматизации, DnD — быстрее руками.

Иконка Frappe Bench в Activity Bar и команды Frappe Bench: ... в Command Palette появятся сразу после установки, без перезапуска code-server.

Отладка

F5 в VS Code (открыв этот репозиторий как workspace) поднимает Extension Development Host с уже загруженным расширением.

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2026 Microsoft