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
21 changes: 13 additions & 8 deletions .github/workflows/migration-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,28 +44,33 @@ jobs:
with:
fetch-depth: 2

- name: Set up Python
uses: actions/setup-python@v6
- name: Set up uv
uses: astral-sh/setup-uv@v7
with:
python-version: "3.12.x"
cache: "pip"
cache-dependency-path: "apps/api/requirements/*.txt"
# uv version comes from [tool.uv] required-version.
version-file: "apps/api/pyproject.toml"
# Same patch release as the production image (python:3.12.12-alpine);
# uv fetches a managed build instead of the runner's older system 3.12.
python-version: "3.12.12"
enable-cache: true
cache-dependency-glob: "apps/api/uv.lock"

# Same dependency set as the production image (Dockerfile.api).
- name: Install API dependencies
working-directory: apps/api
run: pip install -r requirements.txt
run: uv sync --locked --no-default-groups --group production

- name: Django system checks
working-directory: apps/api
run: python manage.py check
run: uv run --no-sync python manage.py check

# Fails on two leaf nodes in one app (the PR and the base branch both
# numbered a migration off the same parent), on a dependency pointing at
# a migration that does not exist, and on models whose changes were never
# written to a migration at all.
- name: Migration graph and model/migration drift
working-directory: apps/api
run: python manage.py makemigrations --check --dry-run
run: uv run --no-sync python manage.py makemigrations --check --dry-run

# HEAD^1 is the base branch tip, HEAD^2 the PR head, so this is exactly
# what the PR does to files that already exist on the base branch.
Expand Down
24 changes: 15 additions & 9 deletions .github/workflows/pull-request-build-lint-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,21 @@ jobs:
github.event.pull_request.requested_reviewers != null
steps:
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
- name: Set up uv
uses: astral-sh/setup-uv@v7
with:
python-version: "3.12.x"
cache: 'pip'
cache-dependency-path: 'apps/api/requirements.txt'
- name: Install Pylint
run: python -m pip install ruff
# uv version comes from [tool.uv] required-version.
version-file: "apps/api/pyproject.toml"
# Same patch release as the production image (python:3.12.12-alpine).
python-version: "3.12.12"
enable-cache: true
cache-dependency-glob: "apps/api/uv.lock"
# Only the dev group (ruff) is needed to lint. --locked still fails the
# job if uv.lock is out of date with pyproject.toml.
- name: Install API Dependencies
run: cd apps/api && pip install -r requirements.txt
working-directory: apps/api
run: uv sync --locked --only-group dev
# No --fix: fixable violations must fail the job, not be rewritten on the runner.
- name: Lint apps/api
run: ruff check --fix apps/api
working-directory: apps/api
run: uv run --no-sync ruff check .
12 changes: 11 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,24 @@
- **Testing**: All features require unit tests, use existing test framework per package
- **Components**: Primitives come from the published `@makeplane/propel` npm package (`@makeplane/propel/components/*`, `elements/*`, `icons`); composite/Plane-specific components live in `@plane/blocks` (`packages/blocks`, subpath imports only, e.g. `@plane/blocks/toast`)

## Backend dependencies (uv)

