Skip to content

Commit 9dbea13

Browse files
authored
Merge pull request #20 from laurigates/pr-2-infrastructure-ci-cd
Development Infrastructure & CI/CD
2 parents e6961ce + 99fce1e commit 9dbea13

File tree

8 files changed

+887
-17
lines changed

8 files changed

+887
-17
lines changed

.github/workflows/ci.yml

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ main, develop ]
6+
pull_request:
7+
branches: [ main, develop ]
8+
9+
jobs:
10+
lint:
11+
runs-on: ubuntu-latest
12+
name: Lint and Format
13+
14+
steps:
15+
- uses: actions/checkout@v4
16+
17+
- name: Install uv
18+
uses: astral-sh/setup-uv@v4
19+
with:
20+
enable-cache: true
21+
22+
- name: Set up Python 3.12
23+
run: |
24+
uv python install 3.12
25+
uv python pin 3.12
26+
27+
- name: Install dependencies
28+
run: uv sync --group dev
29+
30+
- name: Lint with ruff
31+
run: uv run ruff check kicad_mcp/ tests/
32+
33+
- name: Check formatting with ruff
34+
run: uv run ruff format --check kicad_mcp/ tests/
35+
36+
test:
37+
runs-on: ${{ matrix.os }}
38+
strategy:
39+
fail-fast: false
40+
matrix:
41+
os: [ubuntu-latest, macos-latest]
42+
python-version: ["3.10", "3.11", "3.12"]
43+
44+
name: Test Python ${{ matrix.python-version }} on ${{ matrix.os }}
45+
46+
steps:
47+
- uses: actions/checkout@v4
48+
49+
- name: Install uv
50+
uses: astral-sh/setup-uv@v4
51+
with:
52+
enable-cache: true
53+
54+
- name: Set up Python ${{ matrix.python-version }}
55+
run: |
56+
uv python install ${{ matrix.python-version }}
57+
uv python pin ${{ matrix.python-version }}
58+
59+
- name: Install dependencies
60+
run: uv sync --group dev
61+
62+
- name: Run tests
63+
run: uv run python -m pytest tests/ -v --cov=kicad_mcp --cov-report=xml --cov-fail-under=30
64+
65+
- name: Upload coverage to Codecov
66+
uses: codecov/codecov-action@v4
67+
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12'
68+
with:
69+
file: ./coverage.xml
70+
fail_ci_if_error: false
71+
72+
build:
73+
runs-on: ubuntu-latest
74+
name: Build Package
75+
needs: [lint, test]
76+
77+
steps:
78+
- uses: actions/checkout@v4
79+
80+
- name: Install uv
81+
uses: astral-sh/setup-uv@v4
82+
with:
83+
enable-cache: true
84+
85+
- name: Set up Python 3.12
86+
run: |
87+
uv python install 3.12
88+
uv python pin 3.12
89+
90+
- name: Build package
91+
run: uv build
92+
93+
- name: Upload artifacts
94+
uses: actions/upload-artifact@v4
95+
with:
96+
name: dist
97+
path: dist/

.gitignore

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ htmlcov/
3333
nosetests.xml
3434
coverage.xml
3535
*.cover
36+
.pytest_cache/
3637

3738
# Logs
3839
logs/
@@ -47,3 +48,25 @@ logs/
4748

4849
# MCP specific
4950
~/.kicad_mcp/drc_history/
51+
52+
# UV and modern Python tooling
53+
uv.lock
54+
.uv-cache/
55+
.ruff_cache/
56+
57+
# Pre-commit
58+
.pre-commit-config.yaml
59+
60+
# KiCad backup files
61+
*-backups/
62+
fp-info-cache
63+
*.bak
64+
*.backup
65+
*.kicad_pcb-bak
66+
*.kicad_sch-bak
67+
*.kicad_pro-bak
68+
*.kicad_prl
69+
*.kicad_prl-bak
70+
*.kicad_sch.lck
71+
*.kicad_pcb.lck
72+
*.kicad_pro.lck

Makefile

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
.PHONY: help install test lint format clean build run
2+
3+
help:
4+
@echo "Available commands:"
5+
@echo " install Install dependencies"
6+
@echo " test Run tests"
7+
@echo " lint Run linting"
8+
@echo " format Format code"
9+
@echo " clean Clean build artifacts"
10+
@echo " build Build package"
11+
12+
install:
13+
uv sync --group dev
14+
15+
test:
16+
uv run python -m pytest tests/ -v
17+
18+
lint:
19+
uv run ruff check kicad_mcp/ tests/
20+
uv run mypy kicad_mcp/
21+
22+
format:
23+
uv run ruff format kicad_mcp/ tests/
24+
25+
clean:
26+
rm -rf dist/
27+
rm -rf build/
28+
rm -rf *.egg-info/
29+
rm -rf .pytest_cache/
30+
rm -rf htmlcov/
31+
rm -f coverage.xml
32+
find . -type d -name __pycache__ -delete
33+
find . -type f -name "*.pyc" -delete
34+
35+
build:
36+
uv build
37+
38+
run:
39+
uv run python main.py

README.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ This guide will help you set up a Model Context Protocol (MCP) server for KiCad.
2222
- macOS, Windows, or Linux
2323
- Python 3.10 or higher
2424
- KiCad 9.0 or higher
25+
- uv 0.8.0 or higher
2526
- Claude Desktop (or another MCP client)
2627

2728
## Installation Steps
@@ -32,14 +33,15 @@ First, let's install dependencies and set up our environment:
3233

