Skip to content

Commit 29aecd9

Browse files
committed
feat: add storage backend support and CI/CD workflows
- Introduced configurable storage backends: memory, Redis, and Vault, with detailed configuration options in `config.example.yaml`. - Implemented a `StorageManager` to handle storage backend initialization and management. - Added Docker Compose file for easy deployment with Redis storage. - Created GitHub Actions workflows for linting, testing, and Docker image publishing. - Updated documentation to include storage backend details and usage examples. - Enhanced tests for storage functionality and configuration validation.
1 parent 76f86da commit 29aecd9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+5280
-912
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
name: Docker Publish
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
tags: [ 'v*' ]
7+
workflow_dispatch:
8+
9+
env:
10+
REGISTRY: ghcr.io
11+
IMAGE_NAME: ${{ github.repository }}
12+
13+
jobs:
14+
build-and-publish:
15+
runs-on: ubuntu-latest
16+
permissions:
17+
contents: read
18+
packages: write
19+
20+
steps:
21+
- name: Checkout repository
22+
uses: actions/checkout@v4
23+
24+
- name: Set up Docker Buildx
25+
uses: docker/setup-buildx-action@v3
26+
27+
- name: Log in to Container Registry
28+
uses: docker/login-action@v3
29+
with:
30+
registry: ${{ env.REGISTRY }}
31+
username: ${{ github.actor }}
32+
password: ${{ secrets.GITHUB_TOKEN }}
33+
34+
- name: Extract metadata
35+
id: meta
36+
uses: docker/metadata-action@v5
37+
with:
38+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
39+
tags: |
40+
type=ref,event=branch
41+
type=ref,event=pr
42+
type=semver,pattern={{version}}
43+
type=semver,pattern={{major}}.{{minor}}
44+
type=sha,prefix=sha-
45+
type=raw,value=latest,enable={{is_default_branch}}
46+
47+
- name: Build and push Docker image
48+
uses: docker/build-push-action@v5
49+
with:
50+
context: .
51+
platforms: linux/amd64,linux/arm64
52+
push: true
53+
tags: ${{ steps.meta.outputs.tags }}
54+
labels: ${{ steps.meta.outputs.labels }}
55+
cache-from: type=gha
56+
cache-to: type=gha,mode=max

.github/workflows/lint.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: Lint
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
workflow_dispatch:
9+
10+
jobs:
11+
lint:
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- uses: actions/checkout@v4
16+
17+
- name: Set up Python
18+
uses: actions/setup-python@v4
19+
with:
20+
python-version: "3.11"
21+
cache: 'pip'
22+
23+
- name: Install linting dependencies
24+
run: |
25+
python -m pip install --upgrade pip
26+
pip install black>=23.0.0 ruff>=0.1.0
27+
28+
- name: Check code formatting with Black
29+
run: |
30+
black --check --diff src/ tests/ demo/
31+
32+
- name: Lint with Ruff
33+
run: |
34+
ruff check src/ tests/ demo/
35+
36+
- name: Check for security issues with Bandit
37+
run: |
38+
pip install bandit[toml]>=1.7.0
39+
bandit -r src/ -f json -o bandit-report.json || true
40+
bandit -r src/
41+
42+
- name: Type checking with mypy (optional)
43+
run: |
44+
pip install mypy>=1.0.0 types-PyYAML types-requests
45+
mypy src/ --ignore-missing-imports --no-strict-optional || true

