Skip to content
Merged
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
39 changes: 39 additions & 0 deletions .cursor/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
FROM ubuntu:24.04

ENV DEBIAN_FRONTEND=noninteractive
ENV ES_VERSION=7.10.1

# System dependencies: Python 3.12 (matches CI/dev), build toolchain for
# mysqlclient/numpy/pandas, MySQL server, and utilities.
RUN apt-get update && apt-get install -y --no-install-recommends \
python3.12 python3.12-venv python3.12-dev python3-pip \
build-essential pkg-config \
default-libmysqlclient-dev libmagic1 libcairo2-dev \
mysql-server \
git curl wget unzip ca-certificates tzdata sudo procps \
&& rm -rf /var/lib/apt/lists/*

# Provide a plain `python` pointing at 3.12
RUN ln -sf /usr/bin/python3.12 /usr/local/bin/python

# Elasticsearch 7.10.1 (matches docker-compose.yml + CI service)
RUN wget -q "https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-${ES_VERSION}-linux-x86_64.tar.gz" -O /tmp/es.tgz \
&& tar xzf /tmp/es.tgz -C /opt \
&& mv "/opt/elasticsearch-${ES_VERSION}" /opt/elasticsearch \
&& rm /tmp/es.tgz \
&& useradd -r -m -d /opt/elasticsearch-home elasticsearch \
&& mkdir -p /var/lib/elasticsearch /var/log/elasticsearch \
&& chown -R elasticsearch:elasticsearch /opt/elasticsearch /var/lib/elasticsearch /var/log/elasticsearch

COPY .cursor/elasticsearch.yml /opt/elasticsearch/config/elasticsearch.yml
RUN sed -i 's/^-Xms.*/-Xms512m/; s/^-Xmx.*/-Xmx512m/' /opt/elasticsearch/config/jvm.options \
&& chown elasticsearch:elasticsearch /opt/elasticsearch/config/elasticsearch.yml

# Ubuntu 24.04 ships a `ubuntu` user (uid 1000); grant passwordless sudo so
# start.sh can manage MySQL and Elasticsearch services.
RUN if ! id ubuntu >/dev/null 2>&1; then useradd -m -s /bin/bash ubuntu; fi \
&& echo 'ubuntu ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/ubuntu \
&& chmod 0440 /etc/sudoers.d/ubuntu

USER ubuntu
WORKDIR /workspace
10 changes: 10 additions & 0 deletions .cursor/elasticsearch.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
cluster.name: ror-local
node.name: ror-node
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch
network.host: 127.0.0.1
http.port: 9200
discovery.type: single-node
xpack.security.enabled: false
http.cors.enabled: true
http.cors.allow-origin: "*"
9 changes: 9 additions & 0 deletions .cursor/env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
ELASTIC7_HOST=localhost
ELASTIC7_PORT=9200
ELASTIC_PASSWORD=changeme
ROR_BASE_URL=http://localhost
DB_HOST=127.0.0.1
DB_PORT=3306
DB_NAME=rorapi
DB_USER=ror_user
DB_PASSWORD=password
17 changes: 17 additions & 0 deletions .cursor/environment.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "ROR API",
"user": "ubuntu",
"build": {
"dockerfile": "Dockerfile",
"context": ".."
},
"install": "bash .cursor/install.sh",
"start": "bash .cursor/start.sh",
"terminals": [
{
"name": "ror-api server",
"command": "cd /workspace && source .venv/bin/activate && python manage.py runserver 0.0.0.0:9292"
}
],
"ports": [9292, 9200, 3306]
}
25 changes: 25 additions & 0 deletions .cursor/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env bash
# Repository bootstrap for the ROR API Cloud Agent environment.
# Idempotent: safe to run repeatedly. Prepares the Python virtualenv,
# installs dependencies and collects static files. Runtime services
# (MySQL, Elasticsearch) are handled by start.sh.
set -euo pipefail

cd "$(dirname "$0")/.."

# Local dev configuration (settings.py loads this via python-dotenv).
if [ ! -f .env ]; then
cp .cursor/env.example .env
fi

# Python virtualenv
if [ ! -x .venv/bin/python ]; then
python3 -m venv .venv
fi
./.venv/bin/pip install --upgrade pip
./.venv/bin/pip install -r requirements.txt

