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
90 changes: 74 additions & 16 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ on:
- main

jobs:
test:
lint:
runs-on: ubuntu-latest

steps:
Expand All @@ -23,40 +23,98 @@ jobs:
uses: actions/setup-python@v6
with:
python-version: '3.13'
cache: 'pip' # caching pip dependencies
cache: 'pip'

- name: Install dependencies
run: |
pip install -r requirements.txt
pip install -e .
run: python -m pip install -e ".[dev]"

- name: Lint
run: make lint

unit:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'

- name: Install dependencies
run: python -m pip install -e ".[dev]"

- name: Run smoke tests
run: make test-unit

integration:
runs-on: ubuntu-latest
needs:
- lint
- unit
strategy:
fail-fast: false
matrix:
include:
- python-version: '3.8'
moodle-image: erseco/alpine-moodle:v4.5.5
moodle-label: Moodle 4.5.5
moodle-cache-key: moodle-4-5-5
run-examples: false
- python-version: '3.13'
moodle-image: erseco/alpine-moodle:v5.0.1
moodle-label: Moodle 5.0.1
moodle-cache-key: moodle-5-0-1
run-examples: true

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'

- name: Install dependencies
run: python -m pip install -e ".[dev]"

- name: Cache Docker images
uses: actions/cache@v5
with:
path: /tmp/docker-cache
key: ${{ runner.os }}-docker-${{ hashFiles('docker-compose.yml') }}
path: /tmp/docker-cache/${{ matrix.moodle-cache-key }}
key: ${{ runner.os }}-docker-${{ matrix.moodle-cache-key }}-${{ hashFiles('docker-compose.yml') }}

- name: Load cached Docker images
run: |
if [ -f /tmp/docker-cache/postgres.tar ]; then docker load -i /tmp/docker-cache/postgres.tar; fi
if [ -f /tmp/docker-cache/moodle.tar ]; then docker load -i /tmp/docker-cache/moodle.tar; fi
if [ -f /tmp/docker-cache/${{ matrix.moodle-cache-key }}/postgres.tar ]; then
docker load -i /tmp/docker-cache/${{ matrix.moodle-cache-key }}/postgres.tar
fi
if [ -f /tmp/docker-cache/${{ matrix.moodle-cache-key }}/moodle.tar ]; then
docker load -i /tmp/docker-cache/${{ matrix.moodle-cache-key }}/moodle.tar
fi

- name: Start Moodle with Docker Compose (in backgroud)
run: make upd
- name: Start ${{ matrix.moodle-label }} with Docker Compose
run: MOODLE_DOCKER_IMAGE="${{ matrix.moodle-image }}" make upd

- name: Run tests
run: make test
run: make test-local

- name: Run example_script.py
if: matrix.run-examples
run: python example_script.py

- name: Save Docker images to cache
if: always()
run: |
mkdir -p /tmp/docker-cache
docker save postgres:alpine -o /tmp/docker-cache/postgres.tar
docker save erseco/alpine-moodle:v4.5.5 -o /tmp/docker-cache/moodle.tar

mkdir -p /tmp/docker-cache/${{ matrix.moodle-cache-key }}
docker save postgres:16-alpine -o /tmp/docker-cache/${{ matrix.moodle-cache-key }}/postgres.tar
docker save "${{ matrix.moodle-image }}" -o /tmp/docker-cache/${{ matrix.moodle-cache-key }}/moodle.tar
22 changes: 16 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
ENV_FILE=.env

.PHONY: ensure-env check-docker up format lint docs docs-generate test test-local test-staging
.PHONY: ensure-env check-docker up format lint docs docs-generate test test-unit test-local test-staging

ensure-env:
@if [ ! -f $(ENV_FILE) ]; then cp .env.example $(ENV_FILE); fi
Expand All @@ -15,13 +15,19 @@ up: check-docker ensure-env
upd: check-docker ensure-env
docker compose up -d
@echo "Waiting for Moodle to be ready..."
@for i in $$(seq 1 60); do \
if curl -s --head http://localhost | grep "200 OK" > /dev/null; then \
@ready=0; \
for i in $$(seq 1 60); do \
if curl -fsSL http://localhost/login/index.php > /dev/null; then \
echo "Moodle is up!"; \
ready=1; \
break; \
fi; \
sleep 5; \
done
done; \
if [ $$ready -ne 1 ]; then \
echo "Moodle did not become ready in time."; \
exit 1; \
fi

