chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
# Contributing to LightRAG
|
||||
|
||||
Thank you for your interest in contributing! This guide covers everything you need to get started.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Ways to Contribute](#ways-to-contribute)
|
||||
- [Development Setup](#development-setup)
|
||||
- [Code Style](#code-style)
|
||||
- [Running Tests](#running-tests)
|
||||
- [Submitting a Pull Request](#submitting-a-pull-request)
|
||||
- [Reporting Bugs](#reporting-bugs)
|
||||
- [Requesting Features](#requesting-features)
|
||||
|
||||
---
|
||||
|
||||
## Ways to Contribute
|
||||
|
||||
- **Bug reports** — open an [issue](https://github.com/HKUDS/LightRAG/issues) using the Bug Report template
|
||||
- **Feature requests** — open an [issue](https://github.com/HKUDS/LightRAG/issues) using the Feature Request template
|
||||
- **Documentation** — fix typos, clarify explanations, or add examples
|
||||
- **Code** — fix bugs, implement features, or add storage/LLM backends
|
||||
- **Testing** — add test coverage for untested code paths
|
||||
|
||||
---
|
||||
|
||||
## Development Setup
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://github.com/HKUDS/LightRAG.git
|
||||
cd LightRAG
|
||||
|
||||
# Install in development mode (requires uv)
|
||||
uv sync
|
||||
source .venv/bin/activate # Linux/macOS
|
||||
# .venv\Scripts\activate # Windows
|
||||
|
||||
# Install with optional extras as needed
|
||||
uv sync --extra api # FastAPI server
|
||||
uv sync --extra test # Test dependencies
|
||||
uv sync --extra offline-storage # Storage backends
|
||||
uv sync --extra offline-llm # Additional LLM providers
|
||||
|
||||
# Set up pre-commit hooks (run once)
|
||||
pip install pre-commit
|
||||
pre-commit install
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Code Style
|
||||
|
||||
This project uses [Ruff](https://docs.astral.sh/ruff/) for formatting and linting, enforced via [pre-commit](https://pre-commit.com/).
|
||||
|
||||
### Automatic fixing
|
||||
|
||||
Running `pre-commit run --all-files` will automatically fix most style issues:
|
||||
|
||||
```bash
|
||||
# Fix all files
|
||||
pre-commit run --all-files
|
||||
|
||||
# Fix only staged files (faster during development)
|
||||
pre-commit run
|
||||
```
|
||||
|
||||
### What is checked
|
||||
|
||||
| Hook | What it does |
|
||||
|------|-------------|
|
||||
| `trailing-whitespace` | Removes trailing whitespace |
|
||||
| `end-of-file-fixer` | Ensures files end with a newline |
|
||||
| `requirements-txt-fixer` | Keeps `requirements.txt` entries sorted |
|
||||
| `ruff-format` | Formats Python code (Black-compatible) |
|
||||
| `ruff` | Fixes Python lint errors |
|
||||
|
||||
### CI check
|
||||
|
||||
The same checks run automatically on every pull request. If the CI check fails, run `pre-commit run --all-files` locally, commit the fixes, and push again.
|
||||
|
||||
### Language conventions
|
||||
|
||||
- **Python code and comments**: English
|
||||
- **Frontend (WebUI)**: uses i18next for internationalization — add translation keys rather than hardcoding strings
|
||||
|
||||
---
|
||||
|
||||
## Running Tests
|
||||
|
||||
```bash
|
||||
# Run offline tests (no external services required)
|
||||
python -m pytest tests
|
||||
|
||||
# Run integration tests (requires configured external services)
|
||||
python -m pytest tests --run-integration
|
||||
|
||||
# Run a specific test file
|
||||
python -m pytest tests/chunker/test_chunking.py
|
||||
|
||||
# Keep test artifacts for debugging
|
||||
python -m pytest tests --keep-artifacts
|
||||
```
|
||||
|
||||
Set `LIGHTRAG_RUN_INTEGRATION=true` as an environment variable as an alternative to `--run-integration`.
|
||||
|
||||
---
|
||||
|
||||
## Submitting a Pull Request
|
||||
|
||||
1. **Fork** the repository and create a branch from `main`:
|
||||
```bash
|
||||
git checkout -b fix/your-descriptive-branch-name
|
||||
```
|
||||
|
||||
2. **Make your changes** and ensure:
|
||||
- Pre-commit checks pass: `pre-commit run --all-files`
|
||||
- Relevant tests pass: `python -m pytest tests`
|
||||
- New behavior is covered by tests where applicable
|
||||
|
||||
3. **Commit** with a clear message describing *why* the change was made:
|
||||
```bash
|
||||
git commit -m "fix: handle permission-only encrypted PDFs without password"
|
||||
```
|
||||
|
||||
4. **Push** and open a pull request against `main`. Fill out the pull request template completely.
|
||||
|
||||
5. **Respond to review feedback** — a maintainer will review your PR and may request changes.
|
||||
|
||||
### Pull request checklist
|
||||
|
||||
- [ ] Changes tested locally
|
||||
- [ ] Pre-commit checks pass (`pre-commit run --all-files`)
|
||||
- [ ] Unit/integration tests added or updated where applicable
|
||||
- [ ] Documentation updated if behavior changes
|
||||
- [ ] PR description explains the *why*, not just the *what*
|
||||
|
||||
---
|
||||
|
||||
## Reporting Bugs
|
||||
|
||||
Please use the [Bug Report issue template](https://github.com/HKUDS/LightRAG/issues/new?template=bug_report.yml). Include:
|
||||
|
||||
- LightRAG version and Python version
|
||||
- Storage backend and LLM provider being used
|
||||
- Minimal reproducible example
|
||||
- Full error traceback
|
||||
|
||||
---
|
||||
|
||||
## Requesting Features
|
||||
|
||||
Please use the [Feature Request issue template](https://github.com/HKUDS/LightRAG/issues/new?template=feature_request.yml). Describe:
|
||||
|
||||
- The problem you're trying to solve
|
||||
- Your proposed solution
|
||||
- Any alternatives you've considered
|
||||
|
||||
---
|
||||
|
||||
## Questions
|
||||
|
||||
For usage questions, check the [Discussions](https://github.com/HKUDS/LightRAG/discussions) tab or open a [Question issue](https://github.com/HKUDS/LightRAG/issues/new?template=question.yml).
|
||||
@@ -0,0 +1,61 @@
|
||||
name: Bug Report
|
||||
description: File a bug report
|
||||
title: "[Bug]:"
|
||||
labels: ["bug", "triage"]
|
||||
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: existingcheck
|
||||
attributes:
|
||||
label: Do you need to file an issue?
|
||||
description: Please help us manage our time by avoiding duplicates and common bugs with the steps below.
|
||||
options:
|
||||
- label: I have searched the existing issues and this bug is not already filed.
|
||||
- label: I believe this is a legitimate bug, not just a question or feature request.
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Describe the bug
|
||||
description: A clear and concise description of what the bug is.
|
||||
placeholder: What went wrong?
|
||||
- type: textarea
|
||||
id: reproduce
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: Steps to reproduce the behavior.
|
||||
placeholder: How can we replicate the issue?
|
||||
- type: textarea
|
||||
id: expected_behavior
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: A clear and concise description of what you expected to happen.
|
||||
placeholder: What should have happened?
|
||||
- type: textarea
|
||||
id: configused
|
||||
attributes:
|
||||
label: LightRAG Config Used
|
||||
description: The LightRAG configuration used for the run.
|
||||
placeholder: The settings content or LightRAG configuration
|
||||
value: |
|
||||
# Paste your config here
|
||||
- type: textarea
|
||||
id: screenshotslogs
|
||||
attributes:
|
||||
label: Logs and screenshots
|
||||
description: If applicable, add screenshots and logs to help explain your problem.
|
||||
placeholder: Add logs and screenshots here
|
||||
- type: textarea
|
||||
id: additional_information
|
||||
attributes:
|
||||
label: Additional Information
|
||||
description: |
|
||||
- LightRAG Version: e.g., v0.1.1
|
||||
- Operating System: e.g., Windows 10, Ubuntu 20.04
|
||||
- Python Version: e.g., 3.8
|
||||
- Related Issues: e.g., #1
|
||||
- Any other relevant information.
|
||||
value: |
|
||||
- LightRAG Version:
|
||||
- Operating System:
|
||||
- Python Version:
|
||||
- Related Issues:
|
||||
@@ -0,0 +1 @@
|
||||
blank_issues_enabled: false
|
||||
@@ -0,0 +1,26 @@
|
||||
name: Feature Request
|
||||
description: File a feature request
|
||||
labels: ["enhancement"]
|
||||
title: "[Feature Request]:"
|
||||
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: existingcheck
|
||||
attributes:
|
||||
label: Do you need to file a feature request?
|
||||
description: Please help us manage our time by avoiding duplicates and common feature request with the steps below.
|
||||
options:
|
||||
- label: I have searched the existing feature request and this feature request is not already filed.
|
||||
- label: I believe this is a legitimate feature request, not just a question or bug.
|
||||
- type: textarea
|
||||
id: feature_request_description
|
||||
attributes:
|
||||
label: Feature Request Description
|
||||
description: A clear and concise description of the feature request you would like.
|
||||
placeholder: What this feature request add more or improve?
|
||||
- type: textarea
|
||||
id: additional_context
|
||||
attributes:
|
||||
label: Additional Context
|
||||
description: Add any other context or screenshots about the feature request here.
|
||||
placeholder: Any additional information
|
||||
@@ -0,0 +1,26 @@
|
||||
name: Question
|
||||
description: Ask a general question
|
||||
labels: ["question"]
|
||||
title: "[Question]:"
|
||||
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: existingcheck
|
||||
attributes:
|
||||
label: Do you need to ask a question?
|
||||
description: Please help us manage our time by avoiding duplicates and common questions with the steps below.
|
||||
options:
|
||||
- label: I have searched the existing question and discussions and this question is not already answered.
|
||||
- label: I believe this is a legitimate question, not just a bug or feature request.
|
||||
- type: textarea
|
||||
id: question
|
||||
attributes:
|
||||
label: Your Question
|
||||
description: A clear and concise description of your question.
|
||||
placeholder: What is your question?
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional Context
|
||||
description: Provide any additional context or details that might help us understand your question better.
|
||||
placeholder: Add any relevant information here
|
||||
@@ -0,0 +1,206 @@
|
||||
# Keep GitHub Actions up to date with GitHub's Dependabot...
|
||||
# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot
|
||||
# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem
|
||||
version: 2
|
||||
updates:
|
||||
# ============================================================
|
||||
# GitHub Actions
|
||||
# PR Strategy:
|
||||
# - All updates (major/minor/patch): Grouped into a single PR
|
||||
# ============================================================
|
||||
- package-ecosystem: github-actions
|
||||
directory: /
|
||||
groups:
|
||||
github-actions:
|
||||
patterns:
|
||||
- "*" # Group all Actions updates into a single larger pull request
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: monday
|
||||
time: "02:00"
|
||||
timezone: "Asia/Shanghai"
|
||||
labels:
|
||||
- "dependencies"
|
||||
- "github-actions"
|
||||
open-pull-requests-limit: 2
|
||||
|
||||
# ============================================================
|
||||
# Python (pip) Dependencies
|
||||
# PR Strategy:
|
||||
# - Major updates: Individual PR per package (except numpy which is ignored)
|
||||
# - Minor updates: Grouped by category (llm-providers, storage, etc.)
|
||||
# - Patch updates: Grouped by category
|
||||
# ============================================================
|
||||
- package-ecosystem: "pip"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "wednesday"
|
||||
time: "02:00"
|
||||
timezone: "Asia/Shanghai"
|
||||
cooldown:
|
||||
default-days: 5
|
||||
semver-major-days: 30
|
||||
semver-minor-days: 7
|
||||
semver-patch-days: 3
|
||||
groups:
|
||||
# Core dependencies - LLM providers and embeddings
|
||||
llm-providers:
|
||||
patterns:
|
||||
- "openai"
|
||||
- "anthropic"
|
||||
- "google-*"
|
||||
- "boto3"
|
||||
- "botocore"
|
||||
- "ollama"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
# Storage backends
|
||||
storage:
|
||||
patterns:
|
||||
- "neo4j"
|
||||
- "pymongo"
|
||||
- "redis"
|
||||
- "psycopg*"
|
||||
- "asyncpg"
|
||||
- "milvus*"
|
||||
- "qdrant*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
# Data processing and ML
|
||||
data-processing:
|
||||
patterns:
|
||||
- "numpy"
|
||||
- "scipy"
|
||||
- "pandas"
|
||||
- "tiktoken"
|
||||
- "transformers"
|
||||
- "torch*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
# Web framework and API
|
||||
web-framework:
|
||||
patterns:
|
||||
- "fastapi"
|
||||
- "uvicorn"
|
||||
- "gunicorn"
|
||||
- "starlette"
|
||||
- "pydantic*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
# Development and testing tools
|
||||
dev-tools:
|
||||
patterns:
|
||||
- "pytest*"
|
||||
- "ruff"
|
||||
- "pre-commit"
|
||||
- "black"
|
||||
- "mypy"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
# Minor and patch updates for everything else
|
||||
python-minor-patch:
|
||||
patterns:
|
||||
- "*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
ignore:
|
||||
- dependency-name: "numpy"
|
||||
update-types:
|
||||
- "version-update:semver-major"
|
||||
labels:
|
||||
- "dependencies"
|
||||
- "python"
|
||||
open-pull-requests-limit: 5
|
||||
|
||||
# ============================================================
|
||||
# Frontend (bun) Dependencies
|
||||
# PR Strategy:
|
||||
# - Major updates: Individual PR per package
|
||||
# - Minor updates: Grouped by category (react, ui-components, etc.)
|
||||
# - Patch updates: Grouped by category
|
||||
# ============================================================
|
||||
- package-ecosystem: "bun"
|
||||
directory: "/lightrag_webui"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "friday"
|
||||
time: "02:00"
|
||||
timezone: "Asia/Shanghai"
|
||||
cooldown:
|
||||
default-days: 5
|
||||
semver-major-days: 30
|
||||
semver-minor-days: 7
|
||||
semver-patch-days: 3
|
||||
groups:
|
||||
# React ecosystem
|
||||
react:
|
||||
patterns:
|
||||
- "react"
|
||||
- "react-dom"
|
||||
- "react-router*"
|
||||
- "@types/react*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
# UI components and styling
|
||||
ui-components:
|
||||
patterns:
|
||||
- "@radix-ui/*"
|
||||
- "tailwind*"
|
||||
- "@tailwindcss/*"
|
||||
- "lucide-react"
|
||||
- "class-variance-authority"
|
||||
- "clsx"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
# Graph visualization
|
||||
graph-viz:
|
||||
patterns:
|
||||
- "sigma"
|
||||
- "@sigma/*"
|
||||
- "graphology*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
# Build tools and dev dependencies
|
||||
build-tools:
|
||||
patterns:
|
||||
- "vite"
|
||||
- "@vitejs/*"
|
||||
- "typescript"
|
||||
- "eslint*"
|
||||
- "@eslint/*"
|
||||
- "typescript-eslint"
|
||||
- "prettier"
|
||||
- "prettier-*"
|
||||
- "@types/bun"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
# Content rendering libraries (math, diagrams, etc.)
|
||||
content-rendering:
|
||||
patterns:
|
||||
- "katex"
|
||||
- "mermaid"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
# All other minor and patch updates
|
||||
frontend-minor-patch:
|
||||
patterns:
|
||||
- "*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
labels:
|
||||
- "dependencies"
|
||||
- "frontend"
|
||||
open-pull-requests-limit: 5
|
||||
@@ -0,0 +1,32 @@
|
||||
<!--
|
||||
Thanks for contributing to LightRAG!
|
||||
|
||||
Please ensure your pull request is ready for review before submitting.
|
||||
|
||||
About this template
|
||||
|
||||
This template helps contributors provide a clear and concise description of their changes. Feel free to adjust it as needed.
|
||||
-->
|
||||
|
||||
## Description
|
||||
|
||||
[Briefly describe the changes made in this pull request.]
|
||||
|
||||
## Related Issues
|
||||
|
||||
[Reference any related issues or tasks addressed by this pull request.]
|
||||
|
||||
## Changes Made
|
||||
|
||||
[List the specific changes made in this pull request.]
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] Changes tested locally
|
||||
- [ ] Code reviewed
|
||||
- [ ] Documentation updated (if necessary)
|
||||
- [ ] Unit tests added (if applicable)
|
||||
|
||||
## Additional Notes
|
||||
|
||||
[Add any additional notes or context for the reviewer(s).]
|
||||
@@ -0,0 +1,58 @@
|
||||
name: "Copilot Setup Steps"
|
||||
|
||||
# Automatically run the setup steps when they are changed to allow for easy validation, and
|
||||
# allow manual testing through the repository's "Actions" tab
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths:
|
||||
- .github/workflows/copilot-setup-steps.yml
|
||||
pull_request:
|
||||
paths:
|
||||
- .github/workflows/copilot-setup-steps.yml
|
||||
|
||||
jobs:
|
||||
# The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot.
|
||||
copilot-setup-steps:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# Timeout after 30 minutes (maximum is 59)
|
||||
timeout-minutes: 30
|
||||
|
||||
# You can define any steps you want, and they will run before the agent starts.
|
||||
# If you do not check out your code, Copilot will do this for you.
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Set up Python 3.11
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Cache pip packages
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-copilot-${{ hashFiles('**/pyproject.toml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-copilot-
|
||||
${{ runner.os }}-pip-
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -e ".[api]"
|
||||
pip install pytest pytest-asyncio httpx2
|
||||
|
||||
- name: Create minimal frontend stub for Copilot agent
|
||||
run: |
|
||||
mkdir -p lightrag/api/webui
|
||||
echo '<!DOCTYPE html><html><head><title>LightRAG - Copilot Agent</title></head><body><h1>Copilot Agent Mode</h1></body></html>' > lightrag/api/webui/index.html
|
||||
echo "Created minimal frontend stub for Copilot agent environment"
|
||||
|
||||
- name: Verify installation
|
||||
run: |
|
||||
python --version
|
||||
pip list | grep lightrag
|
||||
lightrag-server --help || echo "Note: Server requires .env configuration to run"
|
||||
@@ -0,0 +1,113 @@
|
||||
name: Build Lite Docker Image
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
_notes_:
|
||||
description: '⚠️ Create lite Docker images only after non-trivial version releases.'
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
build-and-push-lite:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.x"
|
||||
|
||||
- name: Get latest tag
|
||||
id: get_tag
|
||||
run: |
|
||||
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
||||
if [ -z "$LATEST_TAG" ]; then
|
||||
LATEST_TAG="sha-$(git rev-parse --short HEAD)"
|
||||
echo "No tags found, using commit SHA: $LATEST_TAG"
|
||||
else
|
||||
echo "Latest tag found: $LATEST_TAG"
|
||||
fi
|
||||
PACKAGE_VERSION="${LATEST_TAG#v}"
|
||||
echo "tag=$LATEST_TAG" >> $GITHUB_OUTPUT
|
||||
echo "package_version=$PACKAGE_VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Prepare lite tag
|
||||
id: lite_tag
|
||||
run: |
|
||||
LITE_TAG="${{ steps.get_tag.outputs.tag }}-lite"
|
||||
echo "Lite image tag: $LITE_TAG"
|
||||
echo "lite_tag=$LITE_TAG" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Update version definitions
|
||||
run: |
|
||||
python scripts/release/set_version.py --core-version "${{ steps.get_tag.outputs.package_version }}"
|
||||
grep '__version__ = ' lightrag/_version.py
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Install cosign
|
||||
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
|
||||
|
||||
- name: Extract metadata for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: ghcr.io/${{ github.repository }}
|
||||
tags: |
|
||||
type=raw,value=${{ steps.lite_tag.outputs.lite_tag }}
|
||||
type=raw,value=lite
|
||||
|
||||
- name: Build and push lite Docker image
|
||||
id: build-and-push
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.lite
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=min
|
||||
|
||||
- name: Sign lite Docker image
|
||||
if: steps.build-and-push.outputs.digest != ''
|
||||
env:
|
||||
DIGEST: ${{ steps.build-and-push.outputs.digest }}
|
||||
TAGS: ${{ steps.meta.outputs.tags }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
echo "Signing manifest digest: $DIGEST"
|
||||
while IFS= read -r tag; do
|
||||
if [ -z "$tag" ]; then
|
||||
continue
|
||||
fi
|
||||
echo "Signing ${tag}@${DIGEST}"
|
||||
cosign sign --yes "${tag}@${DIGEST}"
|
||||
done <<< "$TAGS"
|
||||
|
||||
- name: Output image details
|
||||
run: |
|
||||
echo "Lite Docker image built and pushed successfully!"
|
||||
echo "Image tag: ghcr.io/${{ github.repository }}:${{ steps.lite_tag.outputs.lite_tag }}"
|
||||
echo "Signed manifest digest: ${{ steps.build-and-push.outputs.digest }}"
|
||||
echo "Base Git tag used: ${{ steps.get_tag.outputs.tag }}"
|
||||
@@ -0,0 +1,109 @@
|
||||
name: Build Test Docker Image manually
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
_notes_:
|
||||
description: '⚠️ Please create a new git tag before building the docker image.'
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0 # Fetch all history for tags
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.x"
|
||||
|
||||
- name: Get latest tag
|
||||
id: get_tag
|
||||
run: |
|
||||
# Get the latest tag, fallback to commit SHA if no tags exist
|
||||
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
||||
if [ -z "$LATEST_TAG" ]; then
|
||||
LATEST_TAG="sha-$(git rev-parse --short HEAD)"
|
||||
echo "No tags found, using commit SHA: $LATEST_TAG"
|
||||
else
|
||||
echo "Latest tag found: $LATEST_TAG"
|
||||
fi
|
||||
PACKAGE_VERSION="${LATEST_TAG#v}"
|
||||
echo "tag=$LATEST_TAG" >> $GITHUB_OUTPUT
|
||||
echo "image_tag=$LATEST_TAG" >> $GITHUB_OUTPUT
|
||||
echo "package_version=$PACKAGE_VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Update version definitions
|
||||
run: |
|
||||
python scripts/release/set_version.py --core-version "${{ steps.get_tag.outputs.package_version }}"
|
||||
echo "Updated version definitions with ${{ steps.get_tag.outputs.package_version }}"
|
||||
grep '__version__ = ' lightrag/_version.py
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Install cosign
|
||||
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
|
||||
|
||||
- name: Extract metadata for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: ghcr.io/${{ github.repository }}
|
||||
tags: |
|
||||
type=raw,value=${{ steps.get_tag.outputs.tag }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
id: build-and-push
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- name: Sign Docker image
|
||||
if: steps.build-and-push.outputs.digest != ''
|
||||
env:
|
||||
DIGEST: ${{ steps.build-and-push.outputs.digest }}
|
||||
TAGS: ${{ steps.meta.outputs.tags }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
echo "Signing manifest digest: $DIGEST"
|
||||
while IFS= read -r tag; do
|
||||
if [ -z "$tag" ]; then
|
||||
continue
|
||||
fi
|
||||
echo "Signing ${tag}@${DIGEST}"
|
||||
cosign sign --yes "${tag}@${DIGEST}"
|
||||
done <<< "$TAGS"
|
||||
|
||||
- name: Output image details
|
||||
run: |
|
||||
echo "Docker image built and pushed successfully!"
|
||||
echo "Image tags:"
|
||||
echo " - ghcr.io/${{ github.repository }}:${{ steps.get_tag.outputs.tag }}"
|
||||
echo "Signed manifest digest: ${{ steps.build-and-push.outputs.digest }}"
|
||||
echo "Latest Git tag used: ${{ steps.get_tag.outputs.tag }}"
|
||||
@@ -0,0 +1,120 @@
|
||||
name: Build Latest Docker Image on Release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0 # Fetch all history for tags
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.x"
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Install cosign
|
||||
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
|
||||
|
||||
- name: Get latest tag
|
||||
id: get_tag
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" = "release" ] && [ -n "${{ github.event.release.tag_name }}" ]; then
|
||||
TAG="${{ github.event.release.tag_name }}"
|
||||
else
|
||||
TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
||||
fi
|
||||
if [ -z "$TAG" ]; then
|
||||
echo "No git tag found for docker publish"
|
||||
exit 1
|
||||
fi
|
||||
PACKAGE_VERSION="${TAG#v}"
|
||||
echo "Found tag: $TAG"
|
||||
echo "tag=$TAG" >> $GITHUB_OUTPUT
|
||||
echo "package_version=$PACKAGE_VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Check if pre-release
|
||||
id: check_prerelease
|
||||
run: |
|
||||
TAG="${{ steps.get_tag.outputs.tag }}"
|
||||
if [[ "$TAG" == *"rc"* ]] || [[ "$TAG" == *"dev"* ]]; then
|
||||
echo "is_prerelease=true" >> $GITHUB_OUTPUT
|
||||
echo "This is a pre-release version: $TAG"
|
||||
else
|
||||
echo "is_prerelease=false" >> $GITHUB_OUTPUT
|
||||
echo "This is a stable release: $TAG"
|
||||
fi
|
||||
|
||||
- name: Update version definitions
|
||||
run: |
|
||||
python scripts/release/set_version.py --core-version "${{ steps.get_tag.outputs.package_version }}"
|
||||
echo "Updated version definitions with ${{ steps.get_tag.outputs.package_version }}"
|
||||
grep '__version__ = ' lightrag/_version.py
|
||||
|
||||
- name: Extract metadata for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: ghcr.io/${{ github.repository }}
|
||||
tags: |
|
||||
type=raw,value=${{ steps.get_tag.outputs.tag }}
|
||||
type=raw,value=latest,enable=${{ steps.check_prerelease.outputs.is_prerelease == 'false' }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
id: build-and-push
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- name: Sign Docker image
|
||||
if: steps.build-and-push.outputs.digest != ''
|
||||
env:
|
||||
DIGEST: ${{ steps.build-and-push.outputs.digest }}
|
||||
TAGS: ${{ steps.meta.outputs.tags }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
echo "Signing manifest digest: $DIGEST"
|
||||
while IFS= read -r tag; do
|
||||
if [ -z "$tag" ]; then
|
||||
continue
|
||||
fi
|
||||
echo "Signing ${tag}@${DIGEST}"
|
||||
cosign sign --yes "${tag}@${DIGEST}"
|
||||
done <<< "$TAGS"
|
||||
|
||||
- name: Output image details
|
||||
run: |
|
||||
echo "Docker image built and pushed successfully!"
|
||||
echo "Image tags:"
|
||||
echo " - ghcr.io/${{ github.repository }}:${{ steps.get_tag.outputs.tag }}"
|
||||
echo " - ghcr.io/${{ github.repository }}:latest"
|
||||
echo "Signed manifest digest: ${{ steps.build-and-push.outputs.digest }}"
|
||||
echo "Latest Git tag used: ${{ steps.get_tag.outputs.tag }}"
|
||||
@@ -0,0 +1,134 @@
|
||||
name: Linting and Formatting
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, dev ]
|
||||
pull_request:
|
||||
branches: [ main, dev ]
|
||||
types: [opened, synchronize, reopened, ready_for_review]
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
lint-and-format:
|
||||
name: Linting and Formatting
|
||||
if: ${{ github.event_name != 'pull_request' || !github.event.pull_request.draft }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install pre-commit
|
||||
|
||||
- name: Run pre-commit
|
||||
id: pre-commit
|
||||
run: pre-commit run --all-files --show-diff-on-failure
|
||||
|
||||
- name: Post fix instructions on failure
|
||||
if: failure() && steps.pre-commit.outcome == 'failure'
|
||||
run: |
|
||||
cat >> "$GITHUB_STEP_SUMMARY" << 'EOF'
|
||||
## ❌ Linting / Formatting checks failed
|
||||
|
||||
Pre-commit found issues in your code. Fix them locally and push again:
|
||||
|
||||
```bash
|
||||
# Install pre-commit (one-time setup)
|
||||
pip install pre-commit
|
||||
pre-commit install
|
||||
|
||||
# Auto-fix all issues
|
||||
pre-commit run --all-files
|
||||
|
||||
# Commit the fixes
|
||||
git add -u
|
||||
git commit -m "fix: apply pre-commit formatting fixes"
|
||||
git push
|
||||
```
|
||||
|
||||
### What was checked
|
||||
|
||||
| Hook | Tool | What it fixes |
|
||||
|------|------|---------------|
|
||||
| `trailing-whitespace` | pre-commit-hooks | Removes trailing whitespace |
|
||||
| `end-of-file-fixer` | pre-commit-hooks | Ensures files end with a newline |
|
||||
| `requirements-txt-fixer` | pre-commit-hooks | Sorts requirements.txt entries |
|
||||
| `ruff-format` | Ruff | Auto-formats Python code (like Black) |
|
||||
| `ruff` | Ruff | Fixes Python lint errors (`--fix`) |
|
||||
|
||||
> See the diff above for the exact changes needed.
|
||||
EOF
|
||||
|
||||
- name: Comment on PR with fix instructions
|
||||
if: failure() && steps.pre-commit.outcome == 'failure' && github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
|
||||
uses: actions/github-script@v9
|
||||
with:
|
||||
script: |
|
||||
const body = `## ❌ Linting / Formatting checks failed
|
||||
|
||||
Pre-commit found issues in your code. Run the following locally, then push again:
|
||||
|
||||
\`\`\`bash
|
||||
# Install pre-commit (one-time setup)
|
||||
pip install pre-commit
|
||||
pre-commit install
|
||||
|
||||
# Auto-fix all issues
|
||||
pre-commit run --all-files
|
||||
|
||||
# Commit the fixes
|
||||
git add -u
|
||||
git commit -m "fix: apply pre-commit formatting fixes"
|
||||
git push
|
||||
\`\`\`
|
||||
|
||||
<details>
|
||||
<summary>What was checked</summary>
|
||||
|
||||
| Hook | Tool | What it fixes |
|
||||
|------|------|---------------|
|
||||
| \`trailing-whitespace\` | pre-commit-hooks | Removes trailing whitespace |
|
||||
| \`end-of-file-fixer\` | pre-commit-hooks | Ensures files end with a newline |
|
||||
| \`requirements-txt-fixer\` | pre-commit-hooks | Sorts requirements.txt entries |
|
||||
| \`ruff-format\` | Ruff | Auto-formats Python code (like Black) |
|
||||
| \`ruff\` | Ruff | Fixes Python lint errors (\`--fix\`) |
|
||||
|
||||
</details>
|
||||
|
||||
> See the [workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for the exact diff of required changes.`;
|
||||
|
||||
// Find existing bot comment to avoid duplicates
|
||||
const { data: comments } = await github.rest.issues.listComments({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
});
|
||||
const existing = comments.find(c =>
|
||||
c.user.type === 'Bot' && c.body.includes('Linting / Formatting checks failed')
|
||||
);
|
||||
|
||||
if (existing) {
|
||||
await github.rest.issues.updateComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
comment_id: existing.id,
|
||||
body,
|
||||
});
|
||||
} else {
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
body,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
name: Upload LightRAG-hku Package
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
release-build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0 # Fetch all history for tags
|
||||
|
||||
# Build frontend WebUI
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Build Frontend WebUI
|
||||
run: |
|
||||
cd lightrag_webui
|
||||
bun install --frozen-lockfile
|
||||
bun run build
|
||||
cd ..
|
||||
|
||||
- name: Verify Frontend Build
|
||||
run: |
|
||||
if [ ! -f "lightrag/api/webui/index.html" ]; then
|
||||
echo "❌ Error: Frontend build failed - index.html not found"
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ Frontend build verified"
|
||||
echo "Frontend files:"
|
||||
ls -lh lightrag/api/webui/ | head -10
|
||||
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.x"
|
||||
|
||||
- name: Resolve release version
|
||||
id: get_version
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" = "release" ] && [ -n "${{ github.event.release.tag_name }}" ]; then
|
||||
TAG="${{ github.event.release.tag_name }}"
|
||||
else
|
||||
TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
||||
fi
|
||||
if [ -z "$TAG" ]; then
|
||||
echo "No git tag found for release build"
|
||||
exit 1
|
||||
fi
|
||||
PACKAGE_VERSION="${TAG#v}"
|
||||
echo "Found tag: $TAG"
|
||||
echo "Package version: $PACKAGE_VERSION"
|
||||
echo "version=$TAG" >> $GITHUB_OUTPUT
|
||||
echo "package_version=$PACKAGE_VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Update version definitions
|
||||
run: |
|
||||
python scripts/release/set_version.py --core-version "${{ steps.get_version.outputs.package_version }}"
|
||||
grep '__version__ = ' lightrag/_version.py
|
||||
|
||||
- name: Build release distributions
|
||||
run: |
|
||||
python -m pip install build
|
||||
python -m build
|
||||
|
||||
- name: Upload distributions
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: release-dists
|
||||
path: dist/
|
||||
|
||||
pypi-publish:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- release-build
|
||||
permissions:
|
||||
id-token: write
|
||||
|
||||
environment:
|
||||
name: pypi
|
||||
|
||||
steps:
|
||||
- name: Retrieve release distributions
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: release-dists
|
||||
path: dist/
|
||||
|
||||
- name: Publish release distributions to PyPI
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
packages-dir: dist/
|
||||
@@ -0,0 +1,27 @@
|
||||
# .github/workflows/stale.yml
|
||||
name: Mark stale issues and pull requests
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '30 22 * * *' # run at 22:30+08 every day
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v10
|
||||
with:
|
||||
days-before-stale: 90 # 90 days
|
||||
days-before-close: 7 # 7 days after marked as stale
|
||||
stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.'
|
||||
close-issue-message: 'This issue has been automatically closed because it has not had recent activity. Please open a new issue if you still have this problem.'
|
||||
stale-pr-message: 'This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.'
|
||||
close-pr-message: 'This pull request has been automatically closed because it has not had recent activity.'
|
||||
# If there are specific labels, exempt them from being marked as stale, for example:
|
||||
exempt-issue-labels: 'enhancement,tracked'
|
||||
# exempt-pr-labels: 'bug,enhancement,help wanted'
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }} # token provided by GitHub
|
||||
@@ -0,0 +1,61 @@
|
||||
name: Offline Unit Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, dev ]
|
||||
pull_request:
|
||||
branches: [ main, dev ]
|
||||
types: [opened, synchronize, reopened, ready_for_review]
|
||||
|
||||
jobs:
|
||||
offline-tests:
|
||||
name: Offline Tests
|
||||
if: ${{ github.event_name != 'pull_request' || !github.event.pull_request.draft }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ['3.12', '3.14']
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Cache pip packages
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt', '**/pyproject.toml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
# Install optional-storage and optional-llm deps too — the offline
|
||||
# test suite contains mock-based unit tests that construct real
|
||||
# data classes from these libraries (qdrant-client, pymongo,
|
||||
# anthropic, boto3, etc.). Without them, importorskip falls back
|
||||
# and the tests are silently skipped.
|
||||
pip install -e ".[api,offline-storage,offline-llm]"
|
||||
pip install pytest pytest-asyncio httpx2
|
||||
|
||||
- name: Run offline tests
|
||||
run: |
|
||||
# Run only tests marked as 'offline' (no external dependencies)
|
||||
# Integration tests requiring databases/APIs are skipped by default
|
||||
pytest tests/ -m offline -v --tb=short
|
||||
|
||||
- name: Upload test results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: test-results-py${{ matrix.python-version }}
|
||||
path: |
|
||||
.pytest_cache/
|
||||
test-results.xml
|
||||
retention-days: 7
|
||||
Reference in New Issue
Block a user