Skip to content

Commit b375a4c

Browse files
committed
feat: Enhance deployment model and repository functionality
- Updated the Deploy model to make fields optional, improving flexibility in deployment data handling. - Refactored DeployRepository to support fetching multiple deployment records and added methods for retrieving deployments by owner and for obtaining deployment statistics. - Modified the deploy router to include new endpoints for retrieving deployments and statistics, enhancing API capabilities. - Improved error handling and logging for better traceability during deployment operations.
1 parent b1b2a81 commit b375a4c

5 files changed

Lines changed: 110 additions & 36 deletions

File tree

Backend/app/models/deploy.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
from pydantic import BaseModel
22
from typing import Optional, List, Dict
33
from datetime import datetime
4-
4+
from bson import ObjectId
55
class Deploy(BaseModel):
6-
user_github_id: str
7-
repo_name:str
8-
owner: str
9-
branch: str
6+
user_github_id: Optional[str] = None
7+
repo_name: Optional[str] = None
8+
owner: Optional[str] = None
9+
branch: Optional[str] = None
1010
pipeline_path: Optional[str] = None # path to the pipeline file
1111
framework: Optional[str] = None # e.g., "flask", "django", etc.
1212
root_folder_path: Optional[str] = None
@@ -24,4 +24,4 @@ class Deploy(BaseModel):
2424
updated_at: Optional[datetime] = None
2525

2626
class Config:
27-
from_attributes = True
27+
from_attributes = True

Backend/app/repositories/deploy.py

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from typing import List, Dict, Optional
33
from models.deploy import Deploy
44
from datetime import datetime
5+
from bson import ObjectId
56
from dependencies.database_connection import DatabaseConnection
67
import logging
78

@@ -22,6 +23,7 @@ async def create_deploy(self, deploy: Dict) -> Deploy:
2223
deploy_data = deploy.copy()
2324
deploy_data["created_at"] = datetime.now()
2425
deploy_data["updated_at"] = datetime.now()
26+
deploy_data["status"] = "success"
2527
try:
2628
result = await collection.insert_one(deploy_data)
2729
if result.inserted_id:
@@ -34,21 +36,59 @@ async def create_deploy(self, deploy: Dict) -> Deploy:
3436
logger.error(f"Error creating deployment record: {str(e)}")
3537
raise
3638

37-
async def get_deploy(self, repo_name: str, owner: str) -> Optional[Deploy]:
39+
async def get_deploys(self, owner: str, repo_name: str) -> List[Deploy]:
3840
"""
39-
Get a deploy record from the database.
41+
Get a deploys records from the database.
4042
"""
4143
logger.info(f"Fetching deployment record for {owner}/{repo_name}")
4244
collection = await self.db.get_collection(self.collection)
45+
4346
try:
44-
deploy = await collection.find_one({"repo_name": repo_name, "owner": owner})
45-
if deploy:
46-
logger.info(f"Found deployment record for {owner}/{repo_name}")
47-
return Deploy(**deploy)
48-
else:
49-
logger.warning(f"No deployment record found for {owner}/{repo_name}")
50-
return None
47+
deploys = await collection.find({"owner": owner, "repo_name": repo_name}).to_list(length=None)
48+
return [Deploy(**deploy) for deploy in deploys]
5149
except Exception as e:
5250
logger.error(f"Error fetching deployment record: {str(e)}")
5351
raise
54-
52+
53+
# get a list of all the deploys for owner
54+
async def get_deploys_for_owner(self, owner: str) -> List[Deploy]:
55+
"""
56+
Get a list of all the deploys for a given owner.
57+
"""
58+
logger.info(f"Fetching all deployment records for {owner}")
59+
collection = await self.db.get_collection(self.collection)
60+
try:
61+
deploys = await collection.find({"owner": owner}).to_list(length=None)
62+
print(f"deploys: {deploys}")
63+
logger.info(f"Found {len(deploys)} deployment records for {owner}")
64+
return [Deploy(**deploy) for deploy in deploys]
65+
except Exception as e:
66+
logger.error(f"Error fetching deployment records: {str(e)}")
67+
raise
68+
# deployment statistics
69+
async def get_deployment_statistics(self, owner: str) -> Dict:
70+
"""
71+
Get deployment statistics for a specific owner.
72+
"""
73+
logger.info(f"Fetching deployment statistics for owner: {owner}")
74+
collection = await self.db.get_collection(self.collection)
75+
try:
76+
# Get total number of deployments for owner
77+
total_deployments = await collection.count_documents({"owner": owner})
78+
logger.info(f"Total deployments for {owner}: {total_deployments}")
79+
80+
# Get total number of deployments by status for owner
81+
successful_deployments = await collection.count_documents({"owner": owner, "status": "success"})
82+
failed_deployments = await collection.count_documents({"owner": owner, "status": "failed"})
83+
pending_deployments = await collection.count_documents({"owner": owner, "status": "pending"})
84+
85+
return {
86+
"total": total_deployments,
87+
"successful": successful_deployments,
88+
"failed": failed_deployments,
89+
"pending": pending_deployments,
90+
}
91+
92+
except Exception as e:
93+
logger.error(f"Error getting deployment statistics for {owner}: {str(e)}")
94+
raise

