Skip to content

Commit deaa8ba

Browse files
authored
Merge pull request #181 from morph-data/release/v0.3.0
2 parents 807eb48 + 5a3000b commit deaa8ba

48 files changed

Lines changed: 789 additions & 1201 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

core/morph/api/app.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,6 @@
2121
inertia_request_validation_exception_handler,
2222
inertia_version_conflict_exception_handler,
2323
)
24-
from starlette.middleware.cors import CORSMiddleware
25-
from starlette.middleware.sessions import SessionMiddleware
26-
2724
from morph.api.error import ApiBaseError, InternalError, render_error_html
2825
from morph.api.handler import router
2926
from morph.api.plugin import plugin_app
@@ -32,6 +29,8 @@
3229
MorphFunctionMetaObjectCacheManager,
3330
MorphGlobalContext,
3431
)
32+
from starlette.middleware.cors import CORSMiddleware
33+
from starlette.middleware.sessions import SessionMiddleware
3534

3635
# configuration values
3736

@@ -42,10 +41,11 @@
4241
# set true to MORPH_LOCAL_DEV_MODE to use local frontend server
4342
is_local_dev_mode = True if os.getenv("MORPH_LOCAL_DEV_MODE") == "true" else False
4443

44+
project_root = find_project_root_dir()
45+
4546

4647
def custom_compile_logic():
4748
logger.info("Compiling python and sql files...")
48-
project_root = find_project_root_dir()
4949
context = MorphGlobalContext.get_instance()
5050
errors = context.load(project_root)
5151
if len(errors) > 0:
@@ -129,8 +129,6 @@ async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
129129
inertia_request_validation_exception_handler,
130130
)
131131

132-
frontend_dir = os.path.join(os.getcwd(), ".morph", "frontend")
133-
134132

135133
def get_inertia_config():
136134
templates_dir = os.path.join(Path(__file__).resolve().parent, "templates")
@@ -148,15 +146,16 @@ def get_inertia_config():
148146
use_flash_messages=True,
149147
use_flash_errors=True,
150148
entrypoint_filename="main.tsx",
151-
assets_prefix="/src",
149+
root_directory=".morph/frontend",
152150
dev_url=frontend_url,
153151
)
154152

155153
return InertiaConfig(
156154
templates=Jinja2Templates(directory=templates_dir),
157-
manifest_json_path=os.path.join(frontend_dir, "dist", "manifest.json"),
155+
manifest_json_path=os.path.join(project_root, "dist", "manifest.json"),
158156
environment="production",
159157
entrypoint_filename="main.tsx",
158+
root_directory=".morph/frontend",
160159
)
161160

162161

@@ -167,13 +166,13 @@ def get_inertia_config():
167166
if is_local_dev_mode:
168167
app.mount(
169168
"/src",
170-
StaticFiles(directory=os.path.join(frontend_dir, "src")),
169+
StaticFiles(directory=os.path.join(project_root, "src")),
171170
name="src",
172171
)
173172
else:
174173
app.mount(
175174
"/assets",
176-
StaticFiles(directory=os.path.join(frontend_dir, "dist", "assets")),
175+
StaticFiles(directory=os.path.join(project_root, "dist", "assets")),
177176
name="assets",
178177
)
179178

core/morph/api/cloud/client.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,14 +132,20 @@ def verify_api_secret(self) -> MorphClientResponse:
132132

133133
@validate_project_id
134134
def initiate_deployment(
135-
self, project_id: str, image_build_log: str, image_checksum: str
135+
self,
136+
project_id: str,
137+
image_build_log: str,
138+
image_checksum: str,
139+
config: Optional[dict[str, Any]] = None,
136140
) -> MorphClientResponse:
137141
path = "deployment"
138-
body = {
142+
body: dict[str, Any] = {
139143
"projectId": project_id,
140144
"imageBuildLog": image_build_log,
141145
"imageChecksum": image_checksum,
142146
}
147+
if config:
148+
body["config"] = config
143149

144150
return self.request(method="POST", path=path, data=body)
145151

core/morph/api/service.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import time
88
import uuid
99
from contextlib import redirect_stdout
10-
from pathlib import Path
1110
from typing import Any
1211

1312
import click
@@ -284,11 +283,11 @@ async def file_upload_service(input: UploadFileService) -> Any:
284283
)
285284

