Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions helpers/devcontainer_lookup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from dataclasses import dataclass
from typing import Any, Callable, Mapping, Optional, Tuple


@dataclass(frozen=True)
class DevcontainerLookupResult:
devcontainer_json: str
generated: bool
source: str
url: Optional[str]
repo_context: Optional[str] = None
devcontainer_url: Optional[str] = None
should_save: bool = False


def resolve_devcontainer_lookup(
repo_url: str,
regenerate: bool,
instructor_client: Any,
check_url_exists: Callable[[str], Tuple[bool, Optional[Mapping[str, Any]]]],
fetch_repo_context: Callable[[str], Tuple[str, Optional[str], Optional[str]]],
generate_devcontainer_json: Callable[..., Tuple[str, Optional[str]]],
) -> DevcontainerLookupResult:
exists, existing_record = check_url_exists(repo_url)

if exists and existing_record and not regenerate:
return DevcontainerLookupResult(
devcontainer_json=existing_record["devcontainer_json"],
generated=existing_record["generated"],
source="database",
url=existing_record["devcontainer_url"],
)

repo_context, _existing_devcontainer, devcontainer_url = fetch_repo_context(repo_url)
devcontainer_json, url = generate_devcontainer_json(
instructor_client,
repo_url,
repo_context,
devcontainer_url,
regenerate=regenerate,
)

return DevcontainerLookupResult(
devcontainer_json=devcontainer_json,
generated=True,
source="generated" if url is None else "repository",
url=url,
repo_context=repo_context,
devcontainer_url=devcontainer_url,
should_save=True,
)
35 changes: 19 additions & 16 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from helpers.openai_helpers import setup_azure_openai, setup_instructor
from helpers.github_helpers import fetch_repo_context, check_url_exists
from helpers.devcontainer_lookup import resolve_devcontainer_lookup
from helpers.devcontainer_helpers import generate_devcontainer_json, validate_devcontainer_json
from helpers.token_helpers import count_tokens, truncate_to_token_limit
from models import DevContainer
Expand Down Expand Up @@ -109,26 +110,28 @@ async def post(repo_url: str, regenerate: bool = False):
repo_url = repo_url.rstrip('/')

try:
exists, existing_record = check_url_exists(repo_url)
logging.info(f"URL check result: exists={exists}, existing_record={existing_record}")

repo_context, existing_devcontainer, devcontainer_url = fetch_repo_context(repo_url)
logging.info(f"Fetched repo context. Existing devcontainer: {'Yes' if existing_devcontainer else 'No'}")
logging.info(f"Devcontainer URL: {devcontainer_url}")
lookup_result = resolve_devcontainer_lookup(
repo_url=repo_url,
regenerate=regenerate,
instructor_client=globals().get("instructor_client"),
check_url_exists=check_url_exists,
fetch_repo_context=fetch_repo_context,
generate_devcontainer_json=generate_devcontainer_json,
)

if exists and not regenerate:
if lookup_result.source == "database":
logging.info(f"URL already exists in database. Returning existing devcontainer_json for: {repo_url}")
devcontainer_json = existing_record['devcontainer_json']
generated = existing_record['generated']
source = "database"
url = existing_record['devcontainer_url']
else:
devcontainer_json, url = generate_devcontainer_json(instructor_client, repo_url, repo_context, devcontainer_url, regenerate=regenerate)
generated = True
source = "generated" if url is None else "repository"
logging.info(f"Fetched repo context. Devcontainer URL: {lookup_result.devcontainer_url}")

devcontainer_json = lookup_result.devcontainer_json
generated = lookup_result.generated
source = lookup_result.source
url = lookup_result.url
repo_context = lookup_result.repo_context
devcontainer_url = lookup_result.devcontainer_url

if not exists or regenerate:
if lookup_result.should_save:
logging.info("Saving to database...")
try:
if hasattr(openai_client.embeddings, "create"):
Expand Down Expand Up @@ -207,4 +210,4 @@ async def get(fname:str, ext:str):

