Skip to content

Commit 3fd9fdc

Browse files
authored
chore: add zed config for debugging (baserow#5441)
1 parent 571a4fc commit 3fd9fdc

6 files changed

Lines changed: 374 additions & 0 deletions

File tree

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ out/
130130
.vscode/
131131
!config/vscode/.vscode/
132132

133+
# zed config files
134+
.zed
135+
!config/zed/.zed
136+
133137
# cursor editor config files
134138
.cursor-config/
135139
!config/cursor/.cursor-config/

backend/justfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ help:
4444
@echo "IDE Setup:"
4545
@echo " docs/development/vscode-setup.md - VS Code configuration"
4646
@echo " docs/development/intellij-setup.md - IntelliJ/PyCharm setup"
47+
@echo " docs/development/zed-setup.md - Zed editor setup"
4748
@echo ""
4849
@echo "Other:"
4950
@echo " docs/development/justfile.md - Just command reference"

config/zed/.zed/debug.json

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
// Zed debugger configurations for Baserow — shared/public baseline.
2+
//
3+
// ─── How to install ───────────────────────────────────────────────────────────
4+
// Run the following from the repository root:
5+
// config/zed/apply_standard_baserow_zed_config.sh
6+
// This copies config/zed/.zed/ → .zed/ (overwriting any existing file).
7+
//
8+
// ─── Personal customisations ──────────────────────────────────────────────────
9+
// After running the script, open .zed/debug.json and add:
10+
// • Extra env vars specific to your environment (BASEROW_PUBLIC_URL, etc.)
11+
// • Additional launch configs for your own workflows (frontend, gunicorn, …)
12+
// .zed/ at the worktree root is git-ignored, so your edits are private.
13+
//
14+
// NO SECRETS are stored in this file — it is tracked in git and shared with
15+
// all Baserow contributors. Add any personal or sensitive env vars only to
16+
// .zed/debug.json after the script has copied it.
17+
//
18+
// ─── Adapter ──────────────────────────────────────────────────────────────────
19+
// All configs below use the Debugpy adapter. Zed will auto-install it on
20+
// first use. Open the Debug panel (Cmd-Shift-D / Ctrl-Shift-D) or run
21+
// `debugger: start` from the command palette to pick a configuration.
22+
[
23+
{
24+
// ── backend: django runserver (launch) ─────────────────────────────────
25+
//
26+
// Starts the Django dev server under Debugpy so you can set breakpoints
27+
// directly in the editor and have them hit on incoming requests.
28+
//
29+
// WHY --noreload IS REQUIRED FOR BREAKPOINTS
30+
// Django's autoreloader works by forking a child process (identified by
31+
// the RUN_MAIN env var) that actually handles HTTP requests, while the
32+
// parent process monitors source files for changes. Debugpy is attached
33+
// to the *parent* at launch time, so any breakpoints you set in view or
34+
// model code are in the wrong process — they are never reached.
35+
//
36+
// --noreload disables the fork entirely: Django runs single-process, and
37+
// Debugpy (plus your breakpoints) lives in the same process that handles
38+
// every request. The trade-off is that you must restart this config
39+
// manually after editing Python source files.
40+
//
41+
// WHY `program` AND NOT `module`
42+
// Using `module: "baserow"` tells Debugpy to run `python -m baserow`.
43+
// The baserow __main__.py hands control to Django's execute_from_command_
44+
// line(), which then re-invokes the autoreloader machinery *before*
45+
// Debugpy can intercept the fork. Pointing `program` at the entry-point
46+
// script bypasses that re-invocation path.
47+
//
48+
// ALTERNATIVE — if you need hot-reloading or are using Docker:
49+
// Use the "backend: django (attach to :5678)" config below instead.
50+
// It attaches *inside* the RUN_MAIN child where requests are handled,
51+
// so breakpoints work even with the autoreloader enabled.
52+
"label": "backend: django runserver (launch)",
53+
"adapter": "Debugpy",
54+
"request": "launch",
55+
"program": "$ZED_WORKTREE_ROOT/backend/baserow",
56+
"args": ["runserver", "--noreload", "0.0.0.0:8000"],
57+
"cwd": "$ZED_WORKTREE_ROOT",
58+
"python": "$ZED_WORKTREE_ROOT/.venv/bin/python",
59+
"django": true,
60+
"justMyCode": false,
61+
"console": "integratedTerminal",
62+
"env": {
63+
// Relative paths work because cwd is the worktree root.
64+
"PYTHONPATH": "backend/src:premium/backend/src:enterprise/backend/src",
65+
"DJANGO_SETTINGS_MODULE": "baserow.config.settings.dev",
66+
// Point at your local Postgres. Override in .zed/debug.json if needed.
67+
"DATABASE_HOST": "localhost",
68+
},
69+
},
70+
{
71+
// ── backend: django (attach to :5678) ──────────────────────────────────
72+
//
73+
// Attaches Zed's debugger to a Django dev-server that is already listening
74+
// for a Debugpy client on port 5678. This is the recommended approach
75+
// when you want breakpoints *and* hot-reloading at the same time.
76+
//
77+
// HOW TO USE (local venv)
78+
// 1. Start the backend with the debugger enabled:
79+
// BASEROW_BACKEND_DEBUGGER_ENABLED=1 just b run-dev-server
80+
// With that env var set, manage.py calls `debugpy.listen(5678)` and
81+
// then `debugpy.wait_for_client()` inside the RUN_MAIN child process
82+
// — the process that actually handles HTTP requests.
83+
// 2. Wait until you see "Debugpy waiting for client…" in the terminal.
84+
// 3. Launch this config from the Debug panel. Debugpy will resume the
85+
// server and breakpoints will be hit on the next request.
86+
//
87+
// HOW TO USE (Docker dev env)
88+
// Works identically with `just dc-dev up` once you set
89+
// BASEROW_BACKEND_DEBUGGER_ENABLED=1 in your docker-compose override.
90+
// The backend container already maps container port 5678 → host 5678.
91+
// The pathMappings below translate container paths to your local
92+
// worktree so that editor breakpoints resolve correctly.
93+
"label": "backend: django (attach to :5678)",
94+
"adapter": "Debugpy",
95+
"request": "attach",
96+
"tcp_connection": { "host": "127.0.0.1", "port": 5678 },
97+
"cwd": "$ZED_WORKTREE_ROOT",
98+
"django": true,
99+
"justMyCode": false,
100+
"pathMappings": [
101+
{
102+
"localRoot": "$ZED_WORKTREE_ROOT",
103+
"remoteRoot": "/baserow",
104+
},
105+
],
106+
},
107+
{
108+
// ── backend: celery worker (launch) ────────────────────────────────────
109+
//
110+
// Starts a Celery worker under Debugpy. Set breakpoints inside task
111+
// functions and they will be hit when a task is dispatched.
112+
//
113+
// --pool=solo runs Celery in single-threaded mode (no subprocess pool),
114+
// which is required for Debugpy breakpoints to work reliably — the pool
115+
// strategies that use forked sub-processes suffer the same issue as the
116+
// Django autoreloader.
117+
//
118+
// Queues consumed by this worker:
119+
// celery — default / general task queue
120+
// export — file-export tasks (spreadsheet, PDF, …)
121+
// automation_workflow — automation trigger / action tasks
122+
"label": "backend: celery worker (launch)",
123+
"adapter": "Debugpy",
124+
"request": "launch",
125+
"module": "celery",
126+
"args": [
127+
"-A",
128+
"baserow",
129+
"worker",
130+
"-Q",
131+
"celery,export,automation_workflow",
132+
"-l",
133+
"INFO",
134+
"--pool=solo",
135+
],
136+
"cwd": "$ZED_WORKTREE_ROOT",
137+
"python": "$ZED_WORKTREE_ROOT/.venv/bin/python",
138+
"justMyCode": false,
139+
"console": "integratedTerminal",
140+
"env": {
141+
"PYTHONPATH": "backend/src:premium/backend/src:enterprise/backend/src",
142+
"DJANGO_SETTINGS_MODULE": "baserow.config.settings.dev",
143+
"DATABASE_HOST": "localhost",
144+
},
145+
},
146+
{
147+
// ── backend: pytest current file ───────────────────────────────────────
148+
//
149+
// Runs pytest against whichever test file is currently open/focused in Zed.
150+
// Make sure the test file is the active editor tab before launching.
151+
//
152+
// -v one line per test with pass/fail status
153+
// -s disable output capture so print() calls and logging appear inline
154+
// (useful when debugging a single failing test)
155+
"label": "backend: pytest current file",
156+
"adapter": "Debugpy",
157+
"request": "launch",
158+
"module": "pytest",
159+
"args": ["$ZED_FILE", "-v", "-s"],
160+
"cwd": "$ZED_WORKTREE_ROOT/backend",
161+
"python": "$ZED_WORKTREE_ROOT/.venv/bin/python",
162+
"justMyCode": false,
163+
"console": "integratedTerminal",
164+
"env": {
165+
// Absolute paths are required here because cwd is the backend sub-directory,
166+
// not the worktree root, so relative paths would not resolve correctly.
167+
"PYTHONPATH": "$ZED_WORKTREE_ROOT/backend/src:$ZED_WORKTREE_ROOT/premium/backend/src:$ZED_WORKTREE_ROOT/enterprise/backend/src:$ZED_WORKTREE_ROOT/backend/flake8_plugins",
168+
"DJANGO_SETTINGS_MODULE": "baserow.config.settings.test",
169+
"DATABASE_HOST": "localhost",
170+
},
171+
},
172+
{
173+
// ── backend: pytest all (with coverage) ────────────────────────────────
174+
//
175+
// Runs the complete backend test suite across core, premium, and enterprise
176+
// packages and produces an XML coverage report.
177+
//
178+
// This can take several minutes on a full run. The report is written to:
179+
// <worktree-root>/html_coverage/cov.xml
180+
//
181+
// -n=auto parallelises test collection and execution across all available
182+
// CPU cores via pytest-xdist, significantly reducing wall-clock
183+
// time. Note: parallel runs disable Debugpy breakpoints — remove
184+
// this flag if you need to step through code during a full run.
185+
"label": "backend: pytest all (with coverage)",
186+
"adapter": "Debugpy",
187+
"request": "launch",
188+
"module": "pytest",
189+
"args": [
190+
"-n=auto",
191+
"--cov-report=xml:html_coverage/cov.xml",
192+
"--cov-config=$ZED_WORKTREE_ROOT/backend/.coveragerc",
193+
"--cov=baserow",
194+
"backend/tests/",
195+
"premium/backend/tests/",
196+
"enterprise/backend/tests/",
197+
],
198+
"cwd": "$ZED_WORKTREE_ROOT",
199+
"python": "$ZED_WORKTREE_ROOT/.venv/bin/python",
200+
"justMyCode": false,
201+
"console": "integratedTerminal",
202+
"env": {
203+
"PYTHONPATH": "backend/src:premium/backend/src:enterprise/backend/src",
204+
"DJANGO_SETTINGS_MODULE": "baserow.config.settings.test",
205+
"DATABASE_HOST": "localhost",
206+
},
207+
},
208+
]

config/zed/.zed/settings.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Project-level Zed settings for Baserow.
2+
// Copied into `<repo>/.zed/settings.json` by
3+
// `config/zed/apply_standard_baserow_zed_config.sh`.
4+
{
5+
"languages": {
6+
"Python": {
7+
"language_servers": ["pyright", "ruff"],
8+
"formatter": [
9+
{ "language_server": { "name": "ruff" } }
10+
],
11+
"format_on_save": "on"
12+
}
13+
},
14+
"lsp": {
15+
"pyright": {
16+
"settings": {
17+
"python": {
18+
"pythonPath": ".venv/bin/python"
19+
},
20+
"python.analysis": {
21+
"extraPaths": [
22+
"backend/src",
23+
"premium/backend/src",
24+
"enterprise/backend/src"
25+
]
26+
}
27+
}
28+
}
29+
}
30+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/bin/bash
2+
# Bash strict mode: http://redsymbol.net/articles/unofficial-bash-strict-mode/
3+
set -euo pipefail
4+
5+
RED=$(tput setaf 1)
6+
GREEN=$(tput setaf 2)
7+
YELLOW=$(tput setaf 3)
8+
NC=$(tput sgr0) # No Color
9+
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
10+
echo # (optional) move to a new line
11+
if [[ $REPLY =~ ^[Yy]$ ]]
12+
then
13+
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
14+
cp -a "${SCRIPT_DIR}/.zed" "${SCRIPT_DIR}/../../"
15+
echo "${GREEN}Successfully applied the default Baserow Zed config...${NC}"
16+
else
17+
echo "${RED}Aborted application of the default Baserow Zed config...${NC}"
18+
fi

docs/development/zed-setup.md

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# Zed Setup
2+
3+
This guide explains how to use [Zed](https://zed.dev) with Baserow, including the
4+
Python/Django debugger configurations that ship with the repo.
5+
6+
## Prerequisites
7+
8+
- [just](https://github.com/casey/just)
9+
- [uv](https://github.com/astral-sh/uv)
10+
- A local backend virtualenv created by `just b init` (lives at `.venv/`)
11+
12+
## Apply the standard config
13+
14+
From the repo root run:
15+
16+
```bash
17+
./config/zed/apply_standard_baserow_zed_config.sh
18+
```
19+
20+
This copies `config/zed/.zed/` into `<repo>/.zed/`, giving you:
21+
22+
- `.zed/debug.json` — Debug Adapter Protocol (Debugpy) configurations
23+
- `.zed/settings.json` — Python LSP (`pyright` + `ruff`) extra paths
24+
25+
You can also copy the files manually if you prefer to merge by hand.
26+
27+
> **Personal customisations**`.zed/` at the repo root is git-ignored, so any
28+
> changes you make after running the script are private to your machine. Add
29+
> extra env vars, additional launch configs, or personal secrets directly to
30+
> `.zed/debug.json` without worrying about committing them.
31+
32+
## Debug configurations
33+
34+
Open the debug panel in Zed (`cmd-shift-d` / `ctrl-shift-d`) or run the
35+
`debugger: start` command, then pick one of:
36+
37+
### backend: django runserver (launch)
38+
39+
Starts the Django dev server single-process under Debugpy. Breakpoints set in
40+
view/model code are hit on the next matching request.
41+
42+
> **Why `--noreload`?** Django's autoreloader forks a child process to handle
43+
> HTTP requests while the parent watches source files. Debugpy attaches to the
44+
> parent, so without `--noreload` breakpoints in request-handling code are never
45+
> reached. The trade-off is that you must **restart the debug session manually**
46+
> after editing Python source files.
47+
>
48+
> If you need hot-reloading, use the attach config below instead.
49+
50+
### backend: django (attach to :5678)
51+
52+
Attaches to an already-running Django process that is listening for a Debugpy
53+
client on port 5678. This is the **recommended approach for local development**
54+
because breakpoints work correctly *and* the autoreloader stays enabled.
55+
56+
**Local venv workflow:**
57+
58+
```bash
59+
BASEROW_BACKEND_DEBUGGER_ENABLED=1 just b run-dev-server
60+
```
61+
62+
With that env var set, `manage.py` calls `debugpy.listen(5678)` inside the
63+
`RUN_MAIN` child process — the process that actually handles HTTP requests.
64+
Once you see the server start up, launch this config from the Debug panel to
65+
attach.
66+
67+
**Docker dev env workflow:**
68+
69+
```bash
70+
just dc-dev up -d
71+
```
72+
73+
The backend container already maps container port 5678 → host 5678. Set
74+
`BASEROW_BACKEND_DEBUGGER_ENABLED=1` in your `docker-compose.override.yml` and
75+
then attach as above.
76+
77+
### backend: celery worker (launch)
78+
79+
Runs a Celery worker under Debugpy in single-threaded mode (`--pool=solo`).
80+
Breakpoints set inside task functions are hit when a task is dispatched.
81+
82+
> `--pool=solo` is required for the same reason as `--noreload` above — pool
83+
> strategies that use forked sub-processes put the task execution in a child
84+
> that Debugpy is not attached to.
85+
86+
Queues consumed: `celery`, `export`, `automation_workflow`.
87+
88+
### backend: pytest current file
89+
90+
Runs `pytest` on the file that is currently open and focused in the editor.
91+
Make sure the test file is the active tab before launching this config.
92+
93+
### backend: pytest all (with coverage)
94+
95+
Runs the full core + premium + enterprise test suite with coverage, writing an
96+
XML report to `html_coverage/cov.xml`.
97+
98+
> `-n=auto` parallelises execution across all CPU cores, which significantly
99+
> reduces wall-clock time but **disables Debugpy breakpoints**. Remove that
100+
> flag from `.zed/debug.json` if you need to step through code during a full
101+
> run.
102+
103+
## Interpreter path
104+
105+
All launch configs expect the virtualenv at `.venv/bin/python` (created by
106+
`just b init`). If your interpreter lives elsewhere, update the `python` field
107+
in `.zed/debug.json`.
108+
109+
## See also
110+
111+
- `docs/development/debugging.md``snoop`, `django-silk`, `flower`, etc.
112+
- `docs/development/vscode-setup.md` — equivalent VSCode setup
113+
- `docs/development/running-tests.md` — full test command reference

0 commit comments

Comments
 (0)