dbression 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. dbression-0.1.0/.github/workflows/ci.yml +58 -0
  2. dbression-0.1.0/.github/workflows/publish.yml +51 -0
  3. dbression-0.1.0/.gitignore +16 -0
  4. dbression-0.1.0/.python-version +1 -0
  5. dbression-0.1.0/CHANGELOG.md +65 -0
  6. dbression-0.1.0/LICENSE +21 -0
  7. dbression-0.1.0/PKG-INFO +390 -0
  8. dbression-0.1.0/README.md +353 -0
  9. dbression-0.1.0/examples/01-hello/HelloSql.test.md +13 -0
  10. dbression-0.1.0/examples/01-hello/_root.wiki +2 -0
  11. dbression-0.1.0/examples/01-hello/connection.properties +5 -0
  12. dbression-0.1.0/examples/02-stored-procedure/BumpCounterTest.test.md +34 -0
  13. dbression-0.1.0/examples/02-stored-procedure/SuiteSetUp.test.md +23 -0
  14. dbression-0.1.0/examples/02-stored-procedure/SuiteTearDown.test.md +9 -0
  15. dbression-0.1.0/examples/02-stored-procedure/_root.wiki +2 -0
  16. dbression-0.1.0/examples/02-stored-procedure/connection.properties +4 -0
  17. dbression-0.1.0/examples/03-schema-drift/SchemaSnapshotTest.test.md +17 -0
  18. dbression-0.1.0/examples/03-schema-drift/SuiteSetUp.test.md +14 -0
  19. dbression-0.1.0/examples/03-schema-drift/SuiteTearDown.test.md +6 -0
  20. dbression-0.1.0/examples/03-schema-drift/_root.wiki +2 -0
  21. dbression-0.1.0/examples/03-schema-drift/connection.properties +4 -0
  22. dbression-0.1.0/examples/README.md +23 -0
  23. dbression-0.1.0/pyproject.toml +70 -0
  24. dbression-0.1.0/src/dbression/__init__.py +1 -0
  25. dbression-0.1.0/src/dbression/cli.py +173 -0
  26. dbression-0.1.0/src/dbression/db/__init__.py +12 -0
  27. dbression-0.1.0/src/dbression/db/connection.py +104 -0
  28. dbression-0.1.0/src/dbression/db/engine.py +131 -0
  29. dbression-0.1.0/src/dbression/db/errors.py +63 -0
  30. dbression-0.1.0/src/dbression/fixtures/__init__.py +32 -0
  31. dbression-0.1.0/src/dbression/fixtures/base.py +89 -0
  32. dbression-0.1.0/src/dbression/fixtures/basic.py +628 -0
  33. dbression-0.1.0/src/dbression/fixtures/inspect_and_store.py +292 -0
  34. dbression-0.1.0/src/dbression/fixtures/plugins.py +92 -0
  35. dbression-0.1.0/src/dbression/fixtures/suite_fixtures.py +28 -0
  36. dbression-0.1.0/src/dbression/parser/__init__.py +4 -0
  37. dbression-0.1.0/src/dbression/parser/ast.py +66 -0
  38. dbression-0.1.0/src/dbression/parser/markdown.py +281 -0
  39. dbression-0.1.0/src/dbression/parser/markdown_writer.py +84 -0
  40. dbression-0.1.0/src/dbression/parser/tokenizer.py +208 -0
  41. dbression-0.1.0/src/dbression/parser/wiki.py +204 -0
  42. dbression-0.1.0/src/dbression/report/__init__.py +11 -0
  43. dbression-0.1.0/src/dbression/report/console.py +103 -0
  44. dbression-0.1.0/src/dbression/report/json_report.py +126 -0
  45. dbression-0.1.0/src/dbression/report/junit.py +188 -0
  46. dbression-0.1.0/src/dbression/runner.py +310 -0
  47. dbression-0.1.0/src/dbression/symbols.py +138 -0
  48. dbression-0.1.0/tests/conftest.py +34 -0
  49. dbression-0.1.0/tests/test_connection.py +36 -0
  50. dbression-0.1.0/tests/test_markdown_parser.py +133 -0
  51. dbression-0.1.0/tests/test_markdown_roundtrip.py +92 -0
  52. dbression-0.1.0/tests/test_parser.py +128 -0
  53. dbression-0.1.0/tests/test_phase2_fixtures.py +99 -0
  54. dbression-0.1.0/tests/test_plugins.py +93 -0
  55. dbression-0.1.0/tests/test_postgres_live.py +52 -0
  56. dbression-0.1.0/tests/test_report_junit.py +123 -0
  57. dbression-0.1.0/tests/test_smoke.py +31 -0
  58. dbression-0.1.0/tests/test_symbols.py +58 -0
  59. dbression-0.1.0/tests/test_tokenizer.py +79 -0
  60. dbression-0.1.0/tests/test_update_fixture.py +122 -0
  61. dbression-0.1.0/uv.lock +532 -0