.github/workflows/test.yml

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
workflow_dispatch:
9+
10+
jobs:
11+
test:
12+
runs-on: ubuntu-latest
13+
strategy:
14+
matrix:
15+
python-version: ["3.9", "3.10", "3.11", "3.12"]
16+
17+
services:
18+
redis:
19+
image: redis:7-alpine
20+
ports:
21+
- 6379:6379
22+
options: >-
23+
--health-cmd "redis-cli ping"
24+
--health-interval 10s
25+
--health-timeout 5s
26+
--health-retries 5
27+
28+
steps:
29+
- uses: actions/checkout@v4
30+
31+
- name: Set up Python ${{ matrix.python-version }}
32+
uses: actions/setup-python@v4
33+
with:
34+
python-version: ${{ matrix.python-version }}
35+
cache: 'pip'
36+
37+
- name: Install dependencies
38+
run: |
39+
python -m pip install --upgrade pip
40+
pip install -r requirements.txt
41+
42+
# Install coverage for test reporting
43+
pip install pytest-cov>=4.0.0
44+
45+
# Install storage backend dependencies for comprehensive testing
46+
# Use modern redis library for Python 3.11+ compatibility
47+
if [[ "${{ matrix.python-version }}" == "3.11" || "${{ matrix.python-version }}" == "3.12" ]]; then
48+
pip install 'redis[hiredis]>=4.5.0'
49+
else
50+
pip install aioredis>=2.0.0
51+
fi
52+
53+
# Install Vault dependencies
54+
pip install hvac>=1.2.0 aiohttp>=3.8.0
55+
56+
- name: Wait for Redis
57+
run: |
58+
timeout 30 bash -c 'until redis-cli ping; do sleep 1; done'
59+
60+
- name: Run tests with coverage
61+
run: |
62+
python -m pytest -v --tb=short --cov=src --cov-report=xml --cov-report=term-missing
63+
env:
64+
# Redis service connection for testing
65+
REDIS_HOST: localhost
66+
REDIS_PORT: 6379
67+
REDIS_PASSWORD: ""
68+
69+
- name: Upload coverage to Codecov
70+
uses: codecov/codecov-action@v3
71+
if: matrix.python-version == '3.11'
72+
with:
73+
file: ./coverage.xml
74+
fail_ci_if_error: true
75+
76+
- name: Test CLI entry point
77+
run: |
78+
python -m src.gateway --help
79+
80+
- name: Test storage backends
81+
run: |
82+
# Test memory storage (default)
83+
python -c "
84+
import asyncio
85+
from src.storage.manager import StorageManager
86+
from src.config.config import StorageConfig
87+
88+
async def test():
89+
config = StorageConfig(type='memory')
90+
manager = StorageManager(config)
91+
storage = await manager.start_storage()
92+
await storage.set('test', {'data': 'value'})
93+
result = await storage.get('test')
94+
assert result == {'data': 'value'}
95+
await manager.stop_storage()
96+
print('✅ Memory storage test passed')
97+
98+
asyncio.run(test())
99+
"
100+
101+
# Test Redis storage with service
102+
python -c "
103+
import asyncio
104+
from src.storage.manager import StorageManager
105+
from src.config.config import StorageConfig, RedisStorageConfig
106+
107+
async def test():
108+
config = StorageConfig(
109+
type='redis',
110+
redis=RedisStorageConfig(
111+
host='localhost',
112+
port=6379,
113+
password='',
114+
db=0,
115+
ssl=False,
116+
max_connections=20
117+
)
118+
)
119+
manager = StorageManager(config)
120+
storage = await manager.start_storage()
121+
await storage.set('test', {'redis': 'works'})
122+
result = await storage.get('test')
123+
assert result == {'redis': 'works'}
124+
await manager.stop_storage()
125+
print('✅ Redis storage test passed')
126+
127+
asyncio.run(test())
128+
"
129+
env:
130+
REDIS_HOST: localhost

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ data/
341341
!config/*.example.yaml
342342
!config/*.example.yml
343343
!config.example.yaml
344+
!.github/workflows/*.yml
344345

345346
# =============================================================================
346347
# Project Specific
@@ -374,7 +375,6 @@ development/
374375
# =============================================================================
375376

376377
# CI/CD specific files (keep templates)
377-
.github/workflows/*.yml
378378
!.github/workflows/*.example.yml
379379

380380
# Coverage reports
@@ -398,3 +398,6 @@ perf.data.old
398398
.claude/
399399

400400
.ruff_cache/
401+
402+
# Docker compose
403+
!docker-compose.yml

0 commit comments

Comments
 (0)