Commit Graph

5822 Commits

Author SHA1 Message Date
Nick Sweeting
de4579f2af Use temp nginx logs in docs validation 2026-07-25 12:09:47 -07:00
Nick Sweeting
c5aff50a06 Format nginx docs validator 2026-07-25 12:07:45 -07:00
Nick Sweeting
b7d638efb6
Fix nginx docs validation pid path 2026-07-25 12:05:54 -07:00
Nick Sweeting
8fa9120d18 Use Linux mermaid sandbox config in docs CI 2026-07-25 12:01:32 -07:00
Nick Sweeting
fc30c2cafe Fix ArchiveBox reusable test workflow env 2026-07-25 11:58:31 -07:00
Nick Sweeting
d4ff0d033f
Merge remote-tracking branch 'origin/dev' into codex/all-tests-ci 2026-07-25 11:51:21 -07:00
Nick Sweeting
7658df9208 Fix ArchiveBox CI runtime paths and docs validation 2026-07-25 11:51:15 -07:00
Nick Sweeting
7c44393a0c
Add PostgreSQL backend support alongside SQLite (#1839)
Some checks failed
CI / Linters (push) Has been cancelled
CI / Install and CLI platform compatibility (push) Has been cancelled
CI / Discovered test matrix (push) Has been cancelled
CI / Documentation and root tests (push) Has been cancelled
CI / CodeQL (push) Has been cancelled
CI / Tested Python artifacts (push) Has been cancelled
CI / Tested Docker images (push) Has been cancelled
CI / All required CI lanes (push) Has been cancelled
CodeQL / Analyze (${{ matrix.language }}) (none, javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (${{ matrix.language }}) (none, python) (push) Has been cancelled
## Summary

This PR adds full PostgreSQL database backend support to ArchiveBox,
allowing users to choose between SQLite (default) and PostgreSQL via the
new `DATABASE_ENGINE` configuration option. All
database-backend-specific logic is centralized in a new
`archivebox/misc/db.py` module with helper functions for connection
management, schema initialization, and backend detection.

## Related issues

Enables PostgreSQL as an alternative to SQLite for deployments requiring
better concurrency, larger datasets, or managed database services.

## Changes these areas

- [x] Feature behavior
- [x] Configuration options
- [x] Internal architecture

## Key Changes

### New Database Backend Abstraction (`archivebox/misc/db.py`)
- Centralized all SQLite vs PostgreSQL branching logic in a single
module
- Added helper functions:
  - `database_backend()` / `is_postgres()` - detect configured backend
- `get_database_settings()` - generate Django DATABASES config per
backend
  - `postgres_db_params()` - extract PostgreSQL connection parameters
- `database_exists()` - check if database is initialized (works before
Django setup)
- `ensure_database_ready()` - verify PostgreSQL server is reachable and
create database if needed
  - `approximate_row_counts()` - get optimizer stats from either backend
- `truncate_tables()` / `rebuild_models_from_migration_state()` - schema
management helpers

### Configuration
- Added `DATABASE_ENGINE` config option (default: "sqlite") in
`archivebox/config/common.py`
- Added PostgreSQL-specific config options: `DATABASE_NAME`,
`DATABASE_USER`, `DATABASE_PASSWORD`, `DATABASE_HOST`, `DATABASE_PORT`
- Updated documentation in `docs/Configuration.md`

### Django Settings Integration
- Modified `archivebox/core/settings.py` to use
`get_database_settings()` for dynamic backend selection
- Removed hardcoded SQLite-only connection options

### Migration Strategy
- Refactored existing migrations to support both backends:
- SQLite migrations execute raw DDL via `RunSQL` (byte-for-byte
identical to original)
- PostgreSQL migrations use `rebuild_models_from_migration_state()` to
sync schema from Django models
- Added backend-specific migration functions (`_run_sqlite_only_sql`,
`_pg_sync_schema`)
- Affected migrations: `crawls/0001_initial.py`, `api/0001_initial.py`,
`machine/0001_initial.py`, `core/0024_assign_default_crawl.py`, and
others

### Query Compatibility
- Updated `archivebox/search/query.py` to handle both SQLite's
`json_tree()` and PostgreSQL's `jsonb` operators
- Updated `archivebox/search/views.py` URL prefix search to use
backend-specific range queries
- Added PostgreSQL pattern-ops index migration
(`core/0051_postgres_url_pattern_ops_index.py`) for efficient LIKE
queries

### Testing
- Added comprehensive PostgreSQL backend test suite
(`archivebox/tests/test_postgres_backend.py`)
  - Spins up real throwaway PostgreSQL cluster for end-to-end testing
  - Tests init, status, add, list, remove operations
  - Validates schema parity between models and database
  - Requires PostgreSQL server binaries (initdb/pg_ctl)
- Added database benchmarking tool (`bin/benchmark_db_backends.py`) for
performance comparison

### Admin UI
- Updated `archivebox/core/admin_site.py` to use centralized
`approximate_row_counts()` helper (works on both backends)

### CLI Integration
- Updated `archivebox_init.py` to call `ensure_database_ready()` before
migrations (PostgreSQL-specific setup)
- Updated `archivebox_status.py` to use `database_display_location()`
for user-friendly output

## Test Plan

- CI runs new PostgreSQL backend tests on supported platforms (macOS,
Python 3.14)
- Existing SQLite tests continue to pass (no behavioral changes to
default backend)
- Schema parity test validates all Django models match database schema
on PostgreSQL
- Benchmark tool available for performance

https://claude.ai/code/session_019YHSjZM6TstSAMN2PhgfUg

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds first‑class PostgreSQL support alongside SQLite with backend‑aware
migrations and queries. SQLite stays the default; nothing changes unless
you set `DATABASE_ENGINE=postgres`.

- **New Features**
- Choose Postgres with `DATABASE_ENGINE` and
`DATABASE_HOST/PORT/USER/PASSWORD/NAME` (SQLite remains default).
- Centralized helpers: `is_postgres()`, `postgres_db_params()`,
`database_exists()`, `ensure_database_ready()` (auto‑create DB),
`approximate_row_counts()`, and schema rebuild/drop on non‑SQLite.
- Migrations keep raw SQLite DDL byte‑for‑byte; on Postgres, SQLite‑only
steps are skipped and tables are rebuilt from migration state (reverse
drops tables on Postgres). Adds a Postgres `text_pattern_ops` index for
URL queries.
- Query parity: crawl‑config search matches scalar JSON values on
Postgres via `jsonb_path_query`; URL prefix and fragmentless URL checks
use escaped `LIKE` on Postgres (uses the pattern‑ops index) and bytewise
range scans on SQLite.
- Consistent field limits: clamp overlong `CharField` values on save and
in `bulk_create` so writes behave the same on both backends.
- CLI/Admin: `init` verifies Postgres connectivity and creates the DB if
missing; status shows DB DSN or file; admin counts come from backend
optimizer stats.
- Tests run against a real Postgres cluster; CI only installs Postgres
binaries on the shard running `test_postgres_backend.py`. Added
benchmarking tool for hot‑path queries. New dependency:
`psycopg[binary]`.

- **Migration**
  - SQLite users: no action needed; behavior unchanged.
- To use Postgres: set `DATABASE_ENGINE=postgres` and `DATABASE_*` vars,
then run `archivebox init` (creates the DB and applies migrations).
Choose your backend on first init; there’s no built‑in tool to move an
existing index between SQLite and Postgres.

<sup>Written for commit 2df28d9a72.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/ArchiveBox/ArchiveBox/pull/1839?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
2026-07-24 03:50:23 -07:00
Claude
2df28d9a72
Gate postgres install to the sharded test_postgres_backend job
Re-apply the postgres-server install step in dev's new per-file sharded
test-parallel structure, conditioned on the shard whose matrix.test.path is
the postgres backend test so other shards skip the apt install.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YHSjZM6TstSAMN2PhgfUg
2026-07-24 10:33:43 +00:00
Claude
e6102b52ac
Register new DATABASE_CONFIG docs example in codeblocks inventory
The postgres ArchiveBox.conf example added to Configuration.md is an
illustration snippet; add it to docs/codeblocks.toml so the docs manifest
inventory check passes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YHSjZM6TstSAMN2PhgfUg
2026-07-24 10:32:59 +00:00
Claude
f7c182d76c
Merge remote-tracking branch 'origin/dev' into claude/archivebox-postgresql-support-xrlgim
# Conflicts:
#	.github/workflows/test-parallel.yml
#	.github/workflows/test.yml
#	uv.lock
2026-07-24 10:30:55 +00:00
Claude
ee6867e812
Use is_postgres() in snapshot URL query (centralize backend check)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YHSjZM6TstSAMN2PhgfUg
2026-07-24 10:28:04 +00:00
Claude
6a8062090b
Slim DB helpers and address PR review feedback
Helper reduction:
- Move the Django DATABASES/SQLITE_CONNECTION_OPTIONS assembly into
  core/settings.py, dropping get_database_settings() and
  get_sqlite_connection_options() from misc/db.py.
- Inline the single-use migration_table_columns() into its one migration.

Review fixes:
- search: match only scalar JSON *values* on postgres (jsonb_path_query
  over '$.**' scalar leaves), mirroring SQLite json_tree.atom so config
  keys no longer match.
- CharField clamp now also runs in SnapshotQuerySet.bulk_create (bulk paths
  bypass the pre_save signal); truncate_overlong_charfields is dual-use.
- Restore reverse-migration parity on postgres: crawls/machine/api initial
  migrations drop their rebuilt tables on reverse via drop_models_on_postgres.
- docs: give DATABASE_NAME its own section so the anchor resolves correctly.
- CI: only install postgres binaries on the shard that runs the postgres test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YHSjZM6TstSAMN2PhgfUg
2026-07-24 07:57:09 +00:00
Nick Sweeting
eacfae5d6c
Run all ArchiveBox tests through unified CI 2026-07-24 00:50:40 -07:00
Claude
35145d282c
Regenerate lockfile with pinned uv and slim DB adapter helpers
Re-lock uv.lock with the CI-pinned uv version so the diff is limited to the
psycopg addition (a newer local uv had rewritten platform markers and
exclude-newer, breaking `uv sync --locked` in CI).

Consolidate the misc/db.py adapter surface: fold database_backend() into
is_postgres(), drop the redundant vendor-name constants, remove the unused
migration_table_exists() helper, and inline the single-use missing-table check.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YHSjZM6TstSAMN2PhgfUg
2026-07-24 07:23:44 +00:00
Claude
c2191f9e74
Fix lint: settings import placement and benchmark script exec bit
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YHSjZM6TstSAMN2PhgfUg
2026-07-23 17:18:54 +00:00
Claude
7167c5dd8a
Add native PostgreSQL support alongside SQLite
Add DATABASE_ENGINE=postgres (plus DATABASE_HOST/PORT/USER/PASSWORD/NAME)
config and centralize all sqlite-vs-postgres branching in
archivebox.misc.db:

- get_database_settings() builds DATABASES for either backend; the sqlite
  path is unchanged (custom lock-retry backend, same PRAGMAs).
- database_exists()/ensure_database_ready() replace index.sqlite3 file
  checks; init auto-creates the postgres database when missing.
- approximate_row_counts() serves admin index counts from sqlite_stat1 or
  pg_class.reltuples; missing-table detection covers both vendors.
- rebuild_models_from_migration_state() lets historical sqlite-only raw
  SQL migrations resync postgres schema from Django migration state at
  every divergence point (postgres can never hold legacy data, so
  affected tables are empty when these run). All raw-DDL and PRAGMA
  migrations are now vendor-gated with sqlite behavior byte-for-byte
  unchanged.
- A pre_save clamp truncates CharField values to max_length: sqlite
  never enforced varchar(n) but postgres does (e.g. long crawl labels).
- Collation-sensitive URL range scans branch to escaped LIKE on postgres
  (with a text_pattern_ops index) since linguistic collations break
  bytewise range tricks; the crawl-config JSON search wave gets a
  jsonb-text implementation.

Verified on real PostgreSQL 16: fresh init applies the entire migration
graph, schema matches models exactly (column-level parity check +
makemigrations --check), and add/run/list/search/status/remove all work
end-to-end. New test_postgres_backend.py suite boots a real throwaway
postgres cluster (initdb + pg_ctl); CI workflows install postgres server
binaries.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YHSjZM6TstSAMN2PhgfUg
2026-07-23 17:08:47 +00:00
Nick Sweeting
a3c5e13ff8 Release ArchiveBox through complete CI coverage
Some checks failed
CI / Linters (push) Waiting to run
CI / Complete test suite (push) Waiting to run
CI / Sharded and plugin tests (push) Waiting to run
CI / Documentation and root tests (push) Waiting to run
CI / CodeQL (push) Waiting to run
CI / Tested Python artifacts (push) Waiting to run
CI / Tested Docker images (push) Waiting to run
CI / All required CI lanes (push) Blocked by required conditions
Deploy Publicsite to GitHub Pages / deploy (push) Has been cancelled
2026-07-23 07:00:05 -07:00
Nick Sweeting
bcab0bfa6e
Run the complete core and MCP documentation suites 2026-07-21 19:26:42 -07:00
Nick Sweeting
c36d3c1575
Make release publication atomic and CI-only 2026-07-21 19:26:42 -07:00
Nick Sweeting
6592af0d19
Exercise ArchiveBox through unified runtime lifecycles 2026-07-21 19:26:42 -07:00
github-actions[bot]
e89388b264 release: v0.9.35rc137
Some checks failed
CodeQL / Analyze (${{ matrix.language }}) (none, python) (push) Has been cancelled
Build Docker image / build ${{ matrix.platform }} (digest-linux-amd64, docker-amd64, linux/amd64, ubuntu-24.04) (push) Has been cancelled
Build Docker image / build ${{ matrix.platform }} (digest-linux-arm64, docker-arm64, linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Run linters / lint (push) Has been cancelled
Build Pip package / build (push) Has been cancelled
Release State / release-state (push) Has been cancelled
Parallel Tests / Discover test files (push) Has been cancelled
Run tests / python_tests (ubuntu-24.04, 3.13) (push) Has been cancelled
Run tests / docker_tests (push) Has been cancelled
Build Docker image / publish multiarch tags (push) Has been cancelled
Parallel Tests / ${{ matrix.test.name }} (push) Has been cancelled
Parallel Tests / ${{ matrix.plugin.name }} (push) Has been cancelled
2026-07-20 23:42:31 +00:00
Nick Sweeting
ee91a9e366
Filter version binaries before resolution 2026-07-20 16:42:04 -07:00
github-actions[bot]
d9b648e6a9 release: v0.9.35rc136 2026-07-20 23:23:21 +00:00
Nick Sweeting
81ea053f97
Avoid empty binary resolution buses 2026-07-20 16:22:53 -07:00
github-actions[bot]
1a9796bcaa release: v0.9.35rc135 2026-07-20 22:56:39 +00:00
Nick Sweeting
5a30ab0451
Scope install status to requested binaries 2026-07-20 15:54:33 -07:00
github-actions[bot]
765aef56e9 release: v0.9.35rc134 2026-07-20 22:25:37 +00:00
Nick Sweeting
ee342a0313
Use supported uv group install in lint CI 2026-07-20 15:23:20 -07:00
github-actions[bot]
39e1a77de7 release: v0.9.35rc133 2026-07-20 22:22:55 +00:00
Nick Sweeting
70fb360bae
Preserve feature branch test coverage 2026-07-20 15:21:27 -07:00
github-actions[bot]
95f8f0fbd8 release: v0.9.35rc132 2026-07-20 22:21:07 +00:00
Nick Sweeting
582499be86
Deduplicate ArchiveBox release CI 2026-07-20 15:19:32 -07:00
github-actions[bot]
84624844aa release: v0.9.35rc131 2026-07-20 22:14:36 +00:00
Nick Sweeting
ba405c5f1f
Keep PyPI publishing in release state 2026-07-20 15:06:51 -07:00
github-actions[bot]
1481dedf31 release: v0.9.35rc130 2026-07-20 22:01:31 +00:00
Nick Sweeting
56b0abfb78
Use fixed binary projection releases 2026-07-20 15:00:10 -07:00
github-actions[bot]
6ddf9fcd84 release: v0.9.35rc129 2026-07-20 21:26:39 +00:00
Nick Sweeting
1ca93ee0f6
Use corrected unified runtime releases 2026-07-20 14:23:03 -07:00
github-actions[bot]
2d5760642a release: v0.9.35rc128 2026-07-20 20:09:34 +00:00
Nick Sweeting
ecf35c33d6
Pin unified runtime dependency releases 2026-07-20 13:08:38 -07:00
github-actions[bot]
713eb61829 release: v0.9.35rc127
Some checks failed
CodeQL / Analyze (${{ matrix.language }}) (none, python) (push) Waiting to run
Build Docker image / build ${{ matrix.platform }} (digest-linux-amd64, docker-amd64, linux/amd64, ubuntu-24.04) (push) Waiting to run
Build Docker image / build ${{ matrix.platform }} (digest-linux-arm64, docker-arm64, linux/arm64, ubuntu-24.04-arm) (push) Waiting to run
Build Docker image / publish multiarch tags (push) Blocked by required conditions
Run linters / lint (push) Waiting to run
Build Pip package / build (push) Waiting to run
Release State / release-state (push) Waiting to run
Parallel Tests / Discover test files (push) Waiting to run
Parallel Tests / ${{ matrix.test.name }} (push) Blocked by required conditions
Parallel Tests / ${{ matrix.plugin.name }} (push) Blocked by required conditions
Run tests / python_tests (ubuntu-24.04, 3.13) (push) Waiting to run
Run tests / docker_tests (push) Waiting to run
Update downstream packages / dispatch (push) Has been cancelled
2026-07-20 19:53:24 +00:00
Nick Sweeting
d92b2649bd
Use configured PyPI token for package publishing 2026-07-20 12:52:58 -07:00
github-actions[bot]
fcc9457825 release: v0.9.35rc126 2026-07-20 19:50:42 +00:00
Nick Sweeting
01f5666dbc
Route runtime binaries through abxpkg 2026-07-20 12:50:14 -07:00
github-actions[bot]
e17248b5f1 release: v0.9.35rc125 2026-07-20 15:32:29 +00:00
Nick Sweeting
d0c39fdf2c
Pin corrected hook lifecycle releases 2026-07-20 08:32:01 -07:00
github-actions[bot]
637d2ec210 release: v0.9.35rc124 2026-07-20 15:09:27 +00:00
Nick Sweeting
ed7e3f0ec8 Pin restored hook lifecycle releases 2026-07-20 08:08:47 -07:00
github-actions[bot]
f1a574192a release: v0.9.35rc124 2026-07-20 15:05:54 +00:00