Skip to content

Commit 98c4510

Browse files
authored
Merge pull request #10 from Artifizer/main
feat: implement gts-spec v0.6 reference implementation recommendations
2 parents 5c62a5c + 9dfa618 commit 98c4510

18 files changed

Lines changed: 1910 additions & 277 deletions

.github/workflows/ci.yml

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ main, develop ]
6+
paths-ignore:
7+
- '**/*.md'
8+
- 'docs/**'
9+
pull_request:
10+
branches: [ main, develop ]
11+
paths-ignore:
12+
- '**/*.md'
13+
- 'docs/**'
14+
15+
# Cancel previous runs for the same ref to save CI minutes.
16+
concurrency:
17+
group: ci-${{ github.workflow }}-${{ github.ref }}
18+
cancel-in-progress: true
19+
20+
permissions:
21+
contents: read
22+
23+
env:
24+
PYTHONDONTWRITEBYTECODE: 1
25+
PIP_DISABLE_PIP_VERSION_CHECK: 1
26+
27+
jobs:
28+
test:
29+
name: Test Suite (${{ matrix.os }}, python=${{ matrix.python }})
30+
runs-on: ${{ matrix.os }}
31+
strategy:
32+
fail-fast: false
33+
matrix:
34+
os: [ ubuntu-latest, windows-latest, macos-latest ]
35+
python: [ '3.11' ]
36+
37+
steps:
38+
- name: Checkout
39+
uses: actions/checkout@v4
40+
with:
41+
submodules: recursive
42+
43+
- name: Set up Python
44+
uses: actions/setup-python@v5
45+
with:
46+
python-version: ${{ matrix.python }}
47+
cache: 'pip'
48+
49+
- name: Install dependencies
50+
run: |
51+
python -m pip install --upgrade pip
52+
pip install -e ./gts
53+
pip install pytest pytest-cov ruff mypy httpx
54+
55+
- name: Show Python version
56+
run: python --version
57+
58+
# Formatting check (fast fail for style issues)
59+
- name: ruff format (check)
60+
run: ruff format --check gts/src
61+
62+
# Linting
63+
- name: ruff check
64+
run: ruff check gts/src
65+
66+
# Type checking
67+
- name: mypy
68+
run: mypy gts/src/gts --ignore-missing-imports
69+
continue-on-error: true
70+
71+
# Unit tests (skip if no tests exist)
72+
- name: pytest
73+
run: |
74+
if [ -n "$(find tests/ -name 'test_*.py' -o -name '*_test.py' 2>/dev/null)" ]; then
75+
pytest tests/ -v --no-header
76+
else
77+
echo "No unit tests found in tests/, skipping..."
78+
fi
79+
80+
security:
81+
name: Security (pip-audit on Ubuntu)
82+
runs-on: ubuntu-latest
83+
steps:
84+
- name: Checkout
85+
uses: actions/checkout@v4
86+
with:
87+
submodules: recursive
88+
89+
- name: Set up Python
90+
uses: actions/setup-python@v5
91+
with:
92+
python-version: '3.11'
93+
cache: 'pip'
94+
95+
- name: Install dependencies
96+
run: |
97+
python -m pip install --upgrade pip
98+
pip install -e ./gts
99+
pip install pip-audit
100+
101+
# Run security audit but do not fail CI (as requested).
102+
- name: pip-audit
103+
run: pip-audit
104+
continue-on-error: true
105+
106+
coverage:
107+
name: Code Coverage (pytest-cov)
108+
runs-on: ubuntu-latest
109+
steps:
110+
- name: Checkout
111+
uses: actions/checkout@v4
112+
with:
113+
submodules: recursive
114+
115+
- name: Set up Python
116+
uses: actions/setup-python@v5
117+
with:
118+
python-version: '3.11'
119+
cache: 'pip'
120+
121+
- name: Install dependencies
122+
run: |
123+
python -m pip install --upgrade pip
124+
pip install -e ./gts
125+
pip install pytest pytest-cov
126+
127+
# Generate coverage report (skip if no tests exist)
128+
- name: Coverage
129+
run: |
130+
if [ -n "$(find tests/ -name 'test_*.py' -o -name '*_test.py' 2>/dev/null)" ]; then
131+
pytest tests/ --cov=gts --cov-report=xml --cov-report=term
132+
else
133+
echo "No unit tests found in tests/, skipping coverage..."
134+
fi
135+
136+
# Upload to Codecov; do not fail CI if Codecov is down/misconfigured.
137+
- name: Upload to Codecov
138+
uses: codecov/codecov-action@v4
139+
with:
140+
files: coverage.xml
141+
fail_ci_if_error: false
142+
# token: ${{ secrets.CODECOV_TOKEN }} # Uncomment if required for private repos
143+
144+
e2e:
145+
name: E2E Tests (gts-spec)
146+
runs-on: ubuntu-latest
147+
env:
148+
PYTHONDONTWRITEBYTECODE: 1
149+
steps:
150+
- name: Checkout
151+
uses: actions/checkout@v4
152+
with:
153+
submodules: recursive
154+
155+
- name: Set up Python
156+
uses: actions/setup-python@v5
157+
with:
158+
python-version: '3.11'
159+
cache: 'pip'
160+
161+
- name: Install dependencies
162+
run: |
163+
python -m pip install --upgrade pip
164+
# Install httprunner first to get pydantic<1.9 constraint
165+
pip install httprunner pytest requests
166+
# Then install gts (will use already-installed pydantic v1)
167+
pip install -e ./gts
168+
169+
- name: Run e2e tests
170+
run: |
171+
# Start server in background with logs
172+
gts server --port 8000 > .server.log 2>&1 &
173+
SERVER_PID=$!
174+
echo "Started GTS server with PID $SERVER_PID"
175+
176+
# Wait for server to be ready
177+
echo "Waiting for GTS server to start..."
178+
for i in $(seq 1 30); do
179+
if ! kill -0 $SERVER_PID 2>/dev/null; then
180+
echo "ERROR: Server process died unexpectedly"
181+
echo "=== Server logs ==="
182+
cat .server.log || true
183+
exit 1
184+
fi
185+
if curl -sf http://127.0.0.1:8000/entities > /dev/null 2>&1; then
186+
echo "GTS server is ready!"
187+
break
188+
fi
189+
if [ $i -eq 30 ]; then
190+
echo "ERROR: GTS server failed to start within 30 seconds"
191+
echo "=== Server logs ==="
192+
cat .server.log || true
193+
kill $SERVER_PID 2>/dev/null || true
194+
exit 1
195+
fi
196+
echo "Attempt $i/30: Server not ready yet, waiting..."
197+
sleep 1
198+
done
199+
200+
# Run tests
201+
pytest -p no:cacheprovider ./.gts-spec/tests -v
202+
TEST_EXIT=$?
203+
204+
# Stop server
205+
echo "Stopping GTS server..."
206+
kill $SERVER_PID 2>/dev/null || true
207+
wait $SERVER_PID 2>/dev/null || true
208+
209+
exit $TEST_EXIT

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule ".gts-spec"]
2+
path = .gts-spec
3+
url = https://github.com/GlobalTypeSystem/gts-spec.git

