From 3fd9fdc09e40a78537c762b1257e4ff0fc06ca10 Mon Sep 17 00:00:00 2001 From: alamin-br Date: Tue, 2 Jun 2026 09:05:27 +0200 Subject: [PATCH] chore: add zed config for debugging (#5441) --- .gitignore | 4 + backend/justfile | 1 + config/zed/.zed/debug.json | 208 ++++++++++++++++++ config/zed/.zed/settings.json | 30 +++ .../zed/apply_standard_baserow_zed_config.sh | 18 ++ docs/development/zed-setup.md | 113 ++++++++++ 6 files changed, 374 insertions(+) create mode 100644 config/zed/.zed/debug.json create mode 100644 config/zed/.zed/settings.json create mode 100755 config/zed/apply_standard_baserow_zed_config.sh create mode 100644 docs/development/zed-setup.md diff --git a/.gitignore b/.gitignore index a904272551..04013ab2d9 100644 --- a/.gitignore +++ b/.gitignore @@ -130,6 +130,10 @@ out/ .vscode/ !config/vscode/.vscode/ +# zed config files +.zed +!config/zed/.zed + # cursor editor config files .cursor-config/ !config/cursor/.cursor-config/ diff --git a/backend/justfile b/backend/justfile index a8cc324805..6fd6de5a89 100644 --- a/backend/justfile +++ b/backend/justfile @@ -44,6 +44,7 @@ help: @echo "IDE Setup:" @echo " docs/development/vscode-setup.md - VS Code configuration" @echo " docs/development/intellij-setup.md - IntelliJ/PyCharm setup" + @echo " docs/development/zed-setup.md - Zed editor setup" @echo "" @echo "Other:" @echo " docs/development/justfile.md - Just command reference" diff --git a/config/zed/.zed/debug.json b/config/zed/.zed/debug.json new file mode 100644 index 0000000000..6d46193d0d --- /dev/null +++ b/config/zed/.zed/debug.json @@ -0,0 +1,208 @@ +// Zed debugger configurations for Baserow — shared/public baseline. +// +// ─── How to install ─────────────────────────────────────────────────────────── +// Run the following from the repository root: +// config/zed/apply_standard_baserow_zed_config.sh +// This copies config/zed/.zed/ → .zed/ (overwriting any existing file). +// +// ─── Personal customisations ────────────────────────────────────────────────── +// After running the script, open .zed/debug.json and add: +// • Extra env vars specific to your environment (BASEROW_PUBLIC_URL, etc.) +// • Additional launch configs for your own workflows (frontend, gunicorn, …) +// .zed/ at the worktree root is git-ignored, so your edits are private. +// +// NO SECRETS are stored in this file — it is tracked in git and shared with +// all Baserow contributors. Add any personal or sensitive env vars only to +// .zed/debug.json after the script has copied it. +// +// ─── Adapter ────────────────────────────────────────────────────────────────── +// All configs below use the Debugpy adapter. Zed will auto-install it on +// first use. Open the Debug panel (Cmd-Shift-D / Ctrl-Shift-D) or run +// `debugger: start` from the command palette to pick a configuration. +[ + { + // ── backend: django runserver (launch) ───────────────────────────────── + // + // Starts the Django dev server under Debugpy so you can set breakpoints + // directly in the editor and have them hit on incoming requests. + // + // WHY --noreload IS REQUIRED FOR BREAKPOINTS + // Django's autoreloader works by forking a child process (identified by + // the RUN_MAIN env var) that actually handles HTTP requests, while the + // parent process monitors source files for changes. Debugpy is attached + // to the *parent* at launch time, so any breakpoints you set in view or + // model code are in the wrong process — they are never reached. + // + // --noreload disables the fork entirely: Django runs single-process, and + // Debugpy (plus your breakpoints) lives in the same process that handles + // every request. The trade-off is that you must restart this config + // manually after editing Python source files. + // + // WHY `program` AND NOT `module` + // Using `module: "baserow"` tells Debugpy to run `python -m baserow`. + // The baserow __main__.py hands control to Django's execute_from_command_ + // line(), which then re-invokes the autoreloader machinery *before* + // Debugpy can intercept the fork. Pointing `program` at the entry-point + // script bypasses that re-invocation path. + // + // ALTERNATIVE — if you need hot-reloading or are using Docker: + // Use the "backend: django (attach to :5678)" config below instead. + // It attaches *inside* the RUN_MAIN child where requests are handled, + // so breakpoints work even with the autoreloader enabled. + "label": "backend: django runserver (launch)", + "adapter": "Debugpy", + "request": "launch", + "program": "$ZED_WORKTREE_ROOT/backend/baserow", + "args": ["runserver", "--noreload", "0.0.0.0:8000"], + "cwd": "$ZED_WORKTREE_ROOT", + "python": "$ZED_WORKTREE_ROOT/.venv/bin/python", + "django": true, + "justMyCode": false, + "console": "integratedTerminal", + "env": { + // Relative paths work because cwd is the worktree root. + "PYTHONPATH": "backend/src:premium/backend/src:enterprise/backend/src", + "DJANGO_SETTINGS_MODULE": "baserow.config.settings.dev", + // Point at your local Postgres. Override in .zed/debug.json if needed. + "DATABASE_HOST": "localhost", + }, + }, + { + // ── backend: django (attach to :5678) ────────────────────────────────── + // + // Attaches Zed's debugger to a Django dev-server that is already listening + // for a Debugpy client on port 5678. This is the recommended approach + // when you want breakpoints *and* hot-reloading at the same time. + // + // HOW TO USE (local venv) + // 1. Start the backend with the debugger enabled: + // BASEROW_BACKEND_DEBUGGER_ENABLED=1 just b run-dev-server + // With that env var set, manage.py calls `debugpy.listen(5678)` and + // then `debugpy.wait_for_client()` inside the RUN_MAIN child process + // — the process that actually handles HTTP requests. + // 2. Wait until you see "Debugpy waiting for client…" in the terminal. + // 3. Launch this config from the Debug panel. Debugpy will resume the + // server and breakpoints will be hit on the next request. + // + // HOW TO USE (Docker dev env) + // Works identically with `just dc-dev up` once you set + // BASEROW_BACKEND_DEBUGGER_ENABLED=1 in your docker-compose override. + // The backend container already maps container port 5678 → host 5678. + // The pathMappings below translate container paths to your local + // worktree so that editor breakpoints resolve correctly. + "label": "backend: django (attach to :5678)", + "adapter": "Debugpy", + "request": "attach", + "tcp_connection": { "host": "127.0.0.1", "port": 5678 }, + "cwd": "$ZED_WORKTREE_ROOT", + "django": true, + "justMyCode": false, + "pathMappings": [ + { + "localRoot": "$ZED_WORKTREE_ROOT", + "remoteRoot": "/baserow", + }, + ], + }, + { + // ── backend: celery worker (launch) ──────────────────────────────────── + // + // Starts a Celery worker under Debugpy. Set breakpoints inside task + // functions and they will be hit when a task is dispatched. + // + // --pool=solo runs Celery in single-threaded mode (no subprocess pool), + // which is required for Debugpy breakpoints to work reliably — the pool + // strategies that use forked sub-processes suffer the same issue as the + // Django autoreloader. + // + // Queues consumed by this worker: + // celery — default / general task queue + // export — file-export tasks (spreadsheet, PDF, …) + // automation_workflow — automation trigger / action tasks + "label": "backend: celery worker (launch)", + "adapter": "Debugpy", + "request": "launch", + "module": "celery", + "args": [ + "-A", + "baserow", + "worker", + "-Q", + "celery,export,automation_workflow", + "-l", + "INFO", + "--pool=solo", + ], + "cwd": "$ZED_WORKTREE_ROOT", + "python": "$ZED_WORKTREE_ROOT/.venv/bin/python", + "justMyCode": false, + "console": "integratedTerminal", + "env": { + "PYTHONPATH": "backend/src:premium/backend/src:enterprise/backend/src", + "DJANGO_SETTINGS_MODULE": "baserow.config.settings.dev", + "DATABASE_HOST": "localhost", + }, + }, + { + // ── backend: pytest current file ─────────────────────────────────────── + // + // Runs pytest against whichever test file is currently open/focused in Zed. + // Make sure the test file is the active editor tab before launching. + // + // -v one line per test with pass/fail status + // -s disable output capture so print() calls and logging appear inline + // (useful when debugging a single failing test) + "label": "backend: pytest current file", + "adapter": "Debugpy", + "request": "launch", + "module": "pytest", + "args": ["$ZED_FILE", "-v", "-s"], + "cwd": "$ZED_WORKTREE_ROOT/backend", + "python": "$ZED_WORKTREE_ROOT/.venv/bin/python", + "justMyCode": false, + "console": "integratedTerminal", + "env": { + // Absolute paths are required here because cwd is the backend sub-directory, + // not the worktree root, so relative paths would not resolve correctly. + "PYTHONPATH": "$ZED_WORKTREE_ROOT/backend/src:$ZED_WORKTREE_ROOT/premium/backend/src:$ZED_WORKTREE_ROOT/enterprise/backend/src:$ZED_WORKTREE_ROOT/backend/flake8_plugins", + "DJANGO_SETTINGS_MODULE": "baserow.config.settings.test", + "DATABASE_HOST": "localhost", + }, + }, + { + // ── backend: pytest all (with coverage) ──────────────────────────────── + // + // Runs the complete backend test suite across core, premium, and enterprise + // packages and produces an XML coverage report. + // + // This can take several minutes on a full run. The report is written to: + // /html_coverage/cov.xml + // + // -n=auto parallelises test collection and execution across all available + // CPU cores via pytest-xdist, significantly reducing wall-clock + // time. Note: parallel runs disable Debugpy breakpoints — remove + // this flag if you need to step through code during a full run. + "label": "backend: pytest all (with coverage)", + "adapter": "Debugpy", + "request": "launch", + "module": "pytest", + "args": [ + "-n=auto", + "--cov-report=xml:html_coverage/cov.xml", + "--cov-config=$ZED_WORKTREE_ROOT/backend/.coveragerc", + "--cov=baserow", + "backend/tests/", + "premium/backend/tests/", + "enterprise/backend/tests/", + ], + "cwd": "$ZED_WORKTREE_ROOT", + "python": "$ZED_WORKTREE_ROOT/.venv/bin/python", + "justMyCode": false, + "console": "integratedTerminal", + "env": { + "PYTHONPATH": "backend/src:premium/backend/src:enterprise/backend/src", + "DJANGO_SETTINGS_MODULE": "baserow.config.settings.test", + "DATABASE_HOST": "localhost", + }, + }, +] diff --git a/config/zed/.zed/settings.json b/config/zed/.zed/settings.json new file mode 100644 index 0000000000..0900bdc4ba --- /dev/null +++ b/config/zed/.zed/settings.json @@ -0,0 +1,30 @@ +// Project-level Zed settings for Baserow. +// Copied into `/.zed/settings.json` by +// `config/zed/apply_standard_baserow_zed_config.sh`. +{ + "languages": { + "Python": { + "language_servers": ["pyright", "ruff"], + "formatter": [ + { "language_server": { "name": "ruff" } } + ], + "format_on_save": "on" + } + }, + "lsp": { + "pyright": { + "settings": { + "python": { + "pythonPath": ".venv/bin/python" + }, + "python.analysis": { + "extraPaths": [ + "backend/src", + "premium/backend/src", + "enterprise/backend/src" + ] + } + } + } + } +} diff --git a/config/zed/apply_standard_baserow_zed_config.sh b/config/zed/apply_standard_baserow_zed_config.sh new file mode 100755 index 0000000000..f06ab2d6b3 --- /dev/null +++ b/config/zed/apply_standard_baserow_zed_config.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# Bash strict mode: http://redsymbol.net/articles/unofficial-bash-strict-mode/ +set -euo pipefail + +RED=$(tput setaf 1) +GREEN=$(tput setaf 2) +YELLOW=$(tput setaf 3) +NC=$(tput sgr0) # No Color +read -p "${YELLOW}This script will overwrite any existing Zed config you might already have for this Baserow repo with a standard set of config, are you sure? ${NC}${GREEN}Enter Y or y to continue${NC}${RED}, or any other character to abort.${NC}" -n 1 -r +echo # (optional) move to a new line +if [[ $REPLY =~ ^[Yy]$ ]] +then +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +cp -a "${SCRIPT_DIR}/.zed" "${SCRIPT_DIR}/../../" +echo "${GREEN}Successfully applied the default Baserow Zed config...${NC}" +else +echo "${RED}Aborted application of the default Baserow Zed config...${NC}" +fi diff --git a/docs/development/zed-setup.md b/docs/development/zed-setup.md new file mode 100644 index 0000000000..3dc93595cc --- /dev/null +++ b/docs/development/zed-setup.md @@ -0,0 +1,113 @@ +# Zed Setup + +This guide explains how to use [Zed](https://zed.dev) with Baserow, including the +Python/Django debugger configurations that ship with the repo. + +## Prerequisites + +- [just](https://github.com/casey/just) +- [uv](https://github.com/astral-sh/uv) +- A local backend virtualenv created by `just b init` (lives at `.venv/`) + +## Apply the standard config + +From the repo root run: + +```bash +./config/zed/apply_standard_baserow_zed_config.sh +``` + +This copies `config/zed/.zed/` into `/.zed/`, giving you: + +- `.zed/debug.json` — Debug Adapter Protocol (Debugpy) configurations +- `.zed/settings.json` — Python LSP (`pyright` + `ruff`) extra paths + +You can also copy the files manually if you prefer to merge by hand. + +> **Personal customisations** — `.zed/` at the repo root is git-ignored, so any +> changes you make after running the script are private to your machine. Add +> extra env vars, additional launch configs, or personal secrets directly to +> `.zed/debug.json` without worrying about committing them. + +## Debug configurations + +Open the debug panel in Zed (`cmd-shift-d` / `ctrl-shift-d`) or run the +`debugger: start` command, then pick one of: + +### backend: django runserver (launch) + +Starts the Django dev server single-process under Debugpy. Breakpoints set in +view/model code are hit on the next matching request. + +> **Why `--noreload`?** Django's autoreloader forks a child process to handle +> HTTP requests while the parent watches source files. Debugpy attaches to the +> parent, so without `--noreload` breakpoints in request-handling code are never +> reached. The trade-off is that you must **restart the debug session manually** +> after editing Python source files. +> +> If you need hot-reloading, use the attach config below instead. + +### backend: django (attach to :5678) + +Attaches to an already-running Django process that is listening for a Debugpy +client on port 5678. This is the **recommended approach for local development** +because breakpoints work correctly *and* the autoreloader stays enabled. + +**Local venv workflow:** + +```bash +BASEROW_BACKEND_DEBUGGER_ENABLED=1 just b run-dev-server +``` + +With that env var set, `manage.py` calls `debugpy.listen(5678)` inside the +`RUN_MAIN` child process — the process that actually handles HTTP requests. +Once you see the server start up, launch this config from the Debug panel to +attach. + +**Docker dev env workflow:** + +```bash +just dc-dev up -d +``` + +The backend container already maps container port 5678 → host 5678. Set +`BASEROW_BACKEND_DEBUGGER_ENABLED=1` in your `docker-compose.override.yml` and +then attach as above. + +### backend: celery worker (launch) + +Runs a Celery worker under Debugpy in single-threaded mode (`--pool=solo`). +Breakpoints set inside task functions are hit when a task is dispatched. + +> `--pool=solo` is required for the same reason as `--noreload` above — pool +> strategies that use forked sub-processes put the task execution in a child +> that Debugpy is not attached to. + +Queues consumed: `celery`, `export`, `automation_workflow`. + +### backend: pytest current file + +Runs `pytest` on the file that is currently open and focused in the editor. +Make sure the test file is the active tab before launching this config. + +### backend: pytest all (with coverage) + +Runs the full core + premium + enterprise test suite with coverage, writing an +XML report to `html_coverage/cov.xml`. + +> `-n=auto` parallelises execution across all CPU cores, which significantly +> reduces wall-clock time but **disables Debugpy breakpoints**. Remove that +> flag from `.zed/debug.json` if you need to step through code during a full +> run. + +## Interpreter path + +All launch configs expect the virtualenv at `.venv/bin/python` (created by +`just b init`). If your interpreter lives elsewhere, update the `python` field +in `.zed/debug.json`. + +## See also + +- `docs/development/debugging.md` — `snoop`, `django-silk`, `flower`, etc. +- `docs/development/vscode-setup.md` — equivalent VSCode setup +- `docs/development/running-tests.md` — full test command reference \ No newline at end of file