diff --git a/.github/workflows/aws-preview.yml b/.github/workflows/aws-preview.yml index 46b6cae8..0526abba 100644 --- a/.github/workflows/aws-preview.yml +++ b/.github/workflows/aws-preview.yml @@ -1,13 +1,10 @@ name: Deploy Backend to Preview ECS on: - pull_request: - branches: [ "main" ] - paths: - - .github/workflows/aws-preview.yml - - server/** - - petercat_utils/** - - subscriber/** + workflow_run: + workflows: ["Build And Test"] + types: + - completed env: AWS_REGION: ap-northeast-1 diff --git a/.github/workflows/server-test.yml b/.github/workflows/server-test.yml new file mode 100644 index 00000000..13123ad9 --- /dev/null +++ b/.github/workflows/server-test.yml @@ -0,0 +1,38 @@ +name: Build And Test + +on: + pull_request: + branches: [ "main" ] + paths: + - .github/workflows/aws-preview.yml + - server/** + - petercat_utils/** + - subscriber/** + +jobs: + build: + runs-on: ubuntu-latest + environment: production + strategy: + fail-fast: true + + steps: + - name: Checkout + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + run: | + cd server + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + + - name: Test with pytest + run: | + pip install pytest pytest-cov + pytest \ No newline at end of file diff --git a/client/tests/github/pull_request_test.py b/client/tests/github/pull_request_test.py deleted file mode 100644 index d60b0e69..00000000 --- a/client/tests/github/pull_request_test.py +++ /dev/null @@ -1,13 +0,0 @@ -import pytest -import json -import os - -from server.event_handler.pull_request import PullRequestEventHandler - -def test_event_handler(): - filepath = os.path.join(os.path.dirname(__file__), 'pull_request_event.json') - with open(filepath) as ev: - event = json.load(ev) - handler = PullRequestEventHandler(payload = event, access_token="123") - result = handler.execute() - assert result["success"] == True diff --git a/server/agent/bot_builder.py b/server/agent/bot_builder.py index fbeb9b76..a7b94598 100644 --- a/server/agent/bot_builder.py +++ b/server/agent/bot_builder.py @@ -1,8 +1,9 @@ from typing import AsyncIterator, Optional from petercat_utils.data_class import ChatData -from agent.base import AgentBuilder -from prompts.bot_builder import generate_prompt_by_user_id -from tools import bot_builder + +from ..agent.base import AgentBuilder +from ..prompts.bot_builder import generate_prompt_by_user_id +from ..tools import bot_builder TOOL_MAPPING = { diff --git a/server/agent/qa_chat.py b/server/agent/qa_chat.py index c55ba53b..52717a72 100644 --- a/server/agent/qa_chat.py +++ b/server/agent/qa_chat.py @@ -1,9 +1,10 @@ from typing import AsyncIterator, Optional -from agent.base import AgentBuilder -from prompts.bot_template import generate_prompt_by_repo_name from petercat_utils import get_client from petercat_utils.data_class import ChatData -from tools import issue, sourcecode, knowledge, git_info + +from ..agent.base import AgentBuilder +from ..prompts.bot_template import generate_prompt_by_repo_name +from ..tools import issue, sourcecode, knowledge, git_info def get_tools(bot_id: str, token: Optional[str]): diff --git a/server/bot/builder.py b/server/bot/builder.py index 075e2776..6c270835 100644 --- a/server/bot/builder.py +++ b/server/bot/builder.py @@ -4,7 +4,8 @@ from petercat_utils import get_client from petercat_utils.data_class import RAGGitDocConfig from petercat_utils import git_doc_task -from prompts.bot_template import generate_prompt_by_repo_name + +from ..prompts.bot_template import generate_prompt_by_repo_name g = Github() diff --git a/server/dao/authorizationDAO.py b/server/dao/authorizationDAO.py index 90dbe98f..44f752ef 100644 --- a/server/dao/authorizationDAO.py +++ b/server/dao/authorizationDAO.py @@ -1,11 +1,10 @@ - -import json -from dao.BaseDAO import BaseDAO -from models.authorization import Authorization -from supabase.client import Client, create_client +from supabase.client import Client from petercat_utils.db.client.supabase import get_client +from ..dao.BaseDAO import BaseDAO +from ..models.authorization import Authorization + class AuthorizationDAO(BaseDAO): client: Client diff --git a/server/dao/repositoryConfigDAO.py b/server/dao/repositoryConfigDAO.py index c292a296..89cc1372 100644 --- a/server/dao/repositoryConfigDAO.py +++ b/server/dao/repositoryConfigDAO.py @@ -1,11 +1,8 @@ - -import json -from dao.BaseDAO import BaseDAO -from models.repository import RepositoryConfig -from supabase.client import Client, create_client - +from supabase.client import Client from petercat_utils.db.client.supabase import get_client +from ..dao.BaseDAO import BaseDAO +from ..models.repository import RepositoryConfig class RepositoryConfigDAO(BaseDAO): client: Client diff --git a/server/event_handler/discussion.py b/server/event_handler/discussion.py index f5061d63..c13f43fd 100644 --- a/server/event_handler/discussion.py +++ b/server/event_handler/discussion.py @@ -2,10 +2,11 @@ from typing import Any from github import Github, Auth from github import GithubException -from agent.qa_chat import agent_chat from petercat_utils.data_class import ChatData, Message, TextContentBlock +from ..agent.qa_chat import agent_chat + class DiscussionEventHandler: event: Any diff --git a/server/event_handler/issue.py b/server/event_handler/issue.py index 84d6b431..3db2b954 100644 --- a/server/event_handler/issue.py +++ b/server/event_handler/issue.py @@ -1,10 +1,11 @@ from typing import Any from github import Github, Auth from github import GithubException -from agent.qa_chat import agent_chat from petercat_utils.data_class import ChatData, Message, TextContentBlock +from ..agent.qa_chat import agent_chat + class IssueEventHandler: event: Any diff --git a/server/main.py b/server/main.py index fb151903..90beb75d 100644 --- a/server/main.py +++ b/server/main.py @@ -9,7 +9,8 @@ # Import fastapi routers -from routers import bot, health_checker, github, rag, auth, chat, task +from .routers import bot, health_checker, github, rag, auth, chat, task + AUTH0_DOMAIN = get_env_variable("AUTH0_DOMAIN") API_AUDIENCE = get_env_variable("API_IDENTIFIER") CLIENT_ID = get_env_variable("AUTH0_CLIENT_ID") @@ -50,8 +51,8 @@ app.include_router(task.router) -if __name__ == "__main__": - if is_dev: - uvicorn.run("main:app", host="0.0.0.0", port=int(os.environ.get("PORT", "8080")), reload=True) - else: - uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT", "8080"))) +# if __name__ == "__main__": +# if is_dev: +# uvicorn.run("main:app", host="0.0.0.0", port=int(os.environ.get("PORT", "8080")), reload=True) +# else: +# uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT", "8080"))) diff --git a/server/pytest.ini b/server/pytest.ini index 94a50dc0..7c1d8c1a 100644 --- a/server/pytest.ini +++ b/server/pytest.ini @@ -1,3 +1,5 @@ [pytest] -testpaths = tests -python_files = test_*.py \ No newline at end of file +testpaths = . +python_files = test_*.py +cov=com +cov-report=xml,html diff --git a/server/routers/auth.py b/server/routers/auth.py index 770c4647..d0ce0a26 100644 --- a/server/routers/auth.py +++ b/server/routers/auth.py @@ -1,11 +1,10 @@ from typing import Annotated from fastapi import APIRouter, Cookie, Request, HTTPException, status, Response - from fastapi.responses import RedirectResponse import httpx - from petercat_utils import get_client, get_env_variable -from auth.get_user_info import generateAnonymousUser, getAnonymousUserInfoByToken, getUserAccessToken, getUserInfoByToken + +from ..auth.get_user_info import generateAnonymousUser, getAnonymousUserInfoByToken, getUserInfoByToken AUTH0_DOMAIN = get_env_variable("AUTH0_DOMAIN") diff --git a/server/routers/bot.py b/server/routers/bot.py index 755ecb58..f674994a 100644 --- a/server/routers/bot.py +++ b/server/routers/bot.py @@ -1,11 +1,12 @@ from fastapi import APIRouter, Depends, status, Query, Path from fastapi.responses import JSONResponse -from auth.get_user_info import get_user_id from petercat_utils import get_client -from bot.builder import bot_builder, bot_info_generator -from type_class.bot import BotUpdateRequest, BotCreateRequest from typing import Annotated, Optional +from ..auth.get_user_info import get_user_id +from ..bot.builder import bot_builder, bot_info_generator +from ..type_class.bot import BotUpdateRequest, BotCreateRequest + router = APIRouter( prefix="/api/bot", tags=["bot"], diff --git a/server/routers/chat.py b/server/routers/chat.py index 0baaf94b..5ebd0114 100644 --- a/server/routers/chat.py +++ b/server/routers/chat.py @@ -1,11 +1,11 @@ -import asyncio from typing import Annotated, Optional -from fastapi import APIRouter, Cookie, Depends +from fastapi import APIRouter, Depends from fastapi.responses import StreamingResponse -from auth.get_user_info import get_user_access_token, get_user_id from petercat_utils.data_class import ChatData -from agent import qa_chat, bot_builder -from verify.rate_limit import verify_rate_limit + +from ..agent import qa_chat, bot_builder +from ..verify.rate_limit import verify_rate_limit +from ..auth.get_user_info import get_user_access_token, get_user_id router = APIRouter( diff --git a/server/routers/github.py b/server/routers/github.py index cae15870..79349885 100644 --- a/server/routers/github.py +++ b/server/routers/github.py @@ -4,16 +4,18 @@ from fastapi.responses import RedirectResponse import requests import time -from github import Auth, Github, Organization -from auth.get_user_info import get_user_access_token -from dao.authorizationDAO import AuthorizationDAO -from dao.repositoryConfigDAO import RepositoryConfigDAO -from models.repository import RepositoryConfig -from models.authorization import Authorization -from utils.github import get_handler, get_private_key +from github import Auth, Github + from petercat_utils import get_env_variable from jwt import JWT, jwk_from_pem +from ..auth.get_user_info import get_user_access_token +from ..dao.authorizationDAO import AuthorizationDAO +from ..dao.repositoryConfigDAO import RepositoryConfigDAO +from ..models.repository import RepositoryConfig +from ..models.authorization import Authorization +from ..utils.github import get_handler, get_private_key + APP_ID = get_env_variable("X_GITHUB_APP_ID") WEB_URL = get_env_variable("WEB_URL") diff --git a/server/routers/health_checker.py b/server/routers/health_checker.py index 4b8ca9a2..cfd90517 100644 --- a/server/routers/health_checker.py +++ b/server/routers/health_checker.py @@ -1,6 +1,4 @@ -from fastapi import APIRouter, Depends - -from verify.rate_limit import verify_rate_limit +from fastapi import APIRouter router = APIRouter( prefix="/api", @@ -11,7 +9,3 @@ @router.get("/health_checker") def health_checker(): return { "Hello": "World" } - -@router.get("/login_checker", dependencies=[Depends(verify_rate_limit)]) -def login_checker(): - return { "Hello": "World" } \ No newline at end of file diff --git a/server/routers/rag.py b/server/routers/rag.py index 1806d1f4..04fe4510 100644 --- a/server/routers/rag.py +++ b/server/routers/rag.py @@ -3,7 +3,6 @@ from fastapi import APIRouter, Depends from petercat_utils.db.client.supabase import get_client -from verify.rate_limit import verify_rate_limit from petercat_utils.data_class import RAGGitDocConfig, RAGGitIssueConfig, TaskType from petercat_utils.rag_helper import ( @@ -14,6 +13,9 @@ git_issue_task, ) +from ..verify.rate_limit import verify_rate_limit + + router = APIRouter( prefix="/api", tags=["rag"], diff --git a/server/test_main.py b/server/test_main.py new file mode 100644 index 00000000..9f3561cf --- /dev/null +++ b/server/test_main.py @@ -0,0 +1,9 @@ +from fastapi.testclient import TestClient +from .main import app + +client = TestClient(app) + +def test_health_checker(): + response = client.get("/api/health_checker") + assert response.status_code == 200 + assert response.json() == { "Hello": "World" } diff --git a/server/tools/bot_builder.py b/server/tools/bot_builder.py index d4ec5dcb..3b86dd4c 100644 --- a/server/tools/bot_builder.py +++ b/server/tools/bot_builder.py @@ -4,7 +4,8 @@ from langchain.tools import tool from github import Github from petercat_utils import get_client -from bot.builder import bot_builder + +from ..bot.builder import bot_builder g = Github() diff --git a/server/tools/issue.py b/server/tools/issue.py index 4e44e09a..b937cbc2 100644 --- a/server/tools/issue.py +++ b/server/tools/issue.py @@ -3,7 +3,7 @@ from github import Auth, Github from langchain.tools import tool -from tools.helper import need_github_login +from ..tools.helper import need_github_login DEFAULT_REPO_NAME = "ant-design/ant-design" diff --git a/server/utils/github.py b/server/utils/github.py index cee13286..ce2df27e 100644 --- a/server/utils/github.py +++ b/server/utils/github.py @@ -1,12 +1,12 @@ from typing import Union import boto3 from botocore.exceptions import ClientError -from event_handler.pull_request import PullRequestEventHandler -from event_handler.discussion import DiscussionEventHandler -from event_handler.issue import IssueEventHandler from petercat_utils import get_env_variable from github import Auth +from ..event_handler.pull_request import PullRequestEventHandler +from ..event_handler.discussion import DiscussionEventHandler +from ..event_handler.issue import IssueEventHandler APP_ID = get_env_variable("X_GITHUB_APP_ID") diff --git a/server/verify/rate_limit.py b/server/verify/rate_limit.py index 2a49e826..14db30f6 100644 --- a/server/verify/rate_limit.py +++ b/server/verify/rate_limit.py @@ -2,9 +2,10 @@ from fastapi import Cookie, HTTPException from datetime import datetime, timedelta -from auth.get_user_info import getUserInfoByToken from petercat_utils import get_client, get_env_variable +from ..auth.get_user_info import getUserInfoByToken + RATE_LIMIT_ENABLED = get_env_variable("RATE_LIMIT_ENABLED", "False") == 'True' RATE_LIMIT_REQUESTS = get_env_variable("RATE_LIMIT_REQUESTS") or 100 RATE_LIMIT_DURATION = timedelta(minutes=int(get_env_variable("RATE_LIMIT_DURATION") or 1))