Add Gitea Actions CI/CD and fix trailing slash routing
Build and Push Docker Image / test (push) Failing after 1m5s Details
Build and Push Docker Image / build (push) Has been skipped Details

- Add .gitea/workflows/build.yml for automated builds
- Run tests before building Docker image
- Push to code.letsbe.solutions/letsbe/orchestrator:latest
- Add middleware to normalize trailing slashes in URLs
- Standardize route definitions to use "" instead of "/"

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Matt 2025-12-08 12:37:28 +01:00
parent 7ecc0496f5
commit 42c682c579
5 changed files with 90 additions and 5 deletions

View File

@ -0,0 +1,76 @@
name: Build and Push Docker Image
on:
push:
branches:
- main
- master
tags:
- 'v*'
pull_request:
branches:
- main
- master
env:
REGISTRY: code.letsbe.solutions
IMAGE_NAME: letsbe/orchestrator
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install pytest pytest-asyncio aiosqlite
- name: Run tests
run: pytest -v --tb=short
build:
runs-on: ubuntu-latest
needs: test
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Gitea Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ gitea.actor }}
password: ${{ secrets.REGISTRY_TOKEN }}
- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View File

@ -59,6 +59,15 @@ app = FastAPI(
lifespan=lifespan, lifespan=lifespan,
) )
@app.middleware("http")
async def normalize_trailing_slashes(request: Request, call_next):
"""Strip trailing slashes from URLs to normalize routing."""
if request.url.path != "/" and request.url.path.endswith("/"):
# Modify the scope to remove trailing slash
request.scope["path"] = request.url.path.rstrip("/")
return await call_next(request)
# Add middleware # Add middleware
app.add_middleware(RequestIDMiddleware) app.add_middleware(RequestIDMiddleware)

View File

@ -111,7 +111,7 @@ async def validate_agent_token(
@router.get( @router.get(
"/", "",
response_model=list[AgentResponse], response_model=list[AgentResponse],
summary="List all agents", summary="List all agents",
description="Retrieve all registered agents, optionally filtered by tenant.", description="Retrieve all registered agents, optionally filtered by tenant.",

View File

@ -74,7 +74,7 @@ async def update_task(
# --- Route handlers (thin controllers) --- # --- Route handlers (thin controllers) ---
@router.post("/", response_model=TaskResponse, status_code=status.HTTP_201_CREATED) @router.post("", response_model=TaskResponse, status_code=status.HTTP_201_CREATED)
async def create_task_endpoint( async def create_task_endpoint(
task_in: TaskCreate, task_in: TaskCreate,
db: AsyncSessionDep, db: AsyncSessionDep,
@ -131,7 +131,7 @@ async def create_task_endpoint(
return await create_task(db, task_in) return await create_task(db, task_in)
@router.get("/", response_model=list[TaskResponse]) @router.get("", response_model=list[TaskResponse])
async def list_tasks_endpoint( async def list_tasks_endpoint(
db: AsyncSessionDep, db: AsyncSessionDep,
tenant_id: uuid.UUID | None = Query(None, description="Filter by tenant ID"), tenant_id: uuid.UUID | None = Query(None, description="Filter by tenant ID"),

View File

@ -42,7 +42,7 @@ async def get_tenant_by_id(db: AsyncSessionDep, tenant_id: uuid.UUID) -> Tenant
# --- Route handlers (thin controllers) --- # --- Route handlers (thin controllers) ---
@router.post("/", response_model=TenantResponse, status_code=status.HTTP_201_CREATED) @router.post("", response_model=TenantResponse, status_code=status.HTTP_201_CREATED)
async def create_tenant_endpoint( async def create_tenant_endpoint(
tenant_in: TenantCreate, tenant_in: TenantCreate,
db: AsyncSessionDep, db: AsyncSessionDep,
@ -56,7 +56,7 @@ async def create_tenant_endpoint(
return await create_tenant(db, tenant_in) return await create_tenant(db, tenant_in)
@router.get("/", response_model=list[TenantResponse]) @router.get("", response_model=list[TenantResponse])
async def list_tenants_endpoint(db: AsyncSessionDep) -> list[Tenant]: async def list_tenants_endpoint(db: AsyncSessionDep) -> list[Tenant]:
""" """
List all tenants. List all tenants.