format:
black .
Expand All @@ -36,11 +42,14 @@ docs:
python -m typer py_moodle.cli.app utils docs --output docs/cli.md --name py-moodle
mkdocs build --strict

test-unit:
pytest tests/unit

test-local: ensure-env
pytest --moodle-env local -n auto
pytest --integration --moodle-env local -m integration -n auto

test-staging: ensure-env
pytest --moodle-env staging -n auto
pytest --integration --moodle-env staging -m integration -n auto

test: upd test-local

Expand All @@ -63,6 +72,7 @@ help:
@echo " docs - Build documentation with mkdocs"
@echo ""
@echo "Testing:"
@echo " test-unit - Run fast smoke tests that do not require Moodle"
@echo " test-local - Run local tests (in parallel) using pytest with moodle-env=local"
@echo " test-staging - Run tests (in parallel) using moodle-env=staging"
@echo " test - Start containers (detached) and run local tests"
Expand Down
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

[![MIT License](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/erseco/python-moodle/blob/main/LICENSE)
[![Python Version](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
[![CI](https://github.com/erseco/python-moodle/actions/workflows/ci.yml/badge.svg)](https://github.com/erseco/python-moodle/actions/workflows/ci.yml)
[![PyPI downloads](https://img.shields.io/pypi/dm/python-moodle)](https://pypi.org/project/python-moodle/)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![GitHub repository](https://img.shields.io/badge/github-repository-blue)](https://github.com/erseco/python-moodle)
Expand Down Expand Up @@ -191,7 +192,13 @@ This script is the best starting point for understanding how to use the library'

The project uses `pytest` and provides a `Makefile` with convenient targets.

Run the default test suite against the local environment:
Run the fast smoke test suite (no Moodle service required):

```bash
make test-unit
```

Run the Docker-backed integration suite against the local environment:

```bash
make test-local
Expand All @@ -209,6 +216,14 @@ Run all configured environments:
make test
```

GitHub Actions automatically runs:

- linting on Python 3.13
- smoke tests on Python 3.8 through 3.13
- Docker-backed integration tests on representative Python/Moodle combinations:
- Python 3.8 with Moodle 4.5.5
- Python 3.13 with Moodle 5.0.1

## Development

Use the Makefile to format code, run linters, or build the documentation:
Expand Down
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
services:

postgres:
image: postgres:alpine
image: postgres:16-alpine
restart: unless-stopped
environment:
- POSTGRES_PASSWORD=moodle
Expand All @@ -12,7 +12,7 @@ services:
- postgres:/var/lib/postgresql/data

moodle:
image: erseco/alpine-moodle:v4.5.5
image: ${MOODLE_DOCKER_IMAGE:-erseco/alpine-moodle:v4.5.5}
restart: unless-stopped
environment:
DEBUG: true
Expand Down
2 changes: 2 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ addopts = -ra -q
testpaths = tests
python_files = test_*.py
pythonpath = src
markers =
integration: tests that require a live Moodle instance
3 changes: 2 additions & 1 deletion src/py_moodle/course.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# src/moodle/course.py
"""
Course management module for Moodle.

Provides functions to list courses, retrieve course details,
and enumerate course sections using AJAX endpoints.
"""

from __future__ import annotations

import json
import time
import urllib.parse
Expand Down
3 changes: 2 additions & 1 deletion src/py_moodle/folder.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# src/moodle/folder.py
"""
Folder module management for Moodle CLI.

Expand All @@ -9,6 +8,8 @@
All code and comments are in English.
"""

from __future__ import annotations

import json
import re
import time
Expand Down
3 changes: 2 additions & 1 deletion src/py_moodle/module.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# src/moodle/module.py
"""
Generic Moodle module management helpers.
All code and comments are in English.
"""

from __future__ import annotations

import json
import re
import time
Expand Down
3 changes: 2 additions & 1 deletion src/py_moodle/session.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# src/moodle/session.py
"""Reusable, thread-safe Moodle session.

Lazy login on first access and cache sessions per environment.
"""

from __future__ import annotations

import threading
from typing import TYPE_CHECKING

Expand Down
Loading
Loading