286285
# Read the saved file path from the cache (always created as following path)
287-
cache_file = Path(find_project_root_dir()).joinpath(
288-
".morph/cache/file_upload.md"
289-
)
290-
with open(cache_file, "r") as f:
291-
saved_filepath = f.read()
286+
saved_filepath = ""
287+
cache_file = "/tmp/file_upload.cache"
288+
if os.path.exists(cache_file):
289+
with open(cache_file, "r") as f:
290+
saved_filepath = f.read()
292291

293292
# Remove the temporary directory
294293
if os.path.exists(temp_dir):

core/morph/api/templates/index.html

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,6 @@
1616
window.__vite_plugin_react_preamble_installed__ = true;
1717
</script>
1818
{% endif %}
19-
20-
<script src="https://cdn.tailwindcss.com"></script>
21-
<script>
22-
tailwind.config = {
23-
darkMode: "class",
24-
};
25-
</script>
2619
</head>
2720
<body>
2821
{% inertia_body %}

core/morph/config/project.py

Lines changed: 125 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import os
2-
from typing import List, Optional
2+
from typing import Dict, List, Optional
33

44
import yaml
55
from pydantic import BaseModel, Field
@@ -13,6 +13,20 @@
1313
from morph.task.utils.morph import find_project_root_dir
1414

1515

16+
class BuildConfig(BaseModel):
17+
runtime: Optional[str] = None
18+
framework: Optional[str] = "morph"
19+
package_manager: Optional[str] = None
20+
context: Optional[str] = None
21+
build_args: Optional[Dict[str, str]] = None
22+
23+
24+
class DeploymentConfig(BaseModel):
25+
provider: Optional[str] = "aws"
26+
aws: Optional[Dict[str, Optional[str]]] = None
27+
gcp: Optional[Dict[str, Optional[str]]] = None
28+
29+
1630
class MorphProject(BaseModel):
1731
profile: Optional[str] = "default"
1832
source_paths: List[str] = Field(default_factory=lambda: ["src"])
@@ -21,6 +35,8 @@ class MorphProject(BaseModel):
2135
package_manager: str = Field(
2236
default="pip", description="Package manager to use, e.g., pip or poetry."
2337
)
38+
build: Optional[BuildConfig] = Field(default_factory=BuildConfig)
39+
deployment: Optional[DeploymentConfig] = Field(default_factory=DeploymentConfig)
2440

2541
class Config:
2642
arbitrary_types_allowed = True
@@ -72,9 +88,115 @@ def save_project(project_root: str, project: MorphProject) -> None:
7288
old_config_path = os.path.join(project_root, "morph_project.yaml")
7389
if os.path.exists(old_config_path):
7490
with open(old_config_path, "w") as f:
75-
yaml.safe_dump(project.model_dump(), f)
91+
f.write(dump_project_yaml(project))
7692
return
7793