# Static assets can be built without a database connection.
DJANGO_SKIP_DB_CHECK=True ./.venv/bin/python manage.py collectstatic --noinput

echo "install.sh: dependencies installed"
8 changes: 8 additions & 0 deletions .cursor/mysql-init.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-- Idempotent MySQL bootstrap for local ROR API development.
-- Mirrors the credentials used by the CI test workflow.
CREATE DATABASE IF NOT EXISTS rorapi CHARACTER SET utf8mb4;
CREATE USER IF NOT EXISTS 'ror_user'@'localhost' IDENTIFIED BY 'password';
CREATE USER IF NOT EXISTS 'ror_user'@'%' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON *.* TO 'ror_user'@'localhost' WITH GRANT OPTION;
GRANT ALL PRIVILEGES ON *.* TO 'ror_user'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
53 changes: 53 additions & 0 deletions .cursor/start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/usr/bin/env bash
# Per-boot service startup for the ROR API Cloud Agent environment.
# Starts MySQL and Elasticsearch, applies migrations and ensures the
# v2 Elasticsearch index exists. Idempotent and safe to re-run.
set -euo pipefail

cd "$(dirname "$0")/.."

# Ensure local dev config exists even if the checkout dropped it.
if [ ! -f .env ]; then
cp .cursor/env.example .env
fi

echo "start.sh: starting MySQL..."
# Initialize the data directory if the image did not already do so.
# (/var/lib/mysql is mode 700 mysql:mysql, so probe it with sudo. MySQL 8
# stores the system schema in mysql.ibd rather than a mysql/ directory.)
if ! sudo test -f /var/lib/mysql/mysql.ibd; then
sudo mkdir -p /var/lib/mysql
sudo chown -R mysql:mysql /var/lib/mysql
sudo mysqld --initialize-insecure --user=mysql
fi
sudo mkdir -p /var/run/mysqld
sudo chown mysql:mysql /var/run/mysqld
sudo service mysql start || true
for i in $(seq 1 60); do
if sudo mysqladmin ping >/dev/null 2>&1; then break; fi
sleep 1
done
sudo mysql < .cursor/mysql-init.sql
echo "start.sh: MySQL ready"

echo "start.sh: starting Elasticsearch..."
if ! curl -s -m 3 http://127.0.0.1:9200 >/dev/null 2>&1; then
# Detach all standard fds so the daemon does not hold this command's
# stdout/stderr pipe open (otherwise `start` never returns and boot stalls).
sudo -u elasticsearch ES_PATH_CONF=/opt/elasticsearch/config \
/opt/elasticsearch/bin/elasticsearch -d -p /tmp/es.pid \
</dev/null >/tmp/elasticsearch-console.log 2>&1
fi
for i in $(seq 1 90); do
if curl -s -m 3 http://127.0.0.1:9200 >/dev/null 2>&1; then break; fi
sleep 2
done
echo "start.sh: Elasticsearch ready"

# Database migrations (idempotent) and v2 index creation.
./.venv/bin/python manage.py migrate --noinput
if [ "$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:9200/organizations-v2)" != "200" ]; then
./.venv/bin/python manage.py createindex || true
fi

echo "start.sh: ROR API services ready"
17 changes: 17 additions & 0 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,20 @@ jobs:
test-pr:
uses: ./.github/workflows/run_tests.yml
secrets: inherit
ruff:
runs-on: ubuntu-latest
# Soft-fail until Wave 5 (quickwin/ruff-fix) cleans the tree and removes this.
continue-on-error: true
steps:
- name: Checkout ror-api code
uses: actions/checkout@v2
- name: Set up Python environment
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install ruff
run: pip install ruff
- name: Ruff check
run: ruff check .
- name: Ruff format check
run: ruff format --check .
1 change: 1 addition & 0 deletions .github/workflows/run_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ jobs:
test:
runs-on: ubuntu-latest
env:
SECRET_KEY: "django-insecure-github-actions-test-key"
ELASTIC_PASSWORD: "changeme"
ELASTIC7_HOST: "localhost"
ELASTIC7_PORT: "9200"
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@ esdata/**
.venv310/
.uv-python/
.uv-bin/

# Cloud Agent env
.venv/
/static/
Loading
Loading