Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
FROM python:3.9-slim-bookworm

# Avoid prompts from apt
ENV DEBIAN_FRONTEND=noninteractive

# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
git \
curl \
wget \
make \
gcc \
g++ \
libpq-dev \
libgeos-dev \
libproj-dev \
postgresql-client \
&& rm -rf /var/lib/apt/lists/*

# Set working directory
WORKDIR /workspace

# Upgrade pip
RUN pip install --upgrade pip setuptools wheel
75 changes: 75 additions & 0 deletions .devcontainer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Dev Container for c2corg v6_api

This directory contains a [Dev Container](https://containers.dev/) configuration
that provides a fully configured development environment with all services
(PostgreSQL/PostGIS, Elasticsearch, Redis) running as companion containers.

## Prerequisites

- [Docker Desktop](https://www.docker.com/products/docker-desktop/) (or a compatible Docker engine)
- [VS Code](https://code.visualstudio.com/) with the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)

## Getting started

1. Open this repository in VS Code
2. When prompted, click **"Reopen in Container"** — or use the command palette:
`Dev Containers: Reopen in Container`
3. Wait for the container to build and the `postCreateCommand` setup script to
finish (first run takes a few minutes)
4. You're ready to go!

## What's included

| Service | Hostname | Port |
|----------------|-----------------|------|
| PostgreSQL | `postgresql` | 5432 |
| Elasticsearch | `elasticsearch` | 9200 |
| Redis | `redis` | 6379 |
| API (when run) | `localhost` | 6543 |

All ports are forwarded to your host machine for convenience.

## Common commands

```bash
# Run the test suite
pytest

# Run a specific test file
pytest c2corg_api/tests/models/test_book.py

# Run the linter
flake8 c2corg_api es_migration

# Start the API server (with auto-reload)
pserve development.ini --reload

# Or use make targets
make test
make serve
make lint
```

## Rebuilding

If dependencies change, rebuild the container:

- Command palette → `Dev Containers: Rebuild Container`

## Troubleshooting

- **Database errors**: The setup script creates both databases automatically. If you need to re-run:

```bash
PGPASSWORD=test PGUSER=postgres PGHOST=postgresql \
bash .devcontainer/setup.sh
```

- **Elasticsearch not ready**: The setup script waits for ES, but if tests
fail with connection errors, check: `curl http://elasticsearch:9200`

- **Config out of date**: Re-generate config files:

```bash
bash .devcontainer/setup.sh
```
39 changes: 39 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "c2corg v6_api",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace",

// VS Code settings
"customizations": {
"vscode": {
"settings": {
"python.defaultInterpreterPath": "/usr/local/bin/python",
"python.testing.pytestEnabled": true,
"python.testing.pytestArgs": ["c2corg_api/tests"],
"python.linting.flake8Enabled": true,
"editor.formatOnSave": true
},
"extensions": [
"ms-python.python",
"ms-python.vscode-pylance",
"ms-python.flake8"
]
}
},

// Forward ports for local access
"forwardPorts": [6543, 9200, 6379, 5432],
"portsAttributes": {
"6543": { "label": "API Server" },
"9200": { "label": "Elasticsearch" },
"6379": { "label": "Redis" },
"5432": { "label": "PostgreSQL" }
},

// Run after the container is created (one-time setup)
"postCreateCommand": "bash .devcontainer/setup.sh",

// Run every time the container starts
"postStartCommand": "echo 'Dev container ready. Run: make test'"
}
55 changes: 55 additions & 0 deletions .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
services:
app:
build:
context: .
dockerfile: Dockerfile
volumes:
- ..:/workspace:cached
command: sleep infinity
depends_on:
postgresql:
condition: service_healthy
elasticsearch:
condition: service_started
redis:
condition: service_healthy
environment:
# Point services to their container hostnames
PGHOST: postgresql
PGUSER: postgres
PGPASSWORD: test

postgresql:
image: postgis/postgis:16-3.4
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: test
volumes:
- postgres_data:/var/lib/postgresql/data
- ..:/v6_api
- ../docker/conf/postgresql.conf:/etc/postgresql.conf
command: ["postgres", "-c", "config_file=/etc/postgresql.conf"]
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres"]
interval: 10s
timeout: 5s
retries: 5

elasticsearch:
image: "docker.io/c2corg/c2corg_es:anon-2018-11-02"
command: -Des.index.number_of_replicas=0 -Des.path.data=/c2corg_anon -Des.script.inline=true
ulimits:
nofile:
soft: 65536
hard: 65536

redis:
image: redis:7.2
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5

volumes:
postgres_data:
94 changes: 94 additions & 0 deletions .devcontainer/setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#!/bin/bash
set -e

echo "==> Installing Python dependencies..."
pip install -e ".[dev]"

echo "==> Copying env.local.sample to env.local (if not present)..."
if [ ! -f config/env.local ]; then
cp config/env.local.sample config/env.local
fi

# Override hosts to point to docker-compose service names
# (inside the devcontainer network, services are reachable by name)
cat > config/env.devcontainer <<'EOF'
#!/bin/sh
version=0.0.0dev0
db_host=postgresql
tests_db_host=postgresql
elasticsearch_host=elasticsearch
redis_url=redis://redis:6379/
EOF

echo "==> Generating config files from templates..."
./scripts/env_replace config/env.default config/env.dev config/env.devcontainer < alembic.ini.in > alembic.ini
./scripts/env_replace config/env.default config/env.dev config/env.devcontainer < common.ini.in > common.ini
./scripts/env_replace config/env.default config/env.dev config/env.devcontainer < development.ini.in > development.ini
./scripts/env_replace config/env.default config/env.dev config/env.devcontainer < test.ini.in > test.ini

echo "==> Waiting for PostgreSQL to be ready..."
until pg_isready -h postgresql -U postgres; do
echo " PostgreSQL not ready yet, retrying in 2s..."
sleep 2
done

echo "==> Initializing dev database..."
export PGPASSWORD=test
export PGUSER=postgres
export PGHOST=postgresql
export POSTGRES_USER=postgres

# Create dev database (adapted from scripts/database/create_schema.sh)
DBNAME="c2corg"
if psql -tAc "SELECT 1 FROM pg_database WHERE datname='${DBNAME}'" | grep -q 1; then
echo " Dev database already exists: ${DBNAME}"
else
echo " Creating dev database: ${DBNAME}"
psql -v ON_ERROR_STOP=1 --username "$PGUSER" <<SQL
CREATE DATABASE ${DBNAME} OWNER "postgres";
\c ${DBNAME}
CREATE EXTENSION IF NOT EXISTS postgis;
CREATE SCHEMA IF NOT EXISTS guidebook AUTHORIZATION "postgres";
CREATE SCHEMA IF NOT EXISTS users AUTHORIZATION "postgres";
CREATE SCHEMA IF NOT EXISTS sympa AUTHORIZATION "postgres";
CREATE SCHEMA IF NOT EXISTS alembic AUTHORIZATION "postgres";
SQL
fi
initialize_c2corg_api_db development.ini || true

# Create test database (adapted from scripts/database/create_test_schema.sh)
echo "==> Initializing test database..."
DBNAME="c2corg_tests"
if psql -tAc "SELECT 1 FROM pg_database WHERE datname='${DBNAME}'" | grep -q 1; then
echo " Test database already exists: ${DBNAME}"
else
echo " Creating test database: ${DBNAME}"
psql -v ON_ERROR_STOP=1 --username "$PGUSER" <<SQL
CREATE DATABASE ${DBNAME} OWNER "postgres";
\c ${DBNAME}
CREATE EXTENSION IF NOT EXISTS postgis;
CREATE SCHEMA IF NOT EXISTS guidebook AUTHORIZATION "postgres";
CREATE SCHEMA IF NOT EXISTS users AUTHORIZATION "postgres";
CREATE SCHEMA IF NOT EXISTS sympa AUTHORIZATION "postgres";
CREATE SCHEMA IF NOT EXISTS alembic AUTHORIZATION "postgres";
SQL
fi

echo "==> Waiting for Elasticsearch to be ready..."
until curl -s http://elasticsearch:9200 > /dev/null 2>&1; do
echo " Elasticsearch not ready yet, retrying in 5s..."
sleep 5
done

echo "==> Initializing Elasticsearch indexes..."
fill_es_index development.ini || true

echo ""
echo "============================================="
echo " Dev container setup complete!"
echo ""
echo " Run the API: pserve development.ini --reload"
echo " Run tests: pytest"
echo " Run linter: flake8 c2corg_api es_migration"
echo " Or use make: make test / make serve / make lint"
echo "============================================="
Loading
Loading