router-maestro 0.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- router_maestro-0.1.2/.env.example +20 -0
- router_maestro-0.1.2/.gitignore +103 -0
- router_maestro-0.1.2/CLAUDE.md +79 -0
- router_maestro-0.1.2/Dockerfile +64 -0
- router_maestro-0.1.2/LICENSE +21 -0
- router_maestro-0.1.2/Makefile +140 -0
- router_maestro-0.1.2/PKG-INFO +383 -0
- router_maestro-0.1.2/README.md +346 -0
- router_maestro-0.1.2/docker-compose.yml +72 -0
- router_maestro-0.1.2/docs/deployment.md +210 -0
- router_maestro-0.1.2/pyproject.toml +81 -0
- router_maestro-0.1.2/src/router_maestro/__init__.py +3 -0
- router_maestro-0.1.2/src/router_maestro/__main__.py +6 -0
- router_maestro-0.1.2/src/router_maestro/auth/__init__.py +18 -0
- router_maestro-0.1.2/src/router_maestro/auth/github_oauth.py +181 -0
- router_maestro-0.1.2/src/router_maestro/auth/manager.py +136 -0
- router_maestro-0.1.2/src/router_maestro/auth/storage.py +91 -0
- router_maestro-0.1.2/src/router_maestro/cli/__init__.py +1 -0
- router_maestro-0.1.2/src/router_maestro/cli/auth.py +167 -0
- router_maestro-0.1.2/src/router_maestro/cli/client.py +322 -0
- router_maestro-0.1.2/src/router_maestro/cli/config.py +132 -0
- router_maestro-0.1.2/src/router_maestro/cli/context.py +146 -0
- router_maestro-0.1.2/src/router_maestro/cli/main.py +42 -0
- router_maestro-0.1.2/src/router_maestro/cli/model.py +288 -0
- router_maestro-0.1.2/src/router_maestro/cli/server.py +117 -0
- router_maestro-0.1.2/src/router_maestro/cli/stats.py +76 -0
- router_maestro-0.1.2/src/router_maestro/config/__init__.py +72 -0
- router_maestro-0.1.2/src/router_maestro/config/contexts.py +29 -0
- router_maestro-0.1.2/src/router_maestro/config/paths.py +50 -0
- router_maestro-0.1.2/src/router_maestro/config/priorities.py +93 -0
- router_maestro-0.1.2/src/router_maestro/config/providers.py +34 -0
- router_maestro-0.1.2/src/router_maestro/config/server.py +115 -0
- router_maestro-0.1.2/src/router_maestro/config/settings.py +76 -0
- router_maestro-0.1.2/src/router_maestro/providers/__init__.py +31 -0
- router_maestro-0.1.2/src/router_maestro/providers/anthropic.py +203 -0
- router_maestro-0.1.2/src/router_maestro/providers/base.py +123 -0
- router_maestro-0.1.2/src/router_maestro/providers/copilot.py +346 -0
- router_maestro-0.1.2/src/router_maestro/providers/openai.py +188 -0
- router_maestro-0.1.2/src/router_maestro/providers/openai_compat.py +175 -0
- router_maestro-0.1.2/src/router_maestro/routing/__init__.py +5 -0
- router_maestro-0.1.2/src/router_maestro/routing/router.py +526 -0
- router_maestro-0.1.2/src/router_maestro/server/__init__.py +5 -0
- router_maestro-0.1.2/src/router_maestro/server/app.py +87 -0
- router_maestro-0.1.2/src/router_maestro/server/middleware/__init__.py +11 -0
- router_maestro-0.1.2/src/router_maestro/server/middleware/auth.py +66 -0
- router_maestro-0.1.2/src/router_maestro/server/oauth_sessions.py +159 -0
- router_maestro-0.1.2/src/router_maestro/server/routes/__init__.py +8 -0
- router_maestro-0.1.2/src/router_maestro/server/routes/admin.py +358 -0
- router_maestro-0.1.2/src/router_maestro/server/routes/anthropic.py +228 -0
- router_maestro-0.1.2/src/router_maestro/server/routes/chat.py +142 -0
- router_maestro-0.1.2/src/router_maestro/server/routes/models.py +34 -0
- router_maestro-0.1.2/src/router_maestro/server/schemas/__init__.py +57 -0
- router_maestro-0.1.2/src/router_maestro/server/schemas/admin.py +87 -0
- router_maestro-0.1.2/src/router_maestro/server/schemas/anthropic.py +246 -0
- router_maestro-0.1.2/src/router_maestro/server/schemas/openai.py +107 -0
- router_maestro-0.1.2/src/router_maestro/server/translation.py +636 -0
- router_maestro-0.1.2/src/router_maestro/stats/__init__.py +14 -0
- router_maestro-0.1.2/src/router_maestro/stats/heatmap.py +154 -0
- router_maestro-0.1.2/src/router_maestro/stats/storage.py +228 -0
- router_maestro-0.1.2/src/router_maestro/stats/tracker.py +73 -0
- router_maestro-0.1.2/src/router_maestro/utils/__init__.py +16 -0
- router_maestro-0.1.2/src/router_maestro/utils/logging.py +81 -0
- router_maestro-0.1.2/src/router_maestro/utils/tokens.py +51 -0
- router_maestro-0.1.2/tests/__init__.py +1 -0
- router_maestro-0.1.2/tests/test_auth.py +94 -0
- router_maestro-0.1.2/tests/test_config.py +86 -0
- router_maestro-0.1.2/tests/test_providers.py +115 -0
- router_maestro-0.1.2/tests/test_router.py +147 -0
- router_maestro-0.1.2/tests/test_stats.py +78 -0
- router_maestro-0.1.2/tests/test_translation.py +181 -0
- router_maestro-0.1.2/tests/test_utils.py +63 -0
- router_maestro-0.1.2/uv.lock +1152 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Domain configuration
|
|
2
|
+
DOMAIN=api.example.com
|
|
3
|
+
|
|
4
|
+
# Cloudflare API token for DNS challenge
|
|
5
|
+
# Generate at: https://dash.cloudflare.com/profile/api-tokens
|
|
6
|
+
# Required permissions: Zone:DNS:Edit
|
|
7
|
+
CF_DNS_API_TOKEN=your_cloudflare_api_token
|
|
8
|
+
|
|
9
|
+
# Let's Encrypt email for certificate notifications
|
|
10
|
+
ACME_EMAIL=your-email@example.com
|
|
11
|
+
|
|
12
|
+
# Router-Maestro API key (generate a secure random string)
|
|
13
|
+
ROUTER_MAESTRO_API_KEY=your_secure_api_key_here
|
|
14
|
+
|
|
15
|
+
# Log level (DEBUG, INFO, WARNING, ERROR)
|
|
16
|
+
ROUTER_MAESTRO_LOG_LEVEL=INFO
|
|
17
|
+
|
|
18
|
+
# Traefik dashboard auth (generate with: htpasswd -nB admin)
|
|
19
|
+
# Example: admin:$2y$05$... (user:bcrypt_hash)
|
|
20
|
+
TRAEFIK_DASHBOARD_AUTH=admin:$$2y$$05$$your_bcrypt_hash_here
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.pyc
|
|
6
|
+
*.pyo
|
|
7
|
+
*.pyd
|
|
8
|
+
|
|
9
|
+
# C extensions
|
|
10
|
+
*.so
|
|
11
|
+
|
|
12
|
+
# Distribution / packaging
|
|
13
|
+
.Python
|
|
14
|
+
build/
|
|
15
|
+
develop-eggs/
|
|
16
|
+
dist/
|
|
17
|
+
downloads/
|
|
18
|
+
eggs/
|
|
19
|
+
.eggs/
|
|
20
|
+
lib/
|
|
21
|
+
lib64/
|
|
22
|
+
parts/
|
|
23
|
+
sdist/
|
|
24
|
+
var/
|
|
25
|
+
wheels/
|
|
26
|
+
*.egg-info/
|
|
27
|
+
.installed.cfg
|
|
28
|
+
*.egg
|
|
29
|
+
*.whl
|
|
30
|
+
*.tar.gz
|
|
31
|
+
|
|
32
|
+
# PyInstaller
|
|
33
|
+
*.manifest
|
|
34
|
+
*.spec
|
|
35
|
+
|
|
36
|
+
# Installer logs
|
|
37
|
+
pip-log.txt
|
|
38
|
+
pip-delete-this-directory.txt
|
|
39
|
+
|
|
40
|
+
# Unit test / coverage reports
|
|
41
|
+
htmlcov/
|
|
42
|
+
.tox/
|
|
43
|
+
.nox/
|
|
44
|
+
.coverage
|
|
45
|
+
.coverage.*
|
|
46
|
+
.cache
|
|
47
|
+
nosetests.xml
|
|
48
|
+
coverage.xml
|
|
49
|
+
*.cover
|
|
50
|
+
*.py,cover
|
|
51
|
+
.hypothesis/
|
|
52
|
+
.pytest_cache/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Environments
|
|
59
|
+
.env
|
|
60
|
+
.venv
|
|
61
|
+
env/
|
|
62
|
+
venv/
|
|
63
|
+
ENV/
|
|
64
|
+
env.bak/
|
|
65
|
+
venv.bak/
|
|
66
|
+
|
|
67
|
+
# IDE
|
|
68
|
+
.idea/
|
|
69
|
+
.vscode/
|
|
70
|
+
.claude/
|
|
71
|
+
.serena/
|
|
72
|
+
*.swp
|
|
73
|
+
*.swo
|
|
74
|
+
*.project
|
|
75
|
+
.pydevproject
|
|
76
|
+
|
|
77
|
+
# UV
|
|
78
|
+
.uv/
|
|
79
|
+
|
|
80
|
+
# Ruff
|
|
81
|
+
.ruff_cache/
|
|
82
|
+
|
|
83
|
+
# MyPy
|
|
84
|
+
.mypy_cache/
|
|
85
|
+
.dmypy.json
|
|
86
|
+
dmypy.json
|
|
87
|
+
|
|
88
|
+
# Logs
|
|
89
|
+
*.log
|
|
90
|
+
|
|
91
|
+
# Project specific
|
|
92
|
+
*.db
|
|
93
|
+
*.sqlite3
|
|
94
|
+
|
|
95
|
+
# macOS
|
|
96
|
+
.DS_Store
|
|
97
|
+
.AppleDouble
|
|
98
|
+
.LSOverride
|
|
99
|
+
|
|
100
|
+
# Temporary files
|
|
101
|
+
*.tmp
|
|
102
|
+
*.bak
|
|
103
|
+
*~
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Build and Development Commands
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Install dependencies
|
|
9
|
+
uv pip install -e ".[dev]"
|
|
10
|
+
|
|
11
|
+
# Run the CLI
|
|
12
|
+
uv run router-maestro --help
|
|
13
|
+
|
|
14
|
+
# Start the API server
|
|
15
|
+
uv run router-maestro server start --port 8080
|
|
16
|
+
|
|
17
|
+
# Run all tests
|
|
18
|
+
uv run pytest tests/ -v
|
|
19
|
+
|
|
20
|
+
# Run a single test file
|
|
21
|
+
uv run pytest tests/test_auth.py -v
|
|
22
|
+
|
|
23
|
+
# Run a specific test
|
|
24
|
+
uv run pytest tests/test_auth.py::TestAuthStorage::test_empty_storage -v
|
|
25
|
+
|
|
26
|
+
# Lint code
|
|
27
|
+
uv run ruff check src/
|
|
28
|
+
|
|
29
|
+
# Format code
|
|
30
|
+
uv run ruff format src/
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Architecture Overview
|
|
34
|
+
|
|
35
|
+
Router-Maestro is a multi-model routing system that exposes both OpenAI-compatible and Anthropic-compatible APIs. It routes requests to various LLM providers (GitHub Copilot, OpenAI, Anthropic, custom) with priority-based routing and fallback support.
|
|
36
|
+
|
|
37
|
+
### Core Components
|
|
38
|
+
|
|
39
|
+
**Router (`src/router_maestro/routing/router.py`)**
|
|
40
|
+
- Central routing logic that selects providers based on model priorities
|
|
41
|
+
- Handles auto-routing when model is `router-maestro`
|
|
42
|
+
- Implements fallback to alternative providers on failure
|
|
43
|
+
- Caches model availability from all providers
|
|
44
|
+
|
|
45
|
+
**Providers (`src/router_maestro/providers/`)**
|
|
46
|
+
- `BaseProvider` - Abstract base class defining the provider interface
|
|
47
|
+
- `CopilotProvider` - GitHub Copilot integration with OAuth
|
|
48
|
+
- `OpenAIProvider` - Native OpenAI API
|
|
49
|
+
- `AnthropicProvider` - Native Anthropic API
|
|
50
|
+
- `OpenAICompatibleProvider` - Custom providers with OpenAI-compatible APIs
|
|
51
|
+
|
|
52
|
+
**Server (`src/router_maestro/server/`)**
|
|
53
|
+
- FastAPI application with two API flavors:
|
|
54
|
+
- OpenAI-compatible: `/v1/chat/completions`, `/v1/models`
|
|
55
|
+
- Anthropic-compatible: `/v1/messages`, `/api/anthropic/v1/messages`
|
|
56
|
+
- `translation.py` - Converts between Anthropic and OpenAI request/response formats
|
|
57
|
+
- `schemas/` - Pydantic models for both API formats
|
|
58
|
+
|
|
59
|
+
**CLI (`src/router_maestro/cli/`)**
|
|
60
|
+
- Typer-based CLI with subcommands: `server`, `auth`, `model`, `context`, `config`, `stats`
|
|
61
|
+
- Each subcommand in its own module registered in `main.py`
|
|
62
|
+
|
|
63
|
+
### Data Flow
|
|
64
|
+
|
|
65
|
+
1. Request arrives at API endpoint (OpenAI or Anthropic format)
|
|
66
|
+
2. Anthropic requests are translated to internal OpenAI format
|
|
67
|
+
3. Router selects provider based on model key and priorities
|
|
68
|
+
4. Provider makes upstream API call
|
|
69
|
+
5. Response is translated back if needed (for Anthropic API)
|
|
70
|
+
|
|
71
|
+
### File Locations
|
|
72
|
+
|
|
73
|
+
Configuration and data files follow XDG conventions:
|
|
74
|
+
- **Config** (`~/.config/router-maestro/`): `providers.json`, `priorities.json`, `contexts.json`
|
|
75
|
+
- **Data** (`~/.local/share/router-maestro/`): `auth.json`, `server.json`, `stats.db`
|
|
76
|
+
|
|
77
|
+
### Model Identification
|
|
78
|
+
|
|
79
|
+
Models are identified by `provider/model-id` format (e.g., `github-copilot/gpt-4o`). The special model name `router-maestro` triggers auto-routing based on priority configuration.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Multi-stage build for minimal final image
|
|
2
|
+
# Stage 1: Builder with compilation tools
|
|
3
|
+
FROM python:3.11-alpine AS builder
|
|
4
|
+
|
|
5
|
+
WORKDIR /app
|
|
6
|
+
|
|
7
|
+
# Install build dependencies for native extensions
|
|
8
|
+
# - gcc, musl-dev: C compiler for native extensions
|
|
9
|
+
# - libffi-dev: Required by cffi/cryptography
|
|
10
|
+
# - cargo, rust: Required by tiktoken
|
|
11
|
+
RUN apk add --no-cache \
|
|
12
|
+
gcc \
|
|
13
|
+
musl-dev \
|
|
14
|
+
libffi-dev \
|
|
15
|
+
cargo \
|
|
16
|
+
rust
|
|
17
|
+
|
|
18
|
+
# Install uv for fast package installation
|
|
19
|
+
RUN pip install --no-cache-dir uv
|
|
20
|
+
|
|
21
|
+
# Copy project files
|
|
22
|
+
COPY pyproject.toml README.md ./
|
|
23
|
+
COPY src/ src/
|
|
24
|
+
|
|
25
|
+
# Install dependencies into a virtual environment
|
|
26
|
+
RUN python -m venv /opt/venv
|
|
27
|
+
ENV PATH="/opt/venv/bin:$PATH"
|
|
28
|
+
RUN uv pip install --no-cache .
|
|
29
|
+
|
|
30
|
+
# Stage 2: Minimal runtime image
|
|
31
|
+
FROM python:3.11-alpine
|
|
32
|
+
|
|
33
|
+
WORKDIR /app
|
|
34
|
+
|
|
35
|
+
# Install runtime dependencies only (no build tools)
|
|
36
|
+
RUN apk add --no-cache \
|
|
37
|
+
libffi \
|
|
38
|
+
curl
|
|
39
|
+
|
|
40
|
+
# Copy virtual environment from builder
|
|
41
|
+
COPY --from=builder /opt/venv /opt/venv
|
|
42
|
+
ENV PATH="/opt/venv/bin:$PATH"
|
|
43
|
+
|
|
44
|
+
# Create non-root user
|
|
45
|
+
RUN adduser -D -u 1000 maestro
|
|
46
|
+
USER maestro
|
|
47
|
+
|
|
48
|
+
# Create data and logs directories
|
|
49
|
+
RUN mkdir -p /home/maestro/.local/share/router-maestro/logs \
|
|
50
|
+
&& mkdir -p /home/maestro/.config/router-maestro
|
|
51
|
+
|
|
52
|
+
# Environment variables
|
|
53
|
+
ENV PYTHONUNBUFFERED=1 \
|
|
54
|
+
PYTHONDONTWRITEBYTECODE=1
|
|
55
|
+
|
|
56
|
+
# Expose default port
|
|
57
|
+
EXPOSE 8080
|
|
58
|
+
|
|
59
|
+
# Health check
|
|
60
|
+
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
|
61
|
+
CMD curl -f http://localhost:8080/health || exit 1
|
|
62
|
+
|
|
63
|
+
# Run the server
|
|
64
|
+
CMD ["router-maestro", "server", "start", "--host", "0.0.0.0", "--port", "8080"]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Router-Maestro Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
.PHONY: help install dev test lint format clean build push run stop logs shell docker-up docker-down docker-logs buildx-setup build-multiarch dist publish publish-test
|
|
2
|
+
|
|
3
|
+
# Variables
|
|
4
|
+
VERSION := $(shell grep '^version' pyproject.toml | head -1 | cut -d'"' -f2)
|
|
5
|
+
IMAGE_NAME := likanwen/router-maestro
|
|
6
|
+
DOCKER_TAGS := -t $(IMAGE_NAME):$(VERSION) -t $(IMAGE_NAME):latest
|
|
7
|
+
PLATFORMS := linux/amd64,linux/arm64
|
|
8
|
+
|
|
9
|
+
# Default target
|
|
10
|
+
help:
|
|
11
|
+
@echo "Router-Maestro Development Commands"
|
|
12
|
+
@echo ""
|
|
13
|
+
@echo "Development:"
|
|
14
|
+
@echo " make install Install dependencies"
|
|
15
|
+
@echo " make dev Install with dev dependencies"
|
|
16
|
+
@echo " make test Run tests"
|
|
17
|
+
@echo " make lint Run linter (ruff check)"
|
|
18
|
+
@echo " make format Format code (ruff format)"
|
|
19
|
+
@echo " make clean Clean build artifacts"
|
|
20
|
+
@echo ""
|
|
21
|
+
@echo "Build & Publish:"
|
|
22
|
+
@echo " make dist Build Python package (sdist + wheel)"
|
|
23
|
+
@echo " make publish Publish to PyPI (requires PYPI_TOKEN)"
|
|
24
|
+
@echo ""
|
|
25
|
+
@echo "Local Server:"
|
|
26
|
+
@echo " make run Start local server (port 8080)"
|
|
27
|
+
@echo " make run-debug Start with DEBUG logging"
|
|
28
|
+
@echo " make stop Stop local server"
|
|
29
|
+
@echo ""
|
|
30
|
+
@echo "Docker:"
|
|
31
|
+
@echo " make build Build Docker image ($(IMAGE_NAME):$(VERSION))"
|
|
32
|
+
@echo " make push Push image to Docker Hub"
|
|
33
|
+
@echo " make buildx-setup Setup Docker buildx for multi-arch builds"
|
|
34
|
+
@echo " make build-multiarch Build and push multi-arch image (amd64, arm64)"
|
|
35
|
+
@echo " make shell Open shell in container"
|
|
36
|
+
@echo ""
|
|
37
|
+
@echo "Docker Compose (Production):"
|
|
38
|
+
@echo " make docker-up Start services (Traefik + Router-Maestro)"
|
|
39
|
+
@echo " make docker-down Stop services"
|
|
40
|
+
@echo " make docker-logs View logs"
|
|
41
|
+
@echo ""
|
|
42
|
+
@echo "Current version: $(VERSION)"
|
|
43
|
+
|
|
44
|
+
# ============== Development ==============
|
|
45
|
+
|
|
46
|
+
install:
|
|
47
|
+
uv pip install .
|
|
48
|
+
|
|
49
|
+
dev:
|
|
50
|
+
uv pip install -e ".[dev]"
|
|
51
|
+
|
|
52
|
+
test:
|
|
53
|
+
uv run pytest tests/ -v
|
|
54
|
+
|
|
55
|
+
lint:
|
|
56
|
+
uv run ruff check src/ tests/
|
|
57
|
+
|
|
58
|
+
format:
|
|
59
|
+
uv run ruff format src/ tests/
|
|
60
|
+
uv run ruff check --fix src/ tests/
|
|
61
|
+
|
|
62
|
+
clean:
|
|
63
|
+
rm -rf build/ dist/ *.egg-info .pytest_cache .ruff_cache src/*.egg-info
|
|
64
|
+
find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
|
|
65
|
+
find . -type f -name "*.pyc" -delete 2>/dev/null || true
|
|
66
|
+
|
|
67
|
+
# ============== Build & Publish ==============
|
|
68
|
+
|
|
69
|
+
dist: clean
|
|
70
|
+
uv build
|
|
71
|
+
|
|
72
|
+
publish: dist
|
|
73
|
+
@if [ -z "$$PYPI_TOKEN" ]; then \
|
|
74
|
+
echo "Error: PYPI_TOKEN environment variable is not set"; \
|
|
75
|
+
echo "Usage: PYPI_TOKEN=your_token make publish"; \
|
|
76
|
+
exit 1; \
|
|
77
|
+
fi
|
|
78
|
+
uv publish --token $$PYPI_TOKEN
|
|
79
|
+
|
|
80
|
+
publish-test: dist
|
|
81
|
+
@if [ -z "$$PYPI_TEST_TOKEN" ]; then \
|
|
82
|
+
echo "Error: PYPI_TEST_TOKEN environment variable is not set"; \
|
|
83
|
+
echo "Usage: PYPI_TEST_TOKEN=your_token make publish-test"; \
|
|
84
|
+
exit 1; \
|
|
85
|
+
fi
|
|
86
|
+
uv publish --token $$PYPI_TEST_TOKEN --publish-url https://test.pypi.org/legacy/
|
|
87
|
+
|
|
88
|
+
# ============== Local Server ==============
|
|
89
|
+
|
|
90
|
+
run:
|
|
91
|
+
uv run router-maestro server start --port 8080
|
|
92
|
+
|
|
93
|
+
run-debug:
|
|
94
|
+
uv run router-maestro server start --port 8080 --log-level DEBUG
|
|
95
|
+
|
|
96
|
+
stop:
|
|
97
|
+
@echo "Use Ctrl+C to stop the server"
|
|
98
|
+
|
|
99
|
+
# ============== Docker ==============
|
|
100
|
+
|
|
101
|
+
build:
|
|
102
|
+
docker build $(DOCKER_TAGS) .
|
|
103
|
+
|
|
104
|
+
push: build
|
|
105
|
+
docker push $(IMAGE_NAME):$(VERSION)
|
|
106
|
+
docker push $(IMAGE_NAME):latest
|
|
107
|
+
|
|
108
|
+
buildx-setup:
|
|
109
|
+
@docker buildx inspect multiarch > /dev/null 2>&1 || docker buildx create --name multiarch --use
|
|
110
|
+
docker buildx inspect --bootstrap
|
|
111
|
+
|
|
112
|
+
build-multiarch: buildx-setup
|
|
113
|
+
docker buildx build --platform $(PLATFORMS) $(DOCKER_TAGS) --push .
|
|
114
|
+
|
|
115
|
+
shell:
|
|
116
|
+
docker run --rm -it $(IMAGE_NAME):latest /bin/sh
|
|
117
|
+
|
|
118
|
+
# ============== Docker Compose ==============
|
|
119
|
+
|
|
120
|
+
docker-up:
|
|
121
|
+
docker compose up -d
|
|
122
|
+
|
|
123
|
+
docker-down:
|
|
124
|
+
docker compose down
|
|
125
|
+
|
|
126
|
+
docker-logs:
|
|
127
|
+
docker compose logs -f
|
|
128
|
+
|
|
129
|
+
docker-restart:
|
|
130
|
+
docker compose restart router-maestro
|
|
131
|
+
|
|
132
|
+
docker-pull:
|
|
133
|
+
docker compose pull
|
|
134
|
+
|
|
135
|
+
# ============== Release ==============
|
|
136
|
+
|
|
137
|
+
release: lint test build push
|
|
138
|
+
@echo "Released $(IMAGE_NAME):$(VERSION)"
|
|
139
|
+
git tag -a v$(VERSION) -m "Release v$(VERSION)"
|
|
140
|
+
@echo "Don't forget to push tags: git push origin v$(VERSION)"
|