7894
config_path = os.path.join(project_root, "morph_project.yml")
7995
with open(config_path, "w") as f:
80-
yaml.safe_dump(project.model_dump(), f)
96+
f.write(dump_project_yaml(project))
97+
98+
99+
def dump_project_yaml(project: MorphProject) -> str:
100+
source_paths = "\n- ".join([""] + project.source_paths)
101+
102+
# Default values
103+
build_runtime = ""
104+
build_framework = ""
105+
build_package_manager = ""
106+
build_context = "."
107+
build_args_str = "\n # - ARG_NAME=value\n # - ANOTHER_ARG=value"
108+
deployment_provider = "aws"
109+
deployment_aws_region = "us-east-1"
110+
deployment_aws_memory = "1024"
111+
deployment_aws_timeout = "300"
112+
deployment_aws_concurrency = "1"
113+
deployment_gcp_region = "us-central1"
114+
deployment_gcp_memory = "1Gi"
115+
deployment_gcp_cpu = "1"
116+
deployment_gcp_concurrency = "80"
117+
deployment_gcp_timeout = "300"
118+
119+
# Set values if build exists
120+
if project.build:
121+
if project.build.runtime:
122+
build_runtime = project.build.runtime or ""
123+
if project.build.framework:
124+
build_framework = project.build.framework or ""
125+
if project.build.package_manager:
126+
build_package_manager = project.build.package_manager or ""
127+
if project.build.context:
128+
build_context = f"{project.build.context}" or "."
129+
if project.build.build_args:
130+
build_args_items = []
131+
for key, value in project.build.build_args.items():
132+
build_args_items.append(f"{key}={value}")
133+
build_args_str = (
134+
"\n # - ".join([""] + build_args_items)
135+
if build_args_items
136+
else "\n # - ARG_NAME=value\n # - ANOTHER_ARG=value"
137+
)
138+
139+
# Set values if deployment exists
140+
if project.deployment:
141+
if project.deployment.provider:
142+
deployment_provider = project.deployment.provider or "aws"
143+
if project.deployment.aws:
144+
deployment_aws_region = project.deployment.aws.get("region") or "us-east-1"
145+
deployment_aws_memory = project.deployment.aws.get("memory") or "1024"
146+
deployment_aws_timeout = project.deployment.aws.get("timeout") or "300"
147+
deployment_aws_concurrency = (
148+
project.deployment.aws.get("concurrency") or "1"
149+
)
150+
if project.deployment.gcp:
151+
deployment_gcp_region = (
152+
project.deployment.gcp.get("region") or "us-central1"
153+
)
154+
deployment_gcp_memory = project.deployment.gcp.get("memory") or "1Gi"
155+
deployment_gcp_cpu = project.deployment.gcp.get("cpu") or "1"
156+
deployment_gcp_concurrency = (
157+
project.deployment.gcp.get("concurrency") or "80"
158+
)
159+
deployment_gcp_timeout = project.deployment.gcp.get("timeout") or "300"
160+
else:
161+
# Use default DeploymentConfig
162+
deployment_provider = "aws"
163+
164+
return f"""
165+
version: '1'
166+
167+
# Framework Settings
168+
default_connection: {project.default_connection}
169+
source_paths:{source_paths}
170+
171+
# Cloud Settings
172+
# profile: {project.profile} # Defined in the Profile Section in `~/.morph/credentials`
173+
# project_id: {project.project_id or "null"}
174+
175+
# Build Settings
176+
build:
177+
# These settings are required when there is no Dockerfile in the project root.
178+
# They define the environment in which the project will be built
179+
runtime: {build_runtime} # python3.9, python3.10, python3.11, python3.12
180+
framework: {build_framework}
181+
package_manager: {build_package_manager} # pip, poetry, uv
182+
# These settings are required when there is a Dockerfile in the project root.
183+
# They define how the Docker image will be built
184+
# context: {build_context}
185+
# build_args:{build_args_str}
186+
187+
# Deployment Settings
188+
deployment:
189+
provider: {deployment_provider} # aws or gcp (default is aws)
190+
# These settings are used only when you want to customize the deployment settings
191+
# aws:
192+
# region: {deployment_aws_region}
193+
# memory: {deployment_aws_memory}
194+
# timeout: {deployment_aws_timeout}
195+
# concurrency: {deployment_aws_concurrency}
196+
# gcp:
197+
# region: {deployment_gcp_region}
198+
# memory: {deployment_gcp_memory}
199+
# cpu: {deployment_gcp_cpu}
200+
# concurrency: {deployment_gcp_concurrency}
201+
# timeout: {deployment_gcp_timeout}
202+
"""

core/morph/frontend/template/.eslintrc.cjs

Lines changed: 0 additions & 18 deletions
This file was deleted.

core/morph/frontend/template/.gitignore

Lines changed: 0 additions & 32 deletions
This file was deleted.

core/morph/frontend/template/index.html

Lines changed: 0 additions & 12 deletions
This file was deleted.

core/morph/frontend/template/package.json

Lines changed: 0 additions & 41 deletions
This file was deleted.

0 commit comments

Comments
 (0)