.gts-spec

Submodule .gts-spec added at 5e17b3a

Makefile

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
CI := 1
2+
3+
.PHONY: help build dev-fmt all check fmt lint mypy test security update-spec e2e coverage
4+
5+
# Default target - show help
6+
.DEFAULT_GOAL := help
7+
8+
# Show this help message
9+
help:
10+
@awk '/^# / { desc=substr($$0, 3) } /^[a-zA-Z0-9_-]+:/ && desc { target=$$1; sub(/:$$/, "", target); printf "%-20s - %s\n", target, desc; desc="" }' Makefile | sort
11+
12+
# Build/install the package in development mode
13+
build:
14+
pip install -e ./gts
15+
16+
# Fix formatting issues
17+
dev-fmt:
18+
ruff format gts/src
19+
20+
# Run all checks and build
21+
all: check build
22+
23+
# Check code formatting
24+
fmt:
25+
ruff format --check gts/src
26+
27+
# Run linter (ruff)
28+
lint:
29+
ruff check gts/src
30+
31+
# Run clippy-equivalent linter with auto-fix
32+
clippy:
33+
ruff check --fix gts/src
34+
35+
# Run type checker
36+
mypy:
37+
mypy gts/src/gts --ignore-missing-imports
38+
39+
# Run all tests
40+
test:
41+
pytest tests/ -v
42+
43+
# Check dependencies for security vulnerabilities
44+
security:
45+
@command -v pip-audit >/dev/null || (echo "Installing pip-audit..." && pip install pip-audit)
46+
pip-audit
47+
48+
# Measure code coverage
49+
coverage:
50+
pytest tests/ --cov=gts --cov-report=xml --cov-report=term
51+
52+
# Update gts-spec submodule to latest
53+
update-spec:
54+
git submodule update --remote .gts-spec
55+
56+
# Run end-to-end tests against gts-spec
57+
e2e: build
58+
@echo "Starting server in background..."
59+
@python -m gts server --port 8000 & echo $$! > .server.pid
60+
@sleep 2
61+
@echo "Running e2e tests..."
62+
@PYTHONDONTWRITEBYTECODE=1 pytest -p no:cacheprovider --log-file=e2e.log ./.gts-spec/tests || (kill `cat .server.pid` 2>/dev/null; rm -f .server.pid; exit 1)
63+
@echo "Stopping server..."
64+
@kill `cat .server.pid` 2>/dev/null || true
65+
@rm -f .server.pid
66+
@echo "E2E tests completed successfully"
67+
68+
# Run all quality checks
69+
check: fmt lint test e2e

gts/src/gts/__main__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
"""
2+
Entry point for running gts as a module: python -m gts
3+
"""
4+
5+
from gts.cli import main
6+
7+
if __name__ == "__main__":
8+
main()

0 commit comments

Comments
 (0)