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
17 changes: 17 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.git
.github
**/__pycache__/
*.py[cod]
.venv
*venv/
.env
.env.*
todo_folder/
.pytest_cache/
.mypy_cache/
.ruff_cache/
.coverage
htmlcov/
docs/
tests/
scl/storage/skills/
25 changes: 25 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Copy this file to `.env` and fill in the values below.
# `.env` is gitignored — never commit real credentials.

# OceanBase Configuration
OCEANBASE_HOST=
OCEANBASE_PORT=
OCEANBASE_USER=
OCEANBASE_PASSWORD=
OCEANBASE_DATABASE=

# LLM Configuration
API_KEY=
BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
MODEL=qwen-plus

# Embedding Configuration
EMBEDDING_API_KEY=
EMBEDDING_BASE_URL=https://api.siliconflow.cn/v1
EMBEDDING_MODEL=BAAI/bge-large-zh-v1.5
EMBEDDING_MODEL_DIMS=1024

# OpenTelemetry Configuration
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
OTEL_TRACES_EXPORTER=otlp
OTEL_EXPORTER_OTLP_PROTOCOL=grpc
69 changes: 41 additions & 28 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
@@ -1,22 +1,40 @@
# path .github/workflows/test.yaml
# This workflow runs unit tests on every PR and after merges.
# Features (as defined in project header):
# - runs per PR level and after merge
# - checks out code
# - sets up Python environment
# - installs dependencies via requirements.txt
# - installs pytest and pytest-asyncio as test tool
# - runs tests via pytest ./scl/test/
# CI: lint, type-check, and unit tests on every PR and after merges to main.
# Dependencies are installed with uv from the locked pyproject/uv.lock.

name: Unit Tests
name: CI

on:
push:
branches: [ main ] # after merge
pull_request: # per PR level
pull_request: # per PR level
branches: [ main ]

jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v5

- name: Install dependencies
run: uv sync --extra dev

- name: Ruff lint
run: uv run ruff check scl tests main.py

- name: Ruff format check
run: uv run ruff format --check scl tests main.py

- name: Mypy type check
# Non-blocking for now: the codebase is being typed incrementally.
# Remove continue-on-error once mypy passes cleanly.
continue-on-error: true
run: uv run mypy scl

test:
runs-on: ubuntu-latest
strategy:
Expand All @@ -27,26 +45,21 @@ jobs:
- name: Check out code
uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v5

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
run: uv python install ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt

- name: Install test tools
run: pip install pytest pytest-asyncio
run: uv sync --extra dev --python ${{ matrix.python-version }}

- name: Run unit tests
run: pytest ./scl/test/

# Example usage:
# This workflow is automatically triggered by:
# - Pushing to main/master
# - Creating, updating, or reopening a pull request targeting main/master
# Developers can also manually trigger it via the "Actions" tab if needed.
# To debug, inspect the "Run unit tests" step logs in the GitHub Actions console.
# run test via pytest ./scl/test/
run: uv run --python ${{ matrix.python-version }} pytest ./tests/ --cov=scl --cov-report=xml

- name: Upload coverage artifact
uses: actions/upload-artifact@v4
with:
name: coverage-${{ matrix.python-version }}
path: coverage.xml
if-no-files-found: ignore
51 changes: 48 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,51 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.egg-info/
*.egg
.eggs/
build/
dist/
*.so

# Virtual environments
.venv
__pycache__
node_modules
*venv
env/

# Environment / secrets
.env

# Testing & coverage
.pytest_cache/
.coverage
.coverage.*
coverage.xml
htmlcov/
.tox/
.cache/

# Type/lint caches
.mypy_cache/
.ruff_cache/
.dmypy.json

# Logs
*.log
*venv

# Editors / IDE
.idea/
.vscode/
*.swp
*.swo

# OS
.DS_Store
Thumbs.db

# Node
node_modules/

# SCL runtime
todo_folder/
14 changes: 14 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.0
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.18.2
hooks:
- id: mypy
args: [--ignore-missing-imports]
files: ^scl/
exclude: ^scl/(test|storage/skills)/
20 changes: 20 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FROM python:3.13-slim

# uv for fast, reproducible installs
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

WORKDIR /app

# Install dependencies from pyproject.toml for better layer caching.
# README.md is needed by setuptools during build metadata resolution.
COPY pyproject.toml README.md ./
RUN uv pip install --system --no-cache -e .

# Application code (skills submodule is intentionally not included; it is
# optional runtime data fetched separately).
COPY scl ./scl
COPY main.py prometheus.yml ./

EXPOSE 8080

CMD ["python", "main.py"]
48 changes: 48 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
.DEFAULT_GOAL := help
.PHONY: help install lint format format-check typecheck test check run build lock docker-build docker-up docker-down clean

help: ## Show this help
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-14s\033[0m %s\n", $$1, $$2}'

install: ## Install dependencies (core + dev) into the uv environment
uv sync --extra dev

lint: ## Run ruff linter
uv run ruff check scl tests main.py

format: ## Auto-format code with ruff
uv run ruff format scl tests main.py

format-check: ## Check formatting without modifying files
uv run ruff format --check scl tests main.py

typecheck: ## Run mypy type checker
uv run mypy scl

test: ## Run the test suite with coverage
uv run pytest

check: lint format-check typecheck test ## Run all CI checks (lint, format, types, tests)

run: ## Start the SCL service
uv run python main.py

build: ## Build the wheel and sdist into dist/
uv build

lock: ## Refresh uv.lock
uv lock

docker-build: ## Build the application Docker image
docker build -t scl-app .

docker-up: ## Start app + prometheus via docker compose
docker compose up --build

docker-down: ## Stop and remove docker compose services
docker compose down

clean: ## Remove caches and build artifacts
find . -type d -name __pycache__ -not -path '*/skills/*' -exec rm -rf {} + 2>/dev/null || true
rm -rf .pytest_cache .ruff_cache .mypy_cache .coverage coverage.xml *.egg-info dist build
Loading
Loading