if __name__ == "__main__":
logging.info("Starting FastHTML app...")
serve()
serve()
118 changes: 118 additions & 0 deletions tests/test_devcontainer_lookup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import unittest

from helpers.devcontainer_lookup import resolve_devcontainer_lookup


class ResolveDevcontainerLookupTests(unittest.TestCase):
def test_cached_database_record_skips_repo_fetch_and_generation(self):
calls = {"lookup": 0, "fetch": 0, "generate": 0}
record = {
"devcontainer_json": '{"name": "cached"}',
"generated": True,
"devcontainer_url": "https://example.com/devcontainer.json",
}

def check_url_exists(url):
calls["lookup"] += 1
return True, record

def fetch_repo_context(url):
calls["fetch"] += 1
raise AssertionError("fetch_repo_context should not run for cache hits")

def generate_devcontainer_json(*args, **kwargs):
calls["generate"] += 1
raise AssertionError("generate_devcontainer_json should not run for cache hits")

result = resolve_devcontainer_lookup(
"https://github.com/example/project",
regenerate=False,
instructor_client=object(),
check_url_exists=check_url_exists,
fetch_repo_context=fetch_repo_context,
generate_devcontainer_json=generate_devcontainer_json,
)

self.assertEqual(result.devcontainer_json, record["devcontainer_json"])
self.assertTrue(result.generated)
self.assertEqual(result.source, "database")
self.assertEqual(result.url, record["devcontainer_url"])
self.assertFalse(result.should_save)
self.assertEqual(calls, {"lookup": 1, "fetch": 0, "generate": 0})

def test_missing_record_fetches_and_generates_devcontainer(self):
calls = {"lookup": 0, "fetch": 0, "generate": 0}

def check_url_exists(url):
calls["lookup"] += 1
return False, None

def fetch_repo_context(url):
calls["fetch"] += 1
return "repo context", None, None

def generate_devcontainer_json(
client, url, repo_context, devcontainer_url, regenerate=False
):
calls["generate"] += 1
return '{"name": "generated"}', None

result = resolve_devcontainer_lookup(
"https://github.com/example/project",
regenerate=False,
instructor_client=object(),
check_url_exists=check_url_exists,
fetch_repo_context=fetch_repo_context,
generate_devcontainer_json=generate_devcontainer_json,
)

self.assertEqual(result.devcontainer_json, '{"name": "generated"}')
self.assertEqual(result.source, "generated")
self.assertTrue(result.generated)
self.assertTrue(result.should_save)
self.assertEqual(result.repo_context, "repo context")
self.assertIsNone(result.devcontainer_url)
self.assertEqual(calls, {"lookup": 1, "fetch": 1, "generate": 1})

def test_regenerate_ignores_cached_record_and_refreshes_context(self):
calls = {"lookup": 0, "fetch": 0, "generate": 0}
record = {
"devcontainer_json": '{"name": "cached"}',
"generated": True,
"devcontainer_url": "https://example.com/devcontainer.json",
}

def check_url_exists(url):
calls["lookup"] += 1
return True, record

def fetch_repo_context(url):
calls["fetch"] += 1
return "repo context", None, "https://example.com/source-devcontainer.json"

def generate_devcontainer_json(
client, url, repo_context, devcontainer_url, regenerate=False
):
calls["generate"] += 1
self.assertTrue(regenerate)
return '{"name": "regenerated"}', None

result = resolve_devcontainer_lookup(
"https://github.com/example/project",
regenerate=True,
instructor_client=object(),
check_url_exists=check_url_exists,
fetch_repo_context=fetch_repo_context,
generate_devcontainer_json=generate_devcontainer_json,
)

self.assertEqual(result.devcontainer_json, '{"name": "regenerated"}')
self.assertEqual(result.source, "generated")
self.assertTrue(result.generated)
self.assertTrue(result.should_save)
self.assertEqual(result.devcontainer_url, "https://example.com/source-devcontainer.json")
self.assertEqual(calls, {"lookup": 1, "fetch": 1, "generate": 1})


if __name__ == "__main__":
unittest.main()