3334
```bash
3435
# Clone the repository
35-
git clone https://github.com/lamaalrajih/kicad-mcp.git .
36+
git clone https://github.com/lamaalrajih/kicad-mcp.git
37+
cd kicad-mcp
3638

37-
# Create a virtual environment and activate it
38-
python3 -m venv venv
39-
source venv/bin/activate # On Windows: venv\Scripts\activate
39+
# Install dependencies – `uv` will create a `.venv/` folder automatically
40+
# (Install `uv` first: `brew install uv` on macOS or `pipx install uv`)
41+
make install
4042

41-
# Install the MCP SDK and other dependencies
42-
pip install -r requirements.txt
43+
# Optional: activate the environment for manual commands
44+
source .venv/bin/activate
4345
```
4446

4547
### 2. Configure Your Environment
@@ -89,7 +91,7 @@ vim ~/Library/Application\ Support/Claude/claude_desktop_config.json
8991
{
9092
"mcpServers": {
9193
"kicad": {
92-
"command": "/ABSOLUTE/PATH/TO/YOUR/PROJECT/kicad-mcp/venv/bin/python",
94+
"command": "/ABSOLUTE/PATH/TO/YOUR/PROJECT/kicad-mcp/.venv/bin/python",
9395
"args": [
9496
"/ABSOLUTE/PATH/TO/YOUR/PROJECT/kicad-mcp/main.py"
9597
]

pyproject.toml

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ authors = [
1414
requires-python = ">=3.10"
1515
dependencies = [
1616
"mcp[cli]>=1.0.0",
17-
"fastmcp>=0.1.0",
1817
"pandas>=2.0.0",
18+
"fastmcp>=2.0.0",
1919
]
2020
classifiers = [
2121
"Programming Language :: Python :: 3",
@@ -41,8 +41,50 @@ kicad-mcp = "kicad_mcp.server:main"
4141
dev = [
4242
"pytest>=7.0.0",
4343
"pytest-asyncio>=0.23.0",
44+
"pytest-mock>=3.10.0",
45+
"pytest-cov>=4.0.0",
46+
"pytest-xdist>=3.0.0",
47+
"ruff>=0.1.0",
48+
"mypy>=1.8.0",
49+
"pre-commit>=3.0.0",
4450
]
4551

52+
[tool.ruff]
53+
target-version = "py310"
54+
line-length = 100
55+
56+
[tool.ruff.lint]
57+
select = [
58+
"E", # pycodestyle errors
59+
"W", # pycodestyle warnings
60+
"F", # pyflakes
61+
"I", # isort
62+
"B", # flake8-bugbear
63+
"UP", # pyupgrade
64+
]
65+
ignore = [
66+
"E501", # line too long, handled by ruff format
67+
"B008", # do not perform function calls in argument defaults
68+
]
69+
70+
[tool.ruff.format]
71+
quote-style = "double"
72+
indent-style = "space"
73+
74+
[tool.pytest.ini_options]
75+
minversion = "7.0"
76+
addopts = [
77+
"--strict-markers",
78+
"--strict-config",
79+
"--cov=kicad_mcp",
80+
"--cov-report=term-missing",
81+
"--cov-report=html:htmlcov",
82+
"--cov-report=xml",
83+
"--cov-fail-under=30",
84+
]
85+
testpaths = ["tests"]
86+
asyncio_mode = "auto"
87+
4688
[tool.setuptools.packages.find]
4789
where = ["."]
4890
include = ["kicad_mcp*"]

requirements.txt

Lines changed: 0 additions & 5 deletions
This file was deleted.

run_tests.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Test runner for KiCad MCP project.
4+
"""
5+
import subprocess
6+
import sys
7+
from pathlib import Path
8+
9+
10+
def run_command(cmd: list[str], description: str) -> int:
11+
"""Run a command and return the exit code."""
12+
print(f"\n🔍 {description}")
13+
print(f"Running: {' '.join(cmd)}")
14+
15+
try:
16+
result = subprocess.run(cmd, check=False)
17+
if result.returncode == 0:
18+
print(f"✅ {description} passed")
19+
else:
20+
print(f"❌ {description} failed with exit code {result.returncode}")
21+
return result.returncode
22+
except FileNotFoundError:
23+
print(f"❌ Command not found: {cmd[0]}")
24+
return 1
25+
26+
27+
def main():
28+
"""Run all tests and checks."""
29+
project_root = Path(__file__).parent
30+
31+
# Change to project directory
32+
import os
33+
34+
os.chdir(project_root)
35+
36+
exit_code = 0
37+
38+
# Run linting
39+
exit_code |= run_command(["uv", "run", "ruff", "check", "kicad_mcp/", "tests/"], "Lint check")
40+
41+
# Run formatting check
42+
exit_code |= run_command(
43+
["uv", "run", "ruff", "format", "--check", "kicad_mcp/", "tests/"], "Format check"
44+
)
45+
46+
# Run type checking
47+
exit_code |= run_command(["uv", "run", "mypy", "kicad_mcp/"], "Type check")
48+
49+
# Run tests
50+
exit_code |= run_command(["uv", "run", "python", "-m", "pytest", "tests/", "-v"], "Unit tests")
51+
52+
if exit_code == 0:
53+
print("\n🎉 All checks passed!")
54+
else:
55+
print(f"\n💥 Some checks failed (exit code: {exit_code})")
56+
57+
return exit_code
58+
59+
60+
if __name__ == "__main__":
61+
sys.exit(main())

0 commit comments

Comments
 (0)