`apps/api` dependencies are managed with [uv](https://docs.astral.sh/uv/): declared in `apps/api/pyproject.toml`, pinned in `apps/api/uv.lock` (commit both). Groups: `dev` and `test` (installed by default; they use `psycopg-binary`), `production` (gunicorn + the source-built `psycopg-c`; production image and migration-check only). Lint config lives in `apps/api/ruff.toml`.

- uv must be exactly the `required-version` in `apps/api/pyproject.toml` (`uv self update <version>`); bump it together with the uv image in both Dockerfiles
- Set up a local env: `cd apps/api && uv sync`
- Inside the dev/test containers, always pass `--inexact` (`uv sync --inexact`): uv targets the image's system Python there, and an exact sync would uninstall pip
- Add/upgrade a dependency: `uv add <pkg>==<version>` (or `--group test`/`--group dev`), or edit `pyproject.toml` and run `uv lock`
- Run tools: `uv run python manage.py ...`, `uv run ruff check .`

## Backend tests (Docker)

The Django/pytest suite for `apps/api` runs in an isolated stack defined by `docker-compose-test.yml` at the repo root.

Prereq (once): `./setup.sh` — generates `apps/api/.env` from `.env.example`.

- Full suite: `docker compose -f docker-compose-test.yml up --build --abort-on-container-exit --exit-code-from api-tests`
- Subset: `docker compose -f docker-compose-test.yml run --rm api-tests pytest -m unit`
- Subset: `docker compose -f docker-compose-test.yml run --rm --build api-tests pytest -m unit`
- Teardown: `docker compose -f docker-compose-test.yml down -v`

See `apps/api/tests/RUNNING_TESTS.md` for the full walkthrough and troubleshooting; see `apps/api/tests/TESTING_GUIDE.md` for test conventions and fixtures.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ This helps us triage and manage issues more efficiently.

- Docker Engine installed and running
- Node.js version 20+ [LTS version](https://nodejs.org/en/about/previous-releases)
- Python version 3.8+
- Python version 3.12 and [uv](https://docs.astral.sh/uv/) (only needed to run the API outside Docker)
- Postgres version v14
- Redis version v6.2.7
- **Memory**: Minimum **12 GB RAM** recommended
Expand Down
10 changes: 10 additions & 0 deletions apps/api/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Every API image builds with ./apps/api as its context, so the repo-root
# .dockerignore never applies here.
# Local virtualenvs hold host-platform binaries.
.venv
Comment thread
sriramveeraghanta marked this conversation as resolved.
venv
# Secrets generated by setup.sh; compose passes them in via env_file.
.env
# Host bytecode (patterns are anchored to the context root, hence **/).
**/__pycache__
**/*.pyc
1 change: 1 addition & 0 deletions apps/api/.python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.12
19 changes: 15 additions & 4 deletions apps/api/Dockerfile.api
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
# Keep in step with required-version in pyproject.toml; bump tag and digest together.
FROM ghcr.io/astral-sh/uv:0.12.21@sha256:a7aed3216253ee804de3e2d8afa5073baa1a177335345d43845cd4165e43b711 AS uv

FROM python:3.12.12-alpine

# set environment variables
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV PIP_DISABLE_PIP_VERSION_CHECK=1
ENV INSTANCE_CHANGELOG_URL=https://sites.plane.so/pages/691ef037bcfe416a902e48cb55f59891/
# uv installs the locked dependencies straight into the image's Python
# (/usr/local), so python, gunicorn and celery resolve exactly as with pip.
ENV UV_PROJECT_ENVIRONMENT=/usr/local
ENV UV_PYTHON_DOWNLOADS=never
ENV UV_COMPILE_BYTECODE=1
ENV UV_NO_CACHE=1

# OS security updates. --available forces reinstall from the current repos;
# bump APK_SECURITY_PATCH to bust buildx's cached layer (keyed on this command
Expand All @@ -21,10 +30,12 @@ RUN apk add --no-cache --upgrade \
"ca-certificates" \
"openssl"

COPY requirements.txt ./
COPY requirements ./requirements
COPY pyproject.toml uv.lock ./
Comment thread
sriramveeraghanta marked this conversation as resolved.
RUN apk add --no-cache libffi-dev
RUN apk add --no-cache --virtual .build-deps \
# uv is bind-mounted for this step only, so the binary never ships in the image.
# --inexact keeps the base image's own packages (pip) in place.
RUN --mount=from=uv,source=/uv,target=/bin/uv \
apk add --no-cache --virtual .build-deps \
"bash~=5.3" \
"g++" \
"gcc" \
Expand All @@ -35,7 +46,7 @@ RUN apk add --no-cache --virtual .build-deps \
"libc-dev" \
"linux-headers" \
&& \
pip install -r requirements.txt --compile --no-cache-dir \
uv sync --locked --inexact --no-default-groups --group production \
&& \
apk del .build-deps \
&& \
Expand Down
17 changes: 13 additions & 4 deletions apps/api/Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
# Keep in step with required-version in pyproject.toml; bump tag and digest together.
FROM ghcr.io/astral-sh/uv:0.12.21@sha256:a7aed3216253ee804de3e2d8afa5073baa1a177335345d43845cd4165e43b711 AS uv

FROM python:3.12.5-alpine AS backend

# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
ENV PIP_DISABLE_PIP_VERSION_CHECK=1
ENV INSTANCE_CHANGELOG_URL https://sites.plane.so/pages/691ef037bcfe416a902e48cb55f59891/
# Install into the image's Python (/usr/local), not /code/.venv: the compose
# files bind-mount the source over /code, which would hide an in-tree venv.
ENV UV_PROJECT_ENVIRONMENT=/usr/local
ENV UV_PYTHON_DOWNLOADS=never
ENV UV_COMPILE_BYTECODE=1
ENV UV_NO_CACHE=1

RUN apk --no-cache add \
"bash~=5.2" \
Expand All @@ -25,11 +34,11 @@ RUN apk --no-cache add \

WORKDIR /code

COPY requirements.txt ./requirements.txt
ADD requirements ./requirements
COPY --from=uv /uv /usr/local/bin/uv
Comment thread
sriramveeraghanta marked this conversation as resolved.
COPY pyproject.toml uv.lock ./

# Install the local development settings
RUN pip install -r requirements/local.txt --compile --no-cache-dir
# Install the default groups (dev + test). --inexact keeps the base image's pip.
RUN uv sync --locked --inexact


COPY . .
Expand Down
2 changes: 1 addition & 1 deletion apps/api/plane/app/views/issue/sub_issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

# Django imports
from django.utils import timezone
from django.db.models import OuterRef, Func, F, Q, Value, UUIDField, Subquery, Count, IntegerField
from django.db.models import OuterRef, F, Value, UUIDField, Subquery, Count, IntegerField
from django.utils.decorators import method_decorator
from django.views.decorators.gzip import gzip_page
from django.contrib.postgres.aggregates import ArrayAgg
Expand Down
1 change: 0 additions & 1 deletion apps/api/plane/app/views/project/invite.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
ProjectMember,
Workspace,
ProjectMemberInvite,
User,
WorkspaceMember,
Project,
ProjectUserProperty,
Expand Down
Loading
Loading