From 45c4b4b16754c46f5e46c498be71740deb965923 Mon Sep 17 00:00:00 2001 From: Ashir Rao <69091220+Ash1R@users.noreply.github.com> Date: Tue, 22 Jul 2025 16:06:34 -0700 Subject: [PATCH 1/4] fic caching issue. and change deploy order --- polyapi/deployables.py | 31 ++++++++++++++----------------- polyapi/sync.py | 2 +- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/polyapi/deployables.py b/polyapi/deployables.py index 55dbbd7..dfaceda 100644 --- a/polyapi/deployables.py +++ b/polyapi/deployables.py @@ -191,20 +191,27 @@ def write_cache_revision(git_revision: Optional[str] = None) -> None: with open(CACHE_VERSION_FILE, 'w', encoding='utf-8') as file: file.write(git_revision) + def is_cache_up_to_date() -> bool: + """Check if the cached revision matches the current Git revision.""" if not Path(CACHE_VERSION_FILE).exists(): return False - with open(CACHE_VERSION_FILE, 'r', encoding='utf-8') as file: - cached_revision = file.read().strip() - git_revision = get_git_revision() - return cached_revision == git_revision -def is_cache_up_to_date() -> bool: - """Check if the cached revision matches the current Git revision.""" + # Check for uncommitted changes + try: + status = check_output(["git", "status", "--porcelain"], text=True).strip() + if status: + return False # Working directory is dirty, so cache is not up-to-date + except CalledProcessError: + # Not a git repository, or git is not installed. + # In this case, we can't rely on git for caching, so we assume not up-to-date. + return False + cached_revision = get_cache_deployments_revision() - git_revision = get_git_revision() # This function needs to be defined or imported + git_revision = get_git_revision() return cached_revision == git_revision + def write_deploy_comments(deployments: List[Dict]) -> str: """Generate a string of deployment comments for each deployment.""" canopy_path = 'polyui/collections' if 'localhost' in os.getenv('POLY_API_BASE_URL', '') else 'canopy/polyui/collections' @@ -288,13 +295,3 @@ def write_updated_deployable(deployable: dict, disable_docs: bool = False) -> di deployable['fileRevision'] = get_deployable_file_revision(file_contents) return deployable -def write_deploy_comments(deployments: list) -> str: - """ - Generate deployment comments for each deployment record. - """ - canopy_path = 'polyui/collections' if 'localhost' in os.getenv('POLY_API_BASE_URL', '') else 'canopy/polyui/collections' - comments = [] - for d in deployments: - instance_url = d['instance'].replace(':8000', ':3000') if d['instance'].endswith(':8000') else d['instance'] - comments.append(f"# Poly deployed @ {d['deployed']} - {d['context']}.{d['name']} - {instance_url}/{canopy_path}/{d['type']}s/{d['id']} - {d['fileRevision']}") - return "\n".join(comments) \ No newline at end of file diff --git a/polyapi/sync.py b/polyapi/sync.py index 921defa..ca684fc 100644 --- a/polyapi/sync.py +++ b/polyapi/sync.py @@ -15,8 +15,8 @@ ) DEPLOY_ORDER = [ - 'server-function', 'client-function', + 'server-function', ] def read_file(file_path: str) -> str: From 4c917a0aadd971a12dcb19c832fca36730760828 Mon Sep 17 00:00:00 2001 From: Ashir Rao <69091220+Ash1R@users.noreply.github.com> Date: Wed, 23 Jul 2025 10:22:37 -0700 Subject: [PATCH 2/4] no use of porcelain --- polyapi/deployables.py | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/polyapi/deployables.py b/polyapi/deployables.py index dfaceda..f7e52e7 100644 --- a/polyapi/deployables.py +++ b/polyapi/deployables.py @@ -196,31 +196,22 @@ def is_cache_up_to_date() -> bool: """Check if the cached revision matches the current Git revision.""" if not Path(CACHE_VERSION_FILE).exists(): return False - - # Check for uncommitted changes - try: - status = check_output(["git", "status", "--porcelain"], text=True).strip() - if status: - return False # Working directory is dirty, so cache is not up-to-date - except CalledProcessError: - # Not a git repository, or git is not installed. - # In this case, we can't rely on git for caching, so we assume not up-to-date. - return False - - cached_revision = get_cache_deployments_revision() + with open(CACHE_VERSION_FILE, 'r', encoding='utf-8') as file: + cached_revision = file.read().strip() git_revision = get_git_revision() return cached_revision == git_revision -def write_deploy_comments(deployments: List[Dict]) -> str: - """Generate a string of deployment comments for each deployment.""" +def write_deploy_comments(deployments: list) -> str: + """ + Generate deployment comments for each deployment record. + """ canopy_path = 'polyui/collections' if 'localhost' in os.getenv('POLY_API_BASE_URL', '') else 'canopy/polyui/collections' comments = [] for d in deployments: instance_url = d['instance'].replace(':8000', ':3000') if d['instance'].endswith(':8000') else d['instance'] - comment = f"# Poly deployed @ {d['deployed']} - {d['context']}.{d['name']} - {instance_url}/{canopy_path}/{d['type']}s/{d['id']} - {d['fileRevision']}" - comments.append(comment) - return '\n'.join(comments) + comments.append(f"# Poly deployed @ {d['deployed']} - {d['context']}.{d['name']} - {instance_url}/{canopy_path}/{d['type']}s/{d['id']} - {d['fileRevision']}") + return "\n".join(comments) def print_docstring_function_comment(description: str, args: list, returns: dict) -> str: docstring = f'"""{description}\n\n' From f1c55f3bcb2405783b0e8ea1924f64ae5ca9b1b9 Mon Sep 17 00:00:00 2001 From: Ashir Rao <69091220+Ash1R@users.noreply.github.com> Date: Wed, 23 Jul 2025 12:14:14 -0700 Subject: [PATCH 3/4] prevent import and deploy inline, add test --- polyapi/deployables.py | 9 ++++-- tests/test_deployables.py | 66 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/polyapi/deployables.py b/polyapi/deployables.py index f7e52e7..b498da8 100644 --- a/polyapi/deployables.py +++ b/polyapi/deployables.py @@ -245,8 +245,13 @@ def update_deployment_comments(file_content: str, deployable: dict) -> str: file_content = file_content[:range[0]] + file_content[range[1]:] if deployable['deployments']: deployment_comments = write_deploy_comments(deployable['deployments']) - deployable['deploymentCommentRanges'] = [(0, len(deployment_comments) + 1)] - file_content = f"{deployment_comments}\n{file_content}" + # Add blank line after deployment comments only if file content doesn't start with blank line + if file_content.startswith('\n'): + deployable['deploymentCommentRanges'] = [(0, len(deployment_comments) + 1)] + file_content = f"{deployment_comments}\n{file_content}" + else: + deployable['deploymentCommentRanges'] = [(0, len(deployment_comments) + 2)] + file_content = f"{deployment_comments}\n\n{file_content}" return file_content def update_deployable_function_comments(file_content: str, deployable: dict, disable_docs: bool = False) -> str: diff --git a/tests/test_deployables.py b/tests/test_deployables.py index 80ec742..9788f0b 100644 --- a/tests/test_deployables.py +++ b/tests/test_deployables.py @@ -121,4 +121,68 @@ def test_parse_and_write_deployable_docstring(self): def test_parse_and_overwrite_docstring(self): parsed_deployable = parse_function_code(EXPECTED_SERVER_FN_DOCSTRINGS) updated_file_contents = update_deployable_function_comments(EXPECTED_SERVER_FN_DOCSTRINGS, parsed_deployable) - self.assertEqual(EXPECTED_SERVER_FN_DOCSTRINGS, updated_file_contents) \ No newline at end of file + self.assertEqual(EXPECTED_SERVER_FN_DOCSTRINGS, updated_file_contents) + + def test_deployment_comments_with_imports_at_top(self): + """Test that deployment comments are placed at the very top, before import statements.""" + # File content that starts with imports (no existing deployment comments) + file_with_imports = '''from typing import Dict +from polyapi.typedefs import PolyServerFunction + +polyConfig: PolyServerFunction = { + "name": "foobar", + "context": "testing", + "logsEnabled": True, +} + +def foobar(foo: str, bar: Dict[str, str]) -> int: + """A function that does something really important.""" + print("Okay then!") + return 7 +''' + + expected_with_deployment_comments = '''# Poly deployed @ 2024-11-12T14:43:22.631113 - testing.foobar - https://na1.polyapi.io/canopy/polyui/collections/server-functions/jh23h5g3h5b24jh5b2j3h45v2jhg43v52j3h - 086aedd + +from typing import Dict +from polyapi.typedefs import PolyServerFunction + +polyConfig: PolyServerFunction = { + "name": "foobar", + "context": "testing", + "logsEnabled": True, +} + +def foobar(foo: str, bar: Dict[str, str]) -> int: + """A function that does something really important.""" + print("Okay then!") + return 7 +''' + + test_deployable = parse_function_code(file_with_imports, "foobar") + + # Add a mock deployment to test comment placement + test_deployable["deployments"] = [{ + 'context': 'testing', + 'deployed': '2024-11-12T14:43:22.631113', + 'fileRevision': '086aedd', + 'id': 'jh23h5g3h5b24jh5b2j3h45v2jhg43v52j3h', + 'instance': 'https://na1.polyapi.io', + 'name': 'foobar', + 'type': 'server-function' + }] + + # Update deployment comments this should place comments at the very top + updated_file_contents = update_deployment_comments(file_with_imports, test_deployable) + + self.assertEqual(updated_file_contents, expected_with_deployment_comments) + + # ensure the first line is a deployment comment, not an import + first_line = updated_file_contents.split('\n')[0] + self.assertTrue(first_line.startswith('# Poly deployed @'), + f"Expected deployment comment at top, but first line was: {first_line}") + + # Ensure imports come after the deployment comment and blank line + lines = updated_file_contents.split('\n') + import_line_index = next(i for i, line in enumerate(lines) if line.startswith('from typing import')) + self.assertGreater(import_line_index, 1, + "Import statements should come after deployment comments and blank line") \ No newline at end of file From 8009a1e17caab0e11ee5750d7ed8e887bdef27fc Mon Sep 17 00:00:00 2001 From: Ashir Rao <69091220+Ash1R@users.noreply.github.com> Date: Mon, 28 Jul 2025 18:23:40 -0700 Subject: [PATCH 4/4] enforce type during sync --- polyapi/sync.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/polyapi/sync.py b/polyapi/sync.py index ca684fc..3349009 100644 --- a/polyapi/sync.py +++ b/polyapi/sync.py @@ -129,7 +129,8 @@ def sync_deployables(dry_run: bool, instance: str | None = None): **deployable, **previous_deployment, "description": deployable["types"]["description"], - "instance": instance + "instance": instance, + "type": deployable["type"] } else: sync_deployment = { **deployable, "instance": instance }