Skip to content

Instantly share code, notes, and snippets.

@Tobi-De
Last active September 18, 2024 07:56
Show Gist options
  • Save Tobi-De/29e8f76cd03a95e2ae150db91ca6e903 to your computer and use it in GitHub Desktop.
Save Tobi-De/29e8f76cd03a95e2ae150db91ca6e903 to your computer and use it in GitHub Desktop.
backup github repos to gitea
# requirements: httpx, python-dotenv
import os
import httpx
from dotenv import load_dotenv
from datetime import datetime as dt
import pytz
from dateutil import parser
load_dotenv()
gitea_api_key = os.getenv("GITEA_API_KEY")
gitea_server_url = os.getenv("GITEA_SERVER_URL")
github_token = os.getenv("GITHUB_TOKEN")
github_username = "tobi-de"
# repos_api_path = f"https://api.github.com/users/{github_username}/repos?type=owner&visibility=all"
repos_api_path = f"https://api.github.com/user/repos?type=owner"
def get_next_link(link):
links = link.split(',')
for l in links:
if 'rel="next"' in l:
return l.split(";")[0].replace("<", "").replace(">", "").strip()
def retrieve_all_gh_repos():
repos = []
with httpx.Client(headers={"Authorization": f"token {github_token}"}) as client:
url = repos_api_path
while True:
resp = client.get(url)
data = resp.json()
repos.extend({"clone_addr": d["clone_url"], "description": d["description"], "private": d["private"],
"repo_name": d["name"], "pushed_at": d["pushed_at"]} for d in data)
link = resp.headers.get("link")
has_next = link and 'rel="next"' in link
if not has_next:
break
url = get_next_link(link)
return repos
def main():
repos = retrieve_all_gh_repos()
print(len(repos))
current_datetime_utc = dt.now(pytz.timezone('UTC'))
with httpx.Client(
base_url=f"{gitea_server_url}/api/v1",
headers={"Authorization": f"token {gitea_api_key}"},
) as client:
for repo in repos:
print(repo["repo_name"])
last_pushed = parser.parse(repo["pushed_at"])
mirror_interval = "24h" if (current_datetime_utc - last_pushed).days < 15 else f"{7 * 24}h"
resp = client.post("repos/migrate", json={
"auth_password": github_token,
"auth_username": github_username,
"clone_addr": repo["clone_addr"],
"description": repo["description"],
"private": repo["private"],
"repo_name": repo["repo_name"],
"service": "github",
"issues": True,
"labels": True,
"mirror": True,
"releases": True,
"wiki": True,
"pull_requests": True,
"mirror_interval": mirror_interval
})
print(resp)
print(len(repos))
if __name__ == "__main__":
main()
@Tobi-De
Copy link
Author

Tobi-De commented Sep 18, 2024

from pathlib import Path
import subprocess

def check_repo_status(repo_path):
    # Check if it's a git repository
    if not (repo_path / ".git").is_dir():
        return False
    
    # Check for uncommitted changes
    uncommitted_changes = subprocess.run(
        ['git', 'status', '--porcelain'],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        text=True,
        cwd=repo_path
    ).stdout.strip()
    
    # Fetch updates from the remote
    subprocess.run(['git', 'remote', 'update'], cwd=repo_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
    
    # Check if branch is behind or diverged from the remote
    branch_status = subprocess.run(
        ['git', 'status', '-uno'],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        text=True,
        cwd=repo_path
    ).stdout
    
    not_up_to_date = "Your branch is behind" in branch_status or "have diverged" in branch_status

    return bool(uncommitted_changes) or not_up_to_date

def check_repos_in_directory(directory):
    # Loop through each folder in the directory
    for repo_path in directory.iterdir():
        if repo_path.is_dir() and check_repo_status(repo_path):
            print(f"Repository {repo_path.name} has uncommitted changes or is not up to date.")

# Set your directory path here
directory_path = Path("/path/to/your/repos")
check_repos_in_directory(directory_path)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment