util script
This commit is contained in:
1 file changed
+148
@@ -0,0 +1,148 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import re
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
PROJECTS_DIR = Path.home() / "Projects"
|
||||
GITHUB_USER = "SowinskiBraeden"
|
||||
GITEA_HOST = "git.sowinski.dev"
|
||||
|
||||
|
||||
def git(repo: Path, *args: str, check: bool = True) -> subprocess.CompletedProcess:
|
||||
return subprocess.run(
|
||||
["git", "-C", str(repo), *args],
|
||||
text=True,
|
||||
capture_output=True,
|
||||
check=check,
|
||||
)
|
||||
|
||||
|
||||
def find_git_repositories(root: Path):
|
||||
"""
|
||||
Find repositories recursively under ~/Projects.
|
||||
|
||||
Once a .git directory/file is found, don't recurse further into that
|
||||
repository looking for nested repositories.
|
||||
"""
|
||||
repositories = []
|
||||
|
||||
for path in root.rglob(".git"):
|
||||
if path.is_dir() or path.is_file():
|
||||
repositories.append(path.parent)
|
||||
|
||||
return sorted(set(repositories))
|
||||
|
||||
|
||||
def github_repo_name(origin: str):
|
||||
"""
|
||||
Recognize origins such as:
|
||||
|
||||
git@github.com:SowinskiBraeden/example.git
|
||||
https://github.com/SowinskiBraeden/example.git
|
||||
ssh://git@github.com/SowinskiBraeden/example.git
|
||||
|
||||
Returns "example" or None.
|
||||
"""
|
||||
|
||||
patterns = [
|
||||
rf"^git@github\.com:{re.escape(GITHUB_USER)}/([^/]+?)(?:\.git)?$",
|
||||
rf"^https?://github\.com/{re.escape(GITHUB_USER)}/([^/]+?)(?:\.git)?/?$",
|
||||
rf"^ssh://git@github\.com/{re.escape(GITHUB_USER)}/([^/]+?)(?:\.git)?/?$",
|
||||
]
|
||||
|
||||
for pattern in patterns:
|
||||
match = re.match(pattern, origin)
|
||||
|
||||
if match:
|
||||
return match.group(1)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def configure_repository(repo: Path):
|
||||
result = git(repo, "remote", "get-url", "origin", check=False)
|
||||
|
||||
if result.returncode != 0:
|
||||
print(f"SKIP {repo}")
|
||||
print(" No origin remote")
|
||||
return
|
||||
|
||||
origin = result.stdout.strip()
|
||||
repo_name = github_repo_name(origin)
|
||||
|
||||
if not repo_name:
|
||||
print(f"SKIP {repo}")
|
||||
print(f" Origin is not {GITHUB_USER}'s GitHub: {origin}")
|
||||
return
|
||||
|
||||
github_url = f"git@github.com:{GITHUB_USER}/{repo_name}.git"
|
||||
gitea_url = f"git@{GITEA_HOST}:{GITHUB_USER}/{repo_name}.git"
|
||||
|
||||
existing_push_urls = git(
|
||||
repo,
|
||||
"remote",
|
||||
"get-url",
|
||||
"--all",
|
||||
"--push",
|
||||
"origin",
|
||||
).stdout.splitlines()
|
||||
|
||||
print(f"FOUND {repo}")
|
||||
print(f" Repository: {GITHUB_USER}/{repo_name}")
|
||||
|
||||
# Explicitly establish GitHub as the first push destination.
|
||||
#
|
||||
# If no separate pushurl exists yet, this creates one without changing
|
||||
# the fetch URL.
|
||||
if github_url not in existing_push_urls:
|
||||
git(repo, "remote", "set-url", "--push", "origin", github_url)
|
||||
print(f" + push -> {github_url}")
|
||||
else:
|
||||
print(" = GitHub push already configured")
|
||||
|
||||
# Re-read because set-url --push may have replaced the implicit
|
||||
# origin push URL.
|
||||
existing_push_urls = git(
|
||||
repo,
|
||||
"remote",
|
||||
"get-url",
|
||||
"--all",
|
||||
"--push",
|
||||
"origin",
|
||||
).stdout.splitlines()
|
||||
|
||||
if gitea_url not in existing_push_urls:
|
||||
git(
|
||||
repo,
|
||||
"remote",
|
||||
"set-url",
|
||||
"--add",
|
||||
"--push",
|
||||
"origin",
|
||||
gitea_url,
|
||||
)
|
||||
print(f" + push -> {gitea_url}")
|
||||
else:
|
||||
print(" = Gitea push already configured")
|
||||
|
||||
print()
|
||||
|
||||
|
||||
def main():
|
||||
if not PROJECTS_DIR.exists():
|
||||
raise SystemExit(f"Projects directory does not exist: {PROJECTS_DIR}")
|
||||
|
||||
repositories = find_git_repositories(PROJECTS_DIR)
|
||||
|
||||
print(f"Searching {PROJECTS_DIR}")
|
||||
print(f"Found {len(repositories)} Git repositories.\n")
|
||||
|
||||
for repo in repositories:
|
||||
configure_repository(repo)
|
||||
|
||||
print("Done.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user