Skip to content

Instantly share code, notes, and snippets.

@f0ster
Last active May 11, 2024 18:46
Show Gist options
  • Save f0ster/88c55f169a79c48479a9cfd8c9b0fb59 to your computer and use it in GitHub Desktop.
Save f0ster/88c55f169a79c48479a9cfd8c9b0fb59 to your computer and use it in GitHub Desktop.
Summarize git repositories
# script to provide a summary of the repositories by only listing each one's name
# along with its status (public, public with changes, or private)
import os
import subprocess
import json
from concurrent.futures import ThreadPoolExecutor, as_completed
def execute_command(command, cwd):
"""Executes a shell command in a specified directory and returns the output."""
result = subprocess.run(command, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True)
if result.returncode != 0:
return None
return result.stdout.strip()
def is_git_repo(path):
"""Check if a directory is a git repository."""
return execute_command("git rev-parse --is-inside-work-tree", cwd=path) is not None
def get_remote_urls(path):
"""Retrieve all remote URLs of the git repository."""
return execute_command("git remote -v", cwd=path)
def is_public(url):
"""Determine if the git repository URL suggests it is public."""
private_indicators = ["gitlab.mycompany.com", "github-private.com"]
return not any(private in url for private in private_indicators)
def check_for_local_changes(path):
"""Check for local branch changes not pushed to remote."""
local_branches = execute_command("git branch -vv", cwd=path)
return "ahead" in local_branches if local_branches else False
def analyze_repository(repo_path):
"""Analyze a single repository to determine its status and return detailed info."""
if is_git_repo(repo_path):
urls = get_remote_urls(repo_path)
if urls:
if is_public(urls):
has_changes = check_for_local_changes(repo_path)
status = 'Public + Changes' if has_changes else 'Public'
else:
status = 'Private'
return {'path': repo_path, 'status': status}
return None
def main():
root_dir = input("Enter the directory path containing git repositories: ")
repo_details = []
# Collect top-level directory paths within the specified root
top_level_repos = [os.path.join(root_dir, d) for d in os.listdir(root_dir) if os.path.isdir(os.path.join(root_dir, d))]
# Use ThreadPoolExecutor to process repositories in parallel
with ThreadPoolExecutor(max_workers=10) as executor:
futures = [executor.submit(analyze_repository, repo_path) for repo_path in top_level_repos if is_git_repo(repo_path)]
for future in as_completed(futures):
result = future.result()
if result:
repo_details.append(result)
# Save results to JSON
with open('repository_summary.json', 'w') as json_file:
json.dump(repo_details, json_file, indent=4)
print("\nDetailed repository status has been saved to 'repository_summary.json'.")
if __name__ == "__main__":
main()
@f0ster
Copy link
Author

f0ster commented May 11, 2024

jq '.[] | select(.status == "Public + Changes")' repository_summary.json

echo "Review the directories to be deleted:" && jq -r '.[] | select(.status == "Public" and (.identifier | contains("specific-owner") | not)) | .path' repository_summary.json && echo "Are you sure you want to delete these directories? (y/n)" && read confirm && [[ "$confirm" =~ ^[Yy]$ ]] && jq -r '.[] | select(.status == "Public" and (.identifier | contains("specific-owner") | not)) | .path' repository_summary.json | xargs rm -rf || echo "Deletion cancelled."

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