@@ -0,0 +1,58 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ # Cancel in-progress runs for the same ref when a new commit arrives.
10
+ concurrency:
11
+ group: ci-${{ github.ref }}
12
+ cancel-in-progress: true
13
+
14
+ jobs:
15
+ test:
16
+ name: Tests (Python ${{ matrix.python }})
17
+ runs-on: ubuntu-latest
18
+ strategy:
19
+ fail-fast: false
20
+ matrix:
21
+ python: ['3.12', '3.13']
22
+
23
+ steps:
24
+ - uses: actions/checkout@v4
25
+
26
+ - name: Install uv
27
+ uses: astral-sh/setup-uv@v6
28
+ with:
29
+ enable-cache: true
30
+
31
+ - name: Set up Python ${{ matrix.python }}
32
+ run: uv python install ${{ matrix.python }}
33
+
34
+ - name: Install project + dev dependencies
35
+ run: uv sync --python ${{ matrix.python }}
36
+
37
+ # Live database tests are gated behind `skipif` on the presence of
38
+ # local connection.properties files — on CI runners they will skip
39
+ # automatically, so unit-only execution is the default here.
40
+ - name: Run tests
41
+ run: uv run python -m pytest -q --tb=short
42
+
43
+ build:
44
+ name: Build sdist + wheel
45
+ runs-on: ubuntu-latest
46
+ needs: test
47
+ steps:
48
+ - uses: actions/checkout@v4
49
+ - uses: astral-sh/setup-uv@v6
50
+ with:
51
+ enable-cache: true
52
+ - run: uv build
53
+ - name: Upload artifacts
54
+ uses: actions/upload-artifact@v4
55
+ with:
56
+ name: dist-${{ github.sha }}
57
+ path: dist/
58
+ retention-days: 7
@@ -0,0 +1,51 @@
1
+ name: Publish to PyPI
2
+
3
+ # Triggered when a GitHub Release is published. Tag the release with
4
+ # the version (e.g. `v0.2.0`) — the workflow builds wheel + sdist and
5
+ # publishes via PyPI Trusted Publishing (OIDC, no API token).
6
+ #
7
+ # One-time setup on PyPI: create a Trusted Publisher entry under
8
+ # https://pypi.org/manage/project/dbression/settings/publishing/
9
+ # with:
10
+ # * Owner: angrydat
11
+ # * Repository name: dbression
12
+ # * Workflow name: publish.yml
13
+ # * Environment: pypi
14
+ on:
15
+ release:
16
+ types: [published]
17
+
18
+ # Allow manual runs for emergencies / re-publishes from a tag.
19
+ workflow_dispatch:
20
+
21
+ jobs:
22
+ build:
23
+ name: Build distributions
24
+ runs-on: ubuntu-latest
25
+ steps:
26
+ - uses: actions/checkout@v4
27
+ - uses: astral-sh/setup-uv@v6
28
+ - run: uv build
29
+ - uses: actions/upload-artifact@v4
30
+ with:
31
+ name: dist
32
+ path: dist/
33
+
34
+ publish:
35
+ name: Publish to PyPI
36
+ needs: build
37
+ runs-on: ubuntu-latest
38
+ environment:
39
+ name: pypi
40
+ url: https://pypi.org/p/dbression
41
+ permissions:
42
+ id-token: write # required for Trusted Publishing (OIDC)
43
+ steps:
44
+ - uses: actions/download-artifact@v4
45
+ with:
46
+ name: dist
47
+ path: dist/
48
+ - uses: pypa/gh-action-pypi-publish@release/v1
49
+ with:
50
+ # Optional belt-and-braces: verify package metadata before upload.
51
+ verify-metadata: true
@@ -0,0 +1,16 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ # Oracle InstantClient (lokal, optional, ~90MB) — Pfad bei Bedarf via
13
+ # DBTEST_ORACLE_CLIENT_LIB_DIR an OracleAdapter weitergegeben.
14
+ .instantclient/
15
+ .idea/
16
+ dist/
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,65 @@
1
+ # Changelog
2
+
3
+ All notable changes to `dbression` are documented here.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project
6
+ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0] — 2026-05-29
11
+
12
+ Initial public release. Functional core that runs real-world DBFit suites against PostgreSQL,
13
+ with code paths in place for SQL Server and Oracle.
14
+
15
+ ### Added
16
+
17
+ - **Wiki parser** for the DBFit subset that real-world suites actually use, including
18
+ `!- ... -!` multi-line escapes, Oracle `q'~ ... ~'` custom quoting, YAML-style
19
+ front-matter for tags, and lenient detection of fixture-prefixed tables without `!|`.
20
+ - **Executable Markdown** (`.test.md`) — a Markdown-based test format that renders cleanly
21
+ in any viewer and runs the same way `.wiki` files do. Conventions: `### <Fixture> [args]`
22
+ headings, fenced ```` ```sql ```` blocks for SQL, Markdown tables for data rows, and
23
+ `<!-- dbression:env=… -->` style HTML-comment directives.
24
+ - **`dbression convert`** — one-shot or recursive migration tool that turns `.wiki` suites
25
+ into `.test.md`. Both formats coexist; Markdown wins at runtime.
26
+ - **Fixtures**:
27
+ - `Query` with `>>capture` / `<<read` / `:bind` / `_:text-substitution`
28
+ - `Execute` / `Execute Ddl`
29
+ - `Execute Procedure` (dialect-aware: `SELECT`/`CALL` for PG, `EXEC` for MSSQL,
30
+ `BEGIN…END;` for Oracle)
31
+ - `Execute Procedure Expect Exception` with SQLSTATE / ORA-code matching
32
+ - `Insert` (with `>>capture` via `RETURNING`) and `Delete`
33
+ - `Set Parameter` with Java-type-hint conversion
34
+ - `Inspect Table` / `Inspect View` / `Inspect Procedure` with optional body comparison
35
+ - `Store Query` and `Compare Stored Queries`
36
+ - **Multi-database support** via SQLAlchemy 2.0:
37
+ - PostgreSQL through `psycopg` v3 — live-verified
38
+ - SQL Server through `pymssql` (pure Python, no ODBC stack needed) — code-complete
39
+ - Oracle through `oracledb` (thin mode by default, optional thick mode via
40
+ `DBRESSION_ORACLE_CLIENT_LIB_DIR`) — code-complete
41
+ - **Runner** with a DBFit-compatible transaction model: one connection + one transaction
42
+ per suite, with savepoints per test for the default rollback-per-test isolation. A
43
+ `--commit-mode page` flag re-enables the DBFit commit-per-page behavior.
44
+ - **CLI**: `dbression run <path>`, `dbression convert`, `dbression version`. Tag-based
45
+ filtering via `--tag` / `--skip-tag`. Verbose output via `-v`.
46
+ - **Reporters**:
47
+ - Rich console output (pytest-style ✓/✗ tree, full exception bodies, agentic-friendly
48
+ plain-text failures)
49
+ - JUnit XML via `--junit-xml` for Bitbucket Pipelines, Jenkins, GitLab CI, etc.
50
+ - JSON via `--json` for tooling / LLM consumption
51
+ - **Plugin entry-points** under the `dbression.fixtures` group, plus the
52
+ `DBRESSION_PLUGINS` environment variable for ad-hoc / unpackaged extensions.
53
+ - **Connection configuration** via DBFit-compatible `connection.properties`, including
54
+ `${ENV_VAR}` expansion and walk-up resolution of declared paths.
55
+
56
+ ### Known limitations
57
+
58
+ - `Update` fixture is stubbed — implementation deferred until a real-world example calls
59
+ for it.
60
+ - Live Oracle connectivity may require InstantClient (thick mode) against servers that
61
+ reject `python-oracledb` thin-mode authentication. Configuration is via
62
+ `DBRESSION_ORACLE_CLIENT_LIB_DIR`.
63
+
64
+ [Unreleased]: https://github.com/angrydat/dbression/compare/v0.1.0...HEAD
65
+ [0.1.0]: https://github.com/angrydat/dbression/releases/tag/v0.1.0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jürgen Zornig / msgis
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,390 @@
1
+ Metadata-Version: 2.4
2
+ Name: dbression
3
+ Version: 0.1.0
4
+ Summary: Rage-quit your flaky DB regressions — modern, lightweight, multi-DB regression testing.
5
+ Project-URL: Homepage, https://angrydata.info/dbression
6
+ Project-URL: Repository, https://github.com/angrydat/dbression
7
+ Project-URL: Issues, https://github.com/angrydat/dbression/issues
8
+ Project-URL: Changelog, https://github.com/angrydat/dbression/blob/main/CHANGELOG.md
9
+ Author-email: Jürgen Zornig <info@angrydata.info>
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: database,dbfit,fitnesse,markdown,oracle,postgres,regression,sql,sqlserver,testing
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Intended Audience :: Information Technology
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python
20
+ Classifier: Programming Language :: Python :: 3
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: SQL
24
+ Classifier: Topic :: Database
25
+ Classifier: Topic :: Software Development :: Quality Assurance
26
+ Classifier: Topic :: Software Development :: Testing
27
+ Classifier: Typing :: Typed
28
+ Requires-Python: >=3.12
29
+ Requires-Dist: markdown-it-py>=4.2.0
30
+ Requires-Dist: oracledb>=4.0.1
31
+ Requires-Dist: psycopg[binary]>=3.3.4
32
+ Requires-Dist: pymssql>=2.3.13
33
+ Requires-Dist: rich>=13.7
34
+ Requires-Dist: sqlalchemy>=2.0
35
+ Requires-Dist: typer>=0.12
36
+ Description-Content-Type: text/markdown
37
+
38
+ # dbression
39
+
40
+ > ### Rage-quit your flaky DB regressions.
41
+
42
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
43
+ [![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
44
+
45
+ Modern, lightweight database regression testing — read your existing DBFit wikis, run them
46
+ anywhere. `dbression` is a Python re-implementation in the spirit of the fantastic [DBFit](https://dbfit.github.io/dbfit/) Framework:
47
+ **your `.wiki` suites stay, the Java runtime, the bulky FitNesse server, and the Browser based Wiki pages are gone.** Multi-DB, pytest-style CLI, JUnit XML and JSON for CI as well as a developer and agentic friendly STDOUT.
48
+
49
+ ```text
50
+ $ dbression run tests/
51
+ dbression 0.1.0 — Suite: tests @ postgresql+psycopg://wlk:***@db01/wlk
52
+
53
+ ✓ HelloSql 0.004s
54
+ CommonSuite/
55
+ MerklisteSuite/
56
+ ✓ AAddBasicTest 0.027s
57
+ ✓ BAddNormalizationTest 0.029s
58
+ ✓ CAddWhitelistTest 0.025s
59
+ ✓ DAddInvalidArgsTest 0.014s
60
+ ✓ ERemTest 0.052s
61
+ ✓ FViewWbTest 1.236s
62
+ EreignisSuite/
63
+ WaldbrandSuite/
64
+ ✓ LookupTest 0.157s
65
+ ✗ SchemaTest 0.013s
66
+
67
+ ══════════════════════ FAILURES ══════════════════════
68
+ EventsSuite/FloodingSuite/SchemaTest :: Query Row-Mismatch
69
+ SQL: SELECT column_name, data_type FROM information_schema.columns WHERE ...
70
+ Expected: | id | integer | … |
71
+ Actual: | id | integer | … | catastrophic | boolean |
72
+ ^^^^^^^^^^^^
73
+
74
+ ══════════════════════ SUMMARY ══════════════════════
75
+ 8 passed, 1 failed in 1.56s
76
+ ```
77
+
78
+ ## Why dbression?
79
+
80
+ | Pain with DBFit | dbression's answer |
81
+ |---|---|
82
+ | Java runtime + FitNesse server + 80 MB InstantClient | One `pip install`, pure Python, ~30 MB |
83
+ | CLI shows only pass/fail counts; failures only visible in web UI | Full exception, SQL, bind values, row diff in stdout |
84
+ | Stagnant, no recent releases | Active development, modern toolchain (uv, SQLAlchemy 2.0, Typer, Rich) |
85
+ | One driver per DB, Oracle thick-mode only | Postgres (psycopg), SQL Server (pymssql), Oracle (oracledb thin) — no native libs needed |
86
+ | No CI integration | JUnit XML + JSON out of the box |
87
+
88
+ **LLM-friendly by design.** Failures land as text — paste them into Claude/ChatGPT/Copilot and
89
+ the model gets every detail it needs to suggest a fix, no screenshots, no context-switching.
90
+
91
+ ## Quickstart
92
+
93
+ ```bash
94
+ # install (we use uv, but pip works too)
95
+ uv tool install git+https://github.com/angrydat/dbression.git
96
+
97
+ # run
98
+ dbression run tests/
99
+ ```
100
+
101
+ There's also an [`examples/`](examples/) folder with three runnable demo suites
102
+ (hello-SQL, stored-procedure-with-capture, schema-drift via `Inspect Table`) — each
103
+ file is browsable Markdown *and* an executable test.
104
+
105
+ ### Your first test
106
+
107
+ Drop a `.wiki` file in a folder with a `_root.wiki` and a `connection.properties`:
108
+
109
+ ```text
110
+ tests/
111
+ ├── _root.wiki
112
+ ├── connection.properties
113
+ └── HelloSql.wiki
114
+ ```
115
+
116
+ `_root.wiki`:
117
+ ```
118
+ !|DatabaseEnvironment|postgres|
119
+ |ConnectUsingFile|connection.properties|
120
+ ```
121
+
122
+ `connection.properties`:
123
+ ```properties
124
+ service=localhost
125
+ username=postgres
126
+ password=${POSTGRES_PASSWORD} # env-var expansion supported
127
+ database=mydb
128
+ ```
129
+
130
+ `HelloSql.wiki`:
131
+ ```
132
+ !|Query|select 'OK' as connection|
133
+ |connection|
134
+ |OK|
135
+ ```
136
+
137
+ ```bash
138
+ $ dbression run tests/
139
+ ✓ HelloSql 0.004s
140
+ 1 passed in 0.04s
141
+ ```
142
+
143
+ ## What dbression understands
144
+
145
+ The full DBFit fixture subset that real-world suites actually use:
146
+
147
+ | Fixture | What it does |
148
+ |---|---|
149
+ | `Query` | SELECT with expected rows; `>>name` captures values, `<<name` reads them back |
150
+ | `Execute` / `Execute Ddl` | Run arbitrary SQL/PL-SQL/DDL |
151
+ | `Execute Procedure` | Call a stored procedure (dialect-aware: `SELECT/CALL` PG, `EXEC` MSSQL, `BEGIN…END` Oracle) |
152
+ | `Execute Procedure Expect Exception` | Assert a procedure raises a specific SQLSTATE or ORA code |
153
+ | `Insert` / `Delete` | DML with column-header + value-rows, `<<sym` substitution, `>>id` capture via RETURNING |
154
+ | `Set Parameter` | Set a symbol/bind variable from the wiki |
155
+ | `Inspect Table` / `Inspect View` / `Inspect Procedure` | Schema introspection with optional diff against expected |
156
+ | `Store Query` / `Compare Stored Queries` | Snapshot a query result, compare snapshots later |
157
+
158
+ Plus the DBFit-isms you already rely on:
159
+
160
+ - `!- ... -!` escape blocks for multi-line SQL with pipes
161
+ - Oracle `q'~ ... ~'` custom quoting
162
+ - `:name` (bind), `<<name` (cell read), `_:name` (text substitution before compile)
163
+ - Nested sub-suites with `_root.wiki` per directory
164
+ - `SuiteSetUp` / `SuiteTearDown` per suite, with one transaction wrapping everything
165
+ - YAML-style front-matter for tags: `--- Suites: critical NotOnCI ---`
166
+
167
+ ## Executable Markdown: `.test.md`
168
+
169
+ If you'd rather never see FitNesse wiki syntax again, write your tests in plain Markdown —
170
+ the same file is a readable document **and** a runnable test:
171
+
172
+ ````markdown
173
+ # Example test
174
+
175
+ <!-- dbression:env=postgres -->
176
+ <!-- dbression:connection=conn.properties -->
177
+
178
+ ### Query
179
+
180
+ ```sql
181
+ select count(*) as cnt from wlk.app_selectset where oid = 999900001
182
+ ```
183
+
184
+ | cnt |
185
+ |-----|
186
+ | 0 |
187
+
188
+ ### Execute Procedure pr_foo_bar
189
+
190
+ | p_oid | p_order |
191
+ |-----------|-------------------|
192
+ | 999900001 | ASCENDING |
193
+ ````
194
+
195
+ Renders in **GitHub, GitLab, Obsidian, Typora, VS Code** out of the box — tables look
196
+ clean, SQL is syntax-highlighted, directives are invisible (HTML comments).
197
+ Conventions:
198
+
199
+ - `### <FixtureName> [args…]` starts a fixture table (longest-prefix match against the registry)
200
+ - A fenced ` ```sql … ``` ` block directly below becomes the SQL argument for `Query` / `Execute` / `Store Query`
201
+ - The next Markdown table → column headers + data rows, with full DBFit idiom support (`>>capture`, `<<read`, `:bind`)
202
+ - `<!-- dbression:env=… -->`, `<!-- dbression:connection=… -->`, `<!-- dbression:tags critical, NotOnCI -->` carry suite directives
203
+
204
+ Built-in migration tool:
205
+
206
+ ```bash
207
+ dbression convert path/to/wiki-suite/ # mirrors the directory, generates a .test.md next to each .wiki
208
+ dbression convert one-file.wiki -o out.test.md
209
+ ```
210
+
211
+ `.wiki` and `.test.md` may coexist — the Markdown file wins at runtime (newer format).
212
+ That lets you migrate one suite at a time.
213
+
214
+ ## CI Integration
215
+
216
+ `dbression` writes JUnit-XML (the universal CI lingua franca) and JSON (rich, for tooling) side
217
+ by side. Pick one or both.
218
+
219
+ ### Bitbucket Pipelines
220
+
221
+ ```yaml
222
+ pipelines:
223
+ default:
224
+ - step:
225
+ name: dbression
226
+ image: python:3.12
227
+ script:
228
+ - pip install uv
229
+ - uv sync
230
+ - uv run dbression run tests/ \
231
+ --junit-xml test-reports/dbression-junit.xml \
232
+ --json test-reports/dbression.json
233
+ artifacts:
234
+ - test-reports/**
235
+ ```
236
+
237
+ Bitbucket scans `test-reports/*.xml` automatically and renders test results in the pipeline UI.
238
+ No plugin needed.
239
+
240
+ ### Jenkins (declarative)
241
+
242
+ ```groovy
243
+ pipeline {
244
+ agent any
245
+ stages {
246
+ stage('dbression') {
247
+ steps {
248
+ sh 'uv run dbression run tests/ --junit-xml test-reports/dbression-junit.xml --json test-reports/dbression.json'
249
+ }
250
+ }
251
+ }
252
+ post {
253
+ always {
254
+ junit 'test-reports/dbression-junit.xml'
255
+ archiveArtifacts 'test-reports/dbression.json'
256
+ }
257
+ }
258
+ }
259
+ ```
260
+
261
+ ### GitLab CI
262
+
263
+ ```yaml
264
+ dbression:
265
+ script:
266
+ - uv run dbression run tests/ --junit-xml test-reports/dbression-junit.xml
267
+ artifacts:
268
+ reports:
269
+ junit: test-reports/dbression-junit.xml
270
+ ```
271
+
272
+ ## CLI cheat sheet
273
+
274
+ ```bash
275
+ dbression run <suite-path> # run an entire (sub-)suite
276
+ dbression run <path> -v # show every fixture table, not just the page line
277
+ dbression run <path> --tag critical # only run pages tagged `critical`
278
+ dbression run <path> --skip-tag NotOnCI # skip pages tagged `NotOnCI`
279
+ dbression run <path> --commit-mode page # DBFit-style: commit per page (default: rollback per test)
280
+ dbression run <path> --junit-xml report.xml # CI report
281
+ dbression run <path> --json report.json # programmatic / LLM consumption
282
+ dbression convert path/to/wiki/ # converts .wiki → .test.md (in-place)
283
+ dbression convert file.wiki -o out.test.md # single file with explicit output path
284
+ dbression version
285
+ ```
286
+
287
+ ## How it works
288
+
289
+ ```
290
+ ┌─────────────────────────────────────────────────────────┐
291
+ │ CLI (typer) dbression run tests/ [--flags] │
292
+ └─────────────────────────────────────────────────────────┘
293
+
294
+
295
+ ┌─────────────────────┐ ┌───────────────────────────────┐
296
+ │ Parser │ │ Engine Factory (SQLAlchemy) │
297
+ │ Wiki → AST │ │ ┌──────────┐ ┌──────────┐ │
298
+ │ • !- -! escapes │ │ │ psycopg │ │ oracledb │ │
299
+ │ • q'~ ~' quoting │ │ │ (Postgres│ │ (thin) │ │
300
+ │ • Nested suites │ │ └──────────┘ └──────────┘ │
301
+ │ • YAML front matter│ │ ┌──────────────────────┐ │
302
+ └─────────┬───────────┘ │ │ pymssql (SQL Server) │ │
303
+ │ │ └──────────────────────┘ │
304
+ ▼ └───────────┬───────────────────┘
305
+ ┌─────────────────────────────────────┴───────────────────┐
306
+ │ Runner — one TX per suite, savepoints per test │
307
+ │ Symbol engine: >>capture, <<read, :bind, _:text-subst │
308
+ │ Fixture registry — pluggable via decorator │
309
+ └─────────────────────┬───────────────────────────────────┘
310
+
311
+ ┌─────────────────────────────────────────────────────────┐
312
+ │ Reporters │
313
+ │ • Rich console (default) │
314
+ │ • JUnit XML (--junit-xml) │
315
+ │ • JSON (--json) │
316
+ └─────────────────────────────────────────────────────────┘
317
+ ```
318
+
319
+ ## Status
320
+
321
+ `dbression` is **WIP but already useful** — running production-scale DBFit suites today against
322
+ PostgreSQL. Honest state of the parts:
323
+
324
+ | Component | Status |
325
+ |---|------------------------------------------|
326
+ | Wiki parser (DBFit subset) | ✅ verified |
327
+ | Fixtures (Query, Execute, Insert, Delete, Set Parameter, Execute Procedure, Inspect *, Store/Compare Query) | ✅ |
328
+ | PostgreSQL | ✅ verified |
329
+ | SQL Server | 🟡 code-complete via `pymssql`, testing |
330
+ | Oracle | 🟡 code-complete via `oracledb`; testing |
331
+ | JUnit XML + JSON output | ✅ |
332
+ | `Update` fixture | ⏳ stubbed — pull request welcome |
333
+ | `.test.md` native Markdown format + `dbression convert` | ✅ |
334
+ | Plugin entry-points for custom fixtures | ✅ |
335
+
336
+ Don't expect perfect compatibility with every obscure DBFit feature. We promise
337
+ **the subset real teams actually use**, with a sharper UX and a tenth of the footprint.
338
+
339
+ ## Contributing
340
+
341
+ `dbression` is small enough to read end-to-end in an afternoon. The whole thing is roughly:
342
+
343
+ ```
344
+ src/dbression/
345
+ ├── cli.py # typer entrypoint
346
+ ├── parser/ # wiki → AST
347
+ ├── fixtures/ # one file per fixture family
348
+ ├── db/ # connection.properties + SQLAlchemy engine factory
349
+ ├── report/ # console + junit + json
350
+ ├── runner.py # transactions, savepoints, tag filtering
351
+ └── symbols.py # capture / read / substitution
352
+ ```
353
+
354
+ Adding a fixture is one decorator and a `run()` method:
355
+
356
+ ```python
357
+ from dbression.fixtures.base import Fixture, FixtureContext, FixtureResult, register
358
+
359
+ @register("My Custom Fixture")
360
+ class MyFixture(Fixture):
361
+ def run(self, table, ctx: FixtureContext) -> FixtureResult:
362
+ # ... use ctx.conn (SQLAlchemy Connection) and ctx.symbols
363
+ return FixtureResult(passed=True, message="OK")
364
+ ```
365
+
366
+ ### Distributing your own fixtures as a plugin
367
+
368
+ You don't have to fork dbression to add fixtures. Ship them in your own pip-installable
369
+ package via an entry-point:
370
+
371
+ ```toml
372
+ # your-plugin-pkg/pyproject.toml
373
+ [project.entry-points."dbression.fixtures"]
374
+ my-fixtures = "my_plugin.fixtures"
375
+ ```
376
+
377
+ dbression discovers the entry-point at startup and imports the module — your `@register`
378
+ decorators do the rest. For quick ad-hoc plugins without packaging:
379
+
380
+ ```bash
381
+ PYTHONPATH=/path/to/plugin DBRESSION_PLUGINS=my_plugin dbression run tests/
382
+ ```
383
+
384
+ Plugin import failures emit a warning and don't crash the run.
385
+
386
+ PRs welcome — please add a test that exercises the new behavior (we use `pytest`).
387
+
388
+ ## License
389
+
390
+ MIT — see [LICENSE](LICENSE).