From dfd9cb303e16f0c3a5ae03a884124d48b90d16f9 Mon Sep 17 00:00:00 2001 From: Scrum Master - Resolve AI Date: Wed, 22 Jul 2026 13:32:29 +0300 Subject: [PATCH] Add baseline CI/CD: typecheck, lint, and Docker image publish - CI workflow runs TypeScript typecheck (tsc --noEmit) and ruff lint on nlp-service for every push/PR to main. - Docker publish workflow builds and pushes server + nlp-service images to GHCR on push to main. - Add Dockerfiles for both services (verified building locally). - Fix pre-existing unused-import lint violations in nlp-service surfaced by adding ruff. Co-Authored-By: Paperclip --- .dockerignore | 6 +++ .github/workflows/ci.yml | 31 +++++++++++++ .github/workflows/docker-publish.yml | 65 ++++++++++++++++++++++++++++ Dockerfile | 13 ++++++ nlp-service/Dockerfile | 13 ++++++ nlp-service/main.py | 2 +- nlp-service/test_service.py | 4 +- package.json | 4 +- 8 files changed, 135 insertions(+), 3 deletions(-) create mode 100644 .dockerignore create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/docker-publish.yml create mode 100644 Dockerfile create mode 100644 nlp-service/Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..b24d90f --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +node_modules +.git +.vscode +nlp-service +*.log +.env diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d5ffc5e --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,31 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + typecheck: + name: TypeScript typecheck (src/) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + - run: npm ci + - run: npm test + + python-lint: + name: Python lint (nlp-service) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + - run: pip install ruff + - run: ruff check nlp-service diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 0000000..02aeed8 --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,65 @@ +name: Build & Publish Docker Images + +on: + push: + branches: [main] + workflow_dispatch: + +env: + REGISTRY: ghcr.io + +jobs: + build-server: + name: Build server image + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - uses: actions/checkout@v4 + - name: Compute lowercase image name + id: image + run: echo "name=${REGISTRY}/${GITHUB_REPOSITORY,,}/server" >> "$GITHUB_OUTPUT" + env: + REGISTRY: ${{ env.REGISTRY }} + - uses: docker/setup-buildx-action@v3 + - uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile + push: true + tags: | + ${{ steps.image.outputs.name }}:latest + ${{ steps.image.outputs.name }}:${{ github.sha }} + + build-nlp-service: + name: Build nlp-service image + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - uses: actions/checkout@v4 + - name: Compute lowercase image name + id: image + run: echo "name=${REGISTRY}/${GITHUB_REPOSITORY,,}/nlp-service" >> "$GITHUB_OUTPUT" + env: + REGISTRY: ${{ env.REGISTRY }} + - uses: docker/setup-buildx-action@v3 + - uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - uses: docker/build-push-action@v6 + with: + context: ./nlp-service + push: true + tags: | + ${{ steps.image.outputs.name }}:latest + ${{ steps.image.outputs.name }}:${{ github.sha }} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..be15a9d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM node:20-slim + +WORKDIR /app + +COPY package.json package-lock.json ./ +RUN npm ci + +COPY . . + +ENV PORT=3000 +EXPOSE 3000 + +CMD ["npm", "start"] diff --git a/nlp-service/Dockerfile b/nlp-service/Dockerfile new file mode 100644 index 0000000..7696883 --- /dev/null +++ b/nlp-service/Dockerfile @@ -0,0 +1,13 @@ +FROM python:3.11-slim + +WORKDIR /app + +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +COPY . . + +ENV PORT=8000 +EXPOSE 8000 + +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/nlp-service/main.py b/nlp-service/main.py index 1b5b4e9..f81f218 100644 --- a/nlp-service/main.py +++ b/nlp-service/main.py @@ -4,7 +4,7 @@ from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from pydantic import BaseModel -from typing import Optional, List +from typing import Optional load_dotenv(dotenv_path=os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", ".env")) diff --git a/nlp-service/test_service.py b/nlp-service/test_service.py index 6e569a5..2a37b5e 100644 --- a/nlp-service/test_service.py +++ b/nlp-service/test_service.py @@ -1,4 +1,6 @@ -import sys, os, json, traceback, importlib.util +import os +import traceback +import importlib.util import spacy nlp_spacy = spacy.load("xx_ent_wiki_sm") diff --git a/package.json b/package.json index 3922264..1ac5e10 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,9 @@ "nlp-service": "python nlp-service/main.py", "start-all": "start /B python nlp-service/main.py > nul 2>&1 & timeout /T 10 /NOBREAK >nul & tsx server.ts", "seed": "npx tsx src/seed.ts", - "demo": "npx tsx src/demo.ts" + "demo": "npx tsx src/demo.ts", + "typecheck": "tsc --noEmit", + "test": "npm run typecheck" }, "dependencies": { "@fission-ai/openspec": "^1.1.1",