Spaces:
Sleeping
Sleeping
#!/usr/bin/env python | |
import base64 | |
import random | |
import requests | |
from requests import Response | |
from typing import Any, Dict, Optional | |
from github import Github | |
from default_params import ( | |
DEFAULT_ACCESS_TOKEN, | |
DEFAULT_DEVCONTAINER_JSON, | |
DEFAULT_DOCKERFILE, | |
DEFAULT_REPO_URL, | |
DEFAULT_SAMPLE_SCRIPT, | |
DEFAULT_USERNAME, | |
) | |
class GithubRepoAccess: | |
access_token: str | |
gh: Github | |
headers = {} | |
def __init__(self, access_token) -> None: | |
self.access_token = access_token | |
self.gh = Github(self.access_token) | |
self.headers["Authorization"] = self.access_token | |
## function that uses the github api for | |
def clone_repository(self,repo_name: str) -> any: | |
repo_details = self.gh.get_repo(repo_name) | |
repo_url = repo_details.clone_url | |
repo_details = requests.get(repo_url, headers=self.headers) | |
## getting principal branch for cloning the file | |
branch = self.gh.get_repo(repo_name) | |
clone_repository_url = ( | |
f"https://api.github.com/repos/{repo_owner}/{repo_name}/tarball/{branch}" | |
) | |
## cloning the repository | |
clone_repository_response = requests.get(clone_repository_url, headers=self.headers) | |
def repo_exists(access_token: str, repo_name: str) -> bool: | |
for repo in gh.get_user().get_repos(): | |
if repo.name == repo_name: | |
print("Repo exists!!") | |
return True | |
return False | |
def fork_repository( | |
username: str, repo_owner: str, repo_name: str, headers: dict[str, str] | |
) -> Optional[Dict[str, Any]]: | |
fork_api_url = ( | |
f"https://api.github.com/repos/{repo_owner}/{repo_name}/forks" | |
) | |
fork_response = requests.post(fork_api_url, headers=self.headers) | |
if fork_response.status_code == 202: | |
print("Repository forked successfully.") | |
return fork_response.json() | |
else: | |
print("Error forking the repository.") | |
print("Status code:", fork_response.status_code) | |
print("Error message:", fork_response.json()) | |
return None | |
def create_new_branch( | |
username: str, | |
repo_name: str, | |
new_branch_name: str, | |
headers: dict[str, str], | |
) -> None: | |
api_base_url: str = f"https://api.github.com/repos/{username}/{repo_name}" | |
branches_api_url: str = f"{api_base_url}/git/refs/heads" | |
branches_response: Response = requests.get( | |
branches_api_url, headers=self.headers | |
) | |
branches = branches_response.json() | |
main_branch_sha = None | |
for branch in branches: | |
if branch["ref"] == "refs/heads/main": | |
main_branch_sha = branch["object"]["sha"] | |
break | |
if not main_branch_sha: | |
print("Error: Couldn't find the main branch.") | |
return | |
new_branch_data: dict[str, Any] = { | |
"ref": f"refs/heads/{new_branch_name}", | |
"sha": main_branch_sha, | |
} | |
new_branch_response: Response = requests.post( | |
branches_api_url, headers=self.headers, json=new_branch_data | |
) | |
if new_branch_response.status_code == 201: | |
print(f"New branch '{new_branch_name}' created successfully.") | |
else: | |
print("Error creating the new branch.") | |
print("Status code:", new_branch_response.status_code) | |
print("Error message:", new_branch_response.json()) | |
def commit_files_to_branch( | |
self, | |
repo_owner: str, | |
repo_name: str, | |
new_branch_name: str, | |
devcontainer_json_content: str, | |
dockerfile_content: str, | |
sample_script_content: str, | |
headers: dict[str, str], | |
) -> None: | |
api_base_url: str = ( | |
f"https://api.github.com/repos/{repo_owner}/{repo_name}" | |
) | |
# Get default branch and its commit SHA | |
repo_info = requests.get(api_base_url, headers=self.headers).json() | |
print(repo_info) | |
default_branch = repo_info["default_branch"] | |
default_branch_sha = requests.get( | |
f"{api_base_url}/git/ref/heads/master", headers=self.headers | |
).json()["object"]["sha"] | |
devcontainer_json_blob_sha = requests.post( | |
f"{api_base_url}/git/blobs", | |
headers=self.headers, | |
json={ | |
"content": base64.b64encode( | |
devcontainer_json_content.encode() | |
).decode(), | |
"encoding": "base64", | |
}, | |
).json()["sha"] | |
dockerfile_blob_sha = requests.post( | |
f"{api_base_url}/git/blobs", | |
headers=self.headers, | |
json={ | |
"content": base64.b64encode(dockerfile_content.encode()).decode(), | |
"encoding": "base64", | |
}, | |
).json()["sha"] | |
sample_script_blob_sha = requests.post( | |
f"{api_base_url}/git/blobs", | |
headers=self.headers, | |
json={ | |
"content": base64.b64encode( | |
sample_script_content.encode() | |
).decode(), | |
"encoding": "base64", | |
}, | |
).json()["sha"] | |
# Get latest commit tree | |
latest_commit_tree_sha = requests.get( | |
f"{api_base_url}/git/commits/{default_branch_sha}", headers=self.headers | |
).json()["tree"]["sha"] | |
print("Latest commit tree SHA:", latest_commit_tree_sha) | |
# Create a new tree with the new blobs | |
new_tree_response = requests.post( | |
f"{api_base_url}/git/trees", | |
headers=self.headers, | |
json={ | |
"base_tree": latest_commit_tree_sha, | |
"tree": [ | |
{ | |
"path": ".devcontainer/devcontainer.json", | |
"mode": "100644", | |
"type": "blob", | |
"sha": devcontainer_json_blob_sha, | |
}, | |
{ | |
"path": ".devcontainer/Dockerfile", | |
"mode": "100644", | |
"type": "blob", | |
"sha": dockerfile_blob_sha, | |
}, | |
{ | |
"path": "sample_script.py", | |
"mode": "100644", | |
"type": "blob", | |
"sha": sample_script_blob_sha, | |
}, | |
], | |
}, | |
) | |
if new_tree_response.status_code == 201: | |
new_tree = new_tree_response.json() | |
print("New tree created successfully.") | |
print("New tree SHA:", new_tree["sha"]) | |
else: | |
print("Error creating the new tree.") | |
print("Status code:", new_tree_response.status_code) | |
print("Error message:", new_tree_response.json()) | |
exit(1) | |
# Create a new commit with the new tree | |
new_commit_response = requests.post( | |
f"{api_base_url}/git/commits", | |
headers=self.headers, | |
json={ | |
"message": "Add devcontainer.json and Dockerfile", | |
"tree": new_tree["sha"], | |
"parents": [default_branch_sha], | |
}, | |
) | |
if new_commit_response.status_code == 201: | |
new_commit = new_commit_response.json() | |
print("New commit created successfully.") | |
print("New commit SHA:", new_commit["sha"]) | |
else: | |
print("Error creating the new commit.") | |
print("Status code:", new_commit_response.status_code) | |
print("Error message:", new_commit_response.json()) | |
exit(1) | |
# Create new branch on the forked repository with the new commit SHA | |
new_branch_ref = f"refs/heads/{new_branch_name}" | |
create_branch_response = requests.post( | |
f"{api_base_url}/git/refs", | |
headers=self.headers, | |
json={"ref": new_branch_ref, "sha": new_commit["sha"]}, | |
) | |
if create_branch_response.status_code == 201: | |
print( | |
f"New branch '{new_branch_name}' created successfully on the forked repository with devcontainer.json and Dockerfile." | |
) | |
else: | |
print("Error creating the new branch on the forked repository.") | |
print("Status code:", create_branch_response.status_code) | |
print("Error message:", create_branch_response.json()) | |
exit(1) | |
def create_codespace( | |
repo_owner: str, | |
repo_name: str, | |
new_branch_name: str, | |
headers: dict[str, str], | |
) -> str: | |
api_base_url: str = ( | |
f"https://api.github.com/repos/{repo_owner}/{repo_name}/codespaces" | |
) | |
create_codespace_payload = {"ref": new_branch_name} | |
create_codespace_response = requests.post( | |
api_base_url, headers=self.headers, json=create_codespace_payload | |
) | |
if create_codespace_response.status_code == 201: | |
print( | |
"Codespace creation request is successful. Waiting for the Codespace to be created..." | |
) | |
codespace = create_codespace_response.json() | |
# Poll the Codespace's status until it becomes 'available' | |
codespace_id = codespace["id"] | |
print(codespace_id) | |
print(codespace) | |
codespace_status = codespace["state"] | |
print(codespace_status) | |
return codespace_id | |
# while codespace_status != 'Available': | |
# time.sleep(10) | |
# codespace_response = requests.get(f'{api_base_url}/{codespace_id}', headers=self.headers) | |
# codespace = codespace_response.json() | |
# import ipdb | |
# ipdb.set_trace() | |
# codespace_status = codespace['state'] | |
# print(f"Current Codespace status: {codespace_status}") | |
# | |
# print(f"Codespace is available! ID: {codespace_id}") | |
else: | |
print("Error creating the Codespace.") | |
print("Status code:", create_codespace_response.status_code) | |
print("Error message:", create_codespace_response.json()) | |
def create_codespace_with_files( | |
username: str, | |
access_token: str, | |
repo_url: str, | |
docker_file: str, | |
devcontainer_json: str, | |
sample_script: str, | |
) -> str: | |
# Extract repository owner and name from the repo URL | |
repo_parts = repo_url.split("/") | |
repo_owner = repo_parts[-2] | |
repo_name = repo_parts[-1].replace(".git", "") | |
# Configure headers for the GitHub API | |
headers = { | |
"Authorization": f"token {access_token}", | |
"Accept": "application/vnd.github+json", | |
"Content-Type": "application/json", | |
} | |
if not repo_exists(access_token, repo_name): | |
# Fork the repository | |
forked_repo = fork_repository(username, repo_owner, repo_name, headers) | |
print("Forked!") | |
# Create a new branch in the forked repository | |
new_branch_name = "devcontainer-setup-" + str(random.randint(1, 1000)) | |
# create_new_branch(username, repo_name, new_branch_name, headers) | |
# Commit devcontainer.json, Dockerfile, and sample_script to the new branch | |
commit_files_to_branch( | |
username, | |
repo_name, | |
new_branch_name, | |
devcontainer_json, | |
docker_file, | |
sample_script, | |
headers, | |
) | |
print("Branch created and committed files") | |
# Create a new Codespace using the new branch | |
codespace_id = create_codespace( | |
username, repo_name, new_branch_name, headers | |
) | |
return codespace_id | |
if __name__ == "__main__": | |
create_codespace_with_files( | |
username=DEFAULT_USERNAME, | |
access_token=DEFAULT_ACCESS_TOKEN, | |
repo_url=DEFAULT_REPO_URL, | |
docker_file=DEFAULT_DOCKERFILE, | |
devcontainer_json=DEFAULT_DEVCONTAINER_JSON, | |
sample_script=DEFAULT_SAMPLE_SCRIPT, | |
) | |