Backend/app/routers/auth.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ async def github_callback(
8080
# Return the token and state in the response
8181
response_data = {
8282
"jwt_token": token,
83+
"token": token,
8384
"user": {
8485

8586
"login": user.login,

Backend/app/routers/deploy.py

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
oauth_2_scheme = OAuth2PasswordBearer(tokenUrl="token")
1414
router = APIRouter(prefix="/deploy", tags=["deploy"], dependencies=[Depends(get_current_user)])
15-
@router.post("/", response_model=DeploySchema)
15+
@router.post("/", response_model=Deploy)
1616
async def create_deploy(
1717
deploy: DeployCreateSchema,
1818
user: UserSchema = Depends(get_current_user),
@@ -45,16 +45,48 @@ def get_frameworks(
4545
raise HTTPException(status_code=500, detail=str(e))
4646

4747

48-
@router.delete("/{owner}/{repo_name}")
49-
async def delete_deploy(
48+
@router.get("/repository/{owner}/{repo_name}")
49+
async def get_deploys(
5050
owner: str,
5151
repo_name: str,
5252
deploy_service: DeployService = Depends(get_deploy_service)
53+
) -> List[Deploy]:
54+
"""
55+
Get deploy records for a specific repository.
56+
"""
57+
try:
58+
return await deploy_service.get_deploys(owner, repo_name)
59+
except HTTPException as http_ex:
60+
raise http_ex
61+
except Exception as e:
62+
raise HTTPException(status_code=500, detail=str(e))
63+
64+
@router.get("/owner/{owner}")
65+
async def get_deploys_for_owner(
66+
owner: str,
67+
deploy_service: DeployService = Depends(get_deploy_service)
68+
) -> List[Deploy]:
69+
"""
70+
Get a list of all the deploys for a given owner.
71+
"""
72+
try:
73+
return await deploy_service.get_deploys_for_owner(owner)
74+
except HTTPException as http_ex:
75+
raise http_ex
76+
except Exception as e:
77+
raise HTTPException(status_code=500, detail=str(e))
78+
79+
@router.get("/statistics/{owner}")
80+
async def get_deploy_statistics(
81+
owner: str,
82+
deploy_service: DeployService = Depends(get_deploy_service)
5383
) -> Dict:
5484
"""
55-
destroy terraform resources for repo
85+
Get the deployment statistics.
5686
"""
5787
try:
58-
return await deploy_service.destroy_terraform_resources(owner, repo_name)
88+
return await deploy_service.get_deploy_statistics(owner)
5989
except HTTPException as http_ex:
60-
raise http_ex
90+
raise http_ex
91+
except Exception as e:
92+
raise HTTPException(status_code=500, detail=str(e))

Backend/app/services/deploy.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from services.aws_user import AWSUserService
1919
from services.git_repository import GitRepositoryService
2020
from services.aws_codebuild import AWSCodeBuild
21-
21+
from typing import List
2222
logger = logging.getLogger('deploy')
2323

2424
class DeployService:
@@ -97,28 +97,28 @@ async def get_aws_user(self, user_id: str) -> AWSUserSchema:
9797
raise ValueError("Invalid user ID")
9898
return await self.aws_user_service.get_user_by_id(user_id)
9999

100-
async def get_deploy(self, repo_name: str, owner: str) -> Deploy:
100+
async def get_deploys(self, owner: str, repo_name: str) -> List[Deploy]:
101101
"""Fetch a deployment record from the repository."""
102-
if not repo_name or not isinstance(repo_name, str):
103-
raise ValueError("Invalid repo name")
104-
if not owner or not isinstance(owner, str):
105-
raise ValueError("Invalid owner")
106-
deploy = await self.deploy_repository.get_deploy(repo_name, owner)
107-
if not deploy:
108-
raise ValueError(f"Deployment not found for {owner}/{repo_name}")
109-
return deploy
102+
return await self.deploy_repository.get_deploys(owner, repo_name)
110103

104+
async def get_deploys_for_owner(self, owner: str) -> List[Deploy]:
105+
"""Fetch all deployment records for a given owner."""
106+
107+
return await self.deploy_repository.get_deploys_for_owner(owner)
108+
async def get_deploy_statistics(self, owner: str) -> Dict:
109+
"""Fetch deployment statistics from the repository."""
110+
return await self.deploy_repository.get_deployment_statistics(owner)
111111
async def destroy_terraform_resources(self, owner: str, repo_name: str) -> Dict[str, str]:
112112
"""Destroy Terraform resources for a given repository."""
113113
try:
114114
# Get the deploy record
115-
deploy = await self.get_deploy(repo_name, owner)
116-
if not deploy or not deploy.absolute_path:
115+
deploys = await self.get_deploys(owner, repo_name)
116+
if not deploys or not deploys[0].absolute_path:
117117
raise ValueError("Deploy record not found or missing absolute path")
118118
# get the absolute path of the deploy
119-
tf_working_dir = os.path.join(str(deploy.absolute_path), "terraform")
119+
tf_working_dir = os.path.join(str(deploys[0].absolute_path), "terraform")
120120
tf = Terraform(working_dir=tf_working_dir)
121-
tf.destroy(auto_approve=True, var={'github_owner': deploy.owner})
121+
tf.destroy(auto_approve=True, var={'github_owner': deploys[0].owner})
122122
return {"status": "success", "message": "Resources destroyed successfully"}
123123
except Exception as e:
124124
raise ValueError(f"Error destroying Terraform resources: {str(e)}")
@@ -353,4 +353,5 @@ async def create_deploy(self, deploy: DeployCreateSchema, access_token: str, use
353353
deploy_data["image_tag"] = deployment_tag # Still store the tag even if build fails
354354

355355
logger.info(f"Creating deployment record for {deploy.owner}/{deploy.repo_name}")
356+
356357
return await self.deploy_repository.create_deploy(deploy_data)

0 commit comments

Comments
 (0)