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
110 changes: 68 additions & 42 deletions app/routers/project.py
Original file line number Diff line number Diff line change
@@ -1,69 +1,73 @@
from fastapi import APIRouter, Depends, Request, Query
import logging
import os
from datetime import datetime, timedelta, timezone
from typing import Any
from urllib.parse import parse_qs, urlparse

import httpx
from fastapi.responses import Response, RedirectResponse
from arq.connections import ArqRedis
from fastapi import APIRouter, Depends, Query, Request
from fastapi.responses import RedirectResponse, Response
from redis.asyncio import Redis
from sqlalchemy import select, update
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload
from datetime import datetime, timedelta, timezone
from redis.asyncio import Redis
from arq.connections import ArqRedis
from urllib.parse import urlparse, parse_qs
import logging
import os
from typing import Any

from config import Settings, get_settings
from db import get_db
from dependencies import (
RedirectResponseX,
TemplateResponse,
flash,
get_access,
get_current_user,
get_project_by_name,
get_deployment_by_id,
get_team_by_slug,
get_github_installation_service,
get_github_service,
get_redis_client,
get_job_queue,
flash,
get_translation as _,
TemplateResponse,
RedirectResponseX,
get_project_by_name,
get_redis_client,
get_role,
get_access,
get_github_installation_service,
get_team_by_slug,
)
from models import (
Project,
Deployment,
Domain,
User,
Team,
TeamMember,
utc_now,
from dependencies import (
get_translation as _,
)
from forms.project import (
NewProjectForm,
ProjectDeployForm,
ProjectDeleteForm,
ProjectGeneralForm,
ProjectEnvVarsForm,
ProjectEnvironmentForm,
ProjectDeleteEnvironmentForm,
ProjectBuildAndProjectDeployForm,
ProjectCancelDeploymentForm,
ProjectRollbackDeploymentForm,
ProjectDeleteEnvironmentForm,
ProjectDeleteForm,
ProjectDeployForm,
ProjectDomainForm,
ProjectEnvironmentForm,
ProjectEnvVarsForm,
ProjectGeneralForm,
ProjectRemoveDomainForm,
ProjectVerifyDomainForm,
ProjectResourcesForm,
ProjectRollbackDeploymentForm,
ProjectVerifyDomainForm,
)
from models import (
Deployment,
Domain,
Project,
Team,
TeamMember,
User,
utc_now,
)
from config import get_settings, Settings
from db import get_db
from services.github import GitHubService
from services.github_installation import GitHubInstallationService
from services.deployment import DeploymentService
from services.domain import DomainService
from utils.project import get_latest_projects, get_latest_deployments
from utils.team import get_latest_teams
from utils.pagination import paginate
from utils.environment import group_branches_by_environment, get_environment_for_branch
from services.github import GitHubService
from services.github_installation import GitHubInstallationService
from services.project_detection import detect_project_settings
from utils.color import COLORS
from utils.environment import get_environment_for_branch, group_branches_by_environment
from utils.pagination import paginate
from utils.project import get_latest_deployments, get_latest_projects
from utils.team import get_latest_teams
from utils.user import get_user_github_token

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -126,6 +130,28 @@ async def new_project_details(
form.name.data = repo_name
form.production_branch.data = repo_default_branch

try:
github_oauth_token = await get_user_github_token(db, current_user)
if github_oauth_token:
detected = await detect_project_settings(
github_service,
github_oauth_token,
int(repo_id),
repo_default_branch,
)
if detected.preset:
form.preset.data = detected.preset
if detected.image:
form.image.data = detected.image
if detected.build_command:
form.build_command.data = detected.build_command
if detected.start_command:
form.start_command.data = detected.start_command
if detected.pre_deploy_command:
form.pre_deploy_command.data = detected.pre_deploy_command
except Exception:
logger.warning("Failed to detect project settings", exc_info=True)

if request.method == "POST" and await form.validate_on_submit():
try:
github_oauth_token = await get_user_github_token(db, current_user)
Expand Down
42 changes: 39 additions & 3 deletions app/services/github.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import httpx
import jwt
import time
from typing import Any
from email.utils import parsedate_to_datetime
from typing import Any

import httpx
import jwt


class GitHubService:
Expand Down Expand Up @@ -298,3 +299,38 @@ async def get_repository_installation(self, repo_full_name: str) -> dict:
)
response.raise_for_status()
return response.json()

async def get_repository_file(
self,
user_access_token: str,
repo_id: int,
path: str,
ref: str | None = None,
) -> dict | None:
"""Get file contents from a repository.

Args:
user_access_token: GitHub access token
repo_id: Repository ID
path: Path to the file (e.g., "package.json")
ref: Optional branch/tag/commit to fetch from

Returns:
File content dict with 'content' (base64 encoded) and metadata,
or None if file doesn't exist.
"""
params = {}
if ref:
params["ref"] = ref

response = httpx.get(
f"https://api.github.com/repositories/{repo_id}/contents/{path}",
headers={"Authorization": f"Bearer {user_access_token}"},
params=params,
)

if response.status_code == 404:
return None

response.raise_for_status()
return response.json()
Loading