Skip to content

Commit

Permalink
Enhance GitHubClient: add auto initialization of repositories with RE…
Browse files Browse the repository at this point in the history
…ADME.md, improve error handling during repository creation, and implement checks for default branches.
  • Loading branch information
Your Name committed May 14, 2025
1 parent 089926f commit 9c4588a
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 36 deletions.
26 changes: 12 additions & 14 deletions template_automation/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
from .models import TemplateInput, GitHubConfig
from .template_manager import TemplateManager
from .github_client import GitHubClient
import requests

# Initialize the logger
logger = logging.getLogger()
Expand Down Expand Up @@ -110,20 +111,6 @@ def lambda_handler(event: dict, context) -> dict:
ValueError: If input validation fails
ClientError: On AWS Secrets Manager errors
GithubException: On GitHub API errors.
Example:
>>> event = {
... "project_name": "my-new-service",
... "template_settings": {
... "environment": "production",
... "region": "us-west-2"
... },
... "trigger_init_workflow": True,
... "owning_team": "platform-team"
... }
>>> result = lambda_handler(event, None)
>>> print(result["repository_url"])
'https://github.com/myorg/my-new-service'
"""
try:
logger.info(f"Processing template request: {event}")
Expand Down Expand Up @@ -154,6 +141,17 @@ def lambda_handler(event: dict, context) -> dict:
verify_ssl=VERIFY_SSL # Pass SSL verification setting
)

# Check if the template repository exists
template_repo_name = github_config.template_repo_name
try:
template_repo = github.get_repository(template_repo_name)
logger.info(f"Using template repository: {template_repo_name}")
except requests.exceptions.HTTPError as e:
if e.response.status_code == 404:
logger.error(f"Template repository not found: {template_repo_name}")
raise ValueError(f"Template repository '{template_repo_name}' does not exist in organization {github_config.org_name}")
raise

# Initialize TemplateManager with proper parameters
template_mgr = TemplateManager(template_repo_name=github_config.template_repo_name)

Expand Down
92 changes: 70 additions & 22 deletions template_automation/github_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,8 @@ def get_repository(
# Try with minimal parameters first
repo = self._request("POST", url, json={
"name": repo_name,
"private": True
"private": True,
"auto_init": True # Try to initialize with README
})
except requests.exceptions.HTTPError as create_error:
# Safe handling of response parsing
Expand All @@ -197,31 +198,49 @@ def get_repository(
logger.error("Received HTML error page instead of JSON response")
raise Exception(f"GitHub API returned HTML error page. Your GitHub token may not have sufficient permissions or the GitHub Enterprise server might be configured differently than expected.")

raise create_error
# Try again without auto_init if that was the issue
if "auto_init" in error_message:
repo = self._request("POST", url, json={
"name": repo_name,
"private": True
})
else:
raise create_error

# Wait for repository initialization
max_retries = 10
retry_delay = 2
for i in range(max_retries):
# Check if we need to initialize the repository with a README.md
has_default_branch = False
for branch_name in ["main", "master"]:
try:
# Try both main and master as possible default branches
for branch_name in ["main", "master"]:
try:
self.get_branch(repo_name, branch_name)
logger.info(f"Repository initialized with default branch '{branch_name}'")
break
except requests.exceptions.HTTPError:
pass
else:
# If we reach here, neither branch was found, but repo may still be usable
if i == max_retries - 1:
logger.warning(f"Repository {repo_name} created but default branch not found")
continue
self.get_branch(repo_name, branch_name)
has_default_branch = True
logger.info(f"Repository initialized with default branch '{branch_name}'")
break
except requests.exceptions.HTTPError:
logger.info(f"Waiting for repository initialization, attempt {i+1}/{max_retries}")
time.sleep(retry_delay)
retry_delay *= 1.5 # Exponential backoff
pass

if not has_default_branch:
logger.info("Repository created but has no default branch, creating initial README.md")
try:
# Create a README.md to initialize the repository
self.create_readme_file(repo_name)
# Wait for branch to be created
for _ in range(5):
try:
for branch_name in ["main", "master"]:
try:
self.get_branch(repo_name, branch_name)
has_default_branch = True
logger.info(f"Default branch '{branch_name}' created successfully")
break
except requests.exceptions.HTTPError:
pass
if has_default_branch:
break
except requests.exceptions.HTTPError:
time.sleep(1)
except Exception as init_error:
logger.error(f"Failed to initialize repository with README: {str(init_error)}")
# Continue anyway since we already have the repository

if owning_team:
try:
Expand Down Expand Up @@ -548,3 +567,32 @@ def create_repository_from_template(

logger.info(f"Created new repository: {new_repo_name} from template: {template_repo_name}")
return new_repo

def create_readme_file(self, repo_name: str) -> Dict[str, Any]:
"""Create a README.md file in an empty repository to initialize it.
Args:
repo_name: Name of the repository
Returns:
The created file content data
"""
content = f"""# {repo_name}
This repository was created automatically by the template automation system.
"""
content_bytes = content.encode("utf-8")
content_base64 = base64.b64encode(content_bytes).decode("utf-8")

url = f"/api/v3/repos/{self.org_name}/{repo_name}/contents/README.md"
result = self._request("PUT", url, json={
"message": "Initialize repository with README",
"content": content_base64,
"committer": {
"name": self.commit_author_name,
"email": self.commit_author_email
}
})

logger.info(f"Created README.md in repository {repo_name} to initialize it")
return result["content"]

0 comments on commit 9c4588a

Please sign in to comment.