From 5be2155b3ce06101ea79e5989d5d907bfa97d873 Mon Sep 17 00:00:00 2001 From: m1ngsama Date: Thu, 4 Dec 2025 09:15:00 +0800 Subject: [PATCH] refactor: improve org-clone script with proper error handling - Add comprehensive error checking and validation - Implement proper argument parsing with usage help - Add colored output for better readability - Include prerequisite checks for gh CLI - Track success/failure statistics Unix philosophy: do one thing well, fail gracefully --- bin/org-clone.sh | 130 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 126 insertions(+), 4 deletions(-) mode change 100644 => 100755 bin/org-clone.sh diff --git a/bin/org-clone.sh b/bin/org-clone.sh old mode 100644 new mode 100755 index c40fddd..cafc379 --- a/bin/org-clone.sh +++ b/bin/org-clone.sh @@ -1,5 +1,127 @@ -# rely on github-cli +#!/usr/bin/env bash +# Clone all repositories from a GitHub organization +# Requires: gh (GitHub CLI) +# +# Usage: ./org-clone.sh [destination-dir] +# Example: ./org-clone.sh myorg ~/repos/myorg -gh repo list myorgname --limit 4000 | while read -r repo _; do - gh repo clone "$repo" "$repo" -done +set -euo pipefail + +# Colors for output +readonly RED='\033[0;31m' +readonly GREEN='\033[0;32m' +readonly YELLOW='\033[1;33m' +readonly NC='\033[0m' # No Color + +# Logging functions +log_info() { echo -e "${GREEN}[INFO]${NC} $*"; } +log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } +log_error() { echo -e "${RED}[ERROR]${NC} $*" >&2; } + +# Check prerequisites +check_prerequisites() { + if ! command -v gh &>/dev/null; then + log_error "GitHub CLI (gh) is not installed" + log_info "Install from: https://cli.github.com/" + exit 1 + fi + + if ! gh auth status &>/dev/null; then + log_error "Not authenticated with GitHub CLI" + log_info "Run: gh auth login" + exit 1 + fi +} + +# Show usage +usage() { + cat < [destination-dir] + +Clone all repositories from a GitHub organization. + +Arguments: + org-name GitHub organization name (required) + destination-dir Target directory (default: current directory) + +Examples: + $0 myorg + $0 myorg ~/repos/myorg + +Requirements: + - GitHub CLI (gh) installed and authenticated +EOF + exit 1 +} + +# Main function +main() { + local org_name="${1:-}" + local dest_dir="${2:-.}" + + # Validate arguments + if [[ -z "$org_name" ]]; then + log_error "Organization name is required" + usage + fi + + check_prerequisites + + # Create destination directory if needed + if [[ ! -d "$dest_dir" ]]; then + log_info "Creating directory: $dest_dir" + mkdir -p "$dest_dir" + fi + + # Change to destination directory + cd "$dest_dir" || { + log_error "Cannot access directory: $dest_dir" + exit 1 + } + + log_info "Cloning repositories from organization: $org_name" + log_info "Destination: $(pwd)" + + # Count repositories + local repo_count + repo_count=$(gh repo list "$org_name" --limit 4000 --json name --jq '. | length') + + if [[ "$repo_count" -eq 0 ]]; then + log_warn "No repositories found for organization: $org_name" + exit 0 + fi + + log_info "Found $repo_count repositories" + + # Clone repositories + local success=0 + local failed=0 + + while IFS= read -r repo; do + local repo_name="${repo##*/}" + + if [[ -d "$repo_name" ]]; then + log_warn "Skipping $repo_name (already exists)" + continue + fi + + log_info "Cloning: $repo" + + if gh repo clone "$repo" "$repo_name" 2>/dev/null; then + ((success++)) + log_info "✓ Successfully cloned: $repo_name" + else + ((failed++)) + log_error "✗ Failed to clone: $repo_name" + fi + done < <(gh repo list "$org_name" --limit 4000 --json nameWithOwner --jq '.[].nameWithOwner') + + # Summary + echo + log_info "=== Clone Summary ===" + log_info "Success: $success" + [[ $failed -gt 0 ]] && log_warn "Failed: $failed" || log_info "Failed: $failed" + log_info "Total: $repo_count" +} + +main "$@"