From b0fbf6c39194b0efd759814b02c05928ec24ab82 Mon Sep 17 00:00:00 2001 From: Saravana Dhandapani Date: Mon, 23 Jun 2025 21:59:14 -0700 Subject: [PATCH] more changes --- bytelyst-cli.sh | 239 ++++++++++++++++++ delete_team_interactive.sh | 61 +++++ github_acc_input.json | 67 +++++ github_repos.json | 49 ++++ list_all_public_repos.sh | 89 +++++-- list_orgs_teams_members.sh | 50 ++++ list_repos_contributors.sh | 175 +++++++++++++ list_repos_contributors_by_user.sh | 162 ++++++++---- ..._contributors_by_user_saravanakumardb.json | 1 - 9 files changed, 810 insertions(+), 83 deletions(-) create mode 100644 bytelyst-cli.sh create mode 100644 delete_team_interactive.sh create mode 100644 github_acc_input.json create mode 100644 github_repos.json create mode 100644 list_orgs_teams_members.sh create mode 100644 list_repos_contributors.sh rename input.json => list_repos_contributors_by_user_saravanakumardb.json (89%) diff --git a/bytelyst-cli.sh b/bytelyst-cli.sh new file mode 100644 index 0000000..e05cd66 --- /dev/null +++ b/bytelyst-cli.sh @@ -0,0 +1,239 @@ +#!/bin/bash + +# bytelyst-cli.sh: Unified CLI for Bytelyst GitHub DevOps Tools +# +# Usage examples: +# ./bytelyst-cli.sh list-public-repos --user +# ./bytelyst-cli.sh list-private-repos --org +# ./bytelyst-cli.sh check-collaborators --input input.json +# ./bytelyst-cli.sh export --type repos --output repos.json +# +# If no arguments are given, an interactive menu is shown. + +RED=$(tput setaf 1) +GREEN=$(tput setaf 2) +YELLOW=$(tput setaf 3) +BLUE=$(tput setaf 4) +RESET=$(tput sgr0) + +REQUIRED_TOOLS=(jq curl) + +# Check for required tools +for tool in "${REQUIRED_TOOLS[@]}"; do + if ! command -v $tool &>/dev/null; then + echo "${RED}❌ Error: Required tool '$tool' is not installed. Please install it and try again.${RESET}" + exit 1 + fi +done + +# Load .env if present +if [[ -f .env ]]; then + export $(grep -v '^#' .env | xargs) +fi + +# Validate GITHUB_TOKEN +if [[ -z "$GITHUB_TOKEN" ]]; then + echo "${RED}❌ Error: GITHUB_TOKEN is not set.\nSet it in your environment (e.g., export GITHUB_TOKEN=... in ~/.zshrc, ~/.bashrc, or .env).${RESET}" + exit 1 +fi + +usage() { + echo "${BLUE}Bytelyst CLI - Unified GitHub DevOps Tool${RESET}" + echo "" + echo "Usage: $0 [options]" + echo "Commands:" + echo " list-public-repos --user " + echo " list-private-repos --org " + echo " check-collaborators --input " + echo " export --type --output " + echo " remove-user-from-all-repos --user [--input ]" + echo " help Show this help message" + echo "" + echo "If no command is given, an interactive menu will be shown." +} + +list_public_repos() { + local user="" + while [[ $# -gt 0 ]]; do + case $1 in + --user) + user="$2"; shift 2;; + *) shift;; + esac + done + if [[ -z "$user" ]]; then + echo "${RED}❌ Please provide --user .${RESET}"; exit 1 + fi + echo "${BLUE}🔍 Fetching all public repositories for user: $user...${RESET}" + local response=$(curl -s -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/users/$user/repos?per_page=100&type=public") + local repos=$(echo "$response" | jq -r '.[].full_name') + if [[ -z "$repos" ]]; then + echo "${YELLOW}🚫 No public repositories found for user.${RESET}" + else + echo "$repos" + fi +} + +list_private_repos() { + local org="" + while [[ $# -gt 0 ]]; do + case $1 in + --org) + org="$2"; shift 2;; + *) shift;; + esac + done + if [[ -z "$org" ]]; then + echo "${RED}❌ Please provide --org .${RESET}"; exit 1 + fi + echo "${BLUE}🔍 Fetching all private repositories for org: $org...${RESET}" + local response=$(curl -s -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/orgs/$org/repos?per_page=100&type=private") + local repos=$(echo "$response" | jq -r '.[].full_name') + if [[ -z "$repos" ]]; then + echo "${YELLOW}🚫 No private repositories found for org.${RESET}" + else + echo "$repos" + fi +} + +check_collaborators() { + local input="" + while [[ $# -gt 0 ]]; do + case $1 in + --input) + input="$2"; shift 2;; + *) shift;; + esac + done + if [[ -z "$input" || ! -f "$input" ]]; then + echo "${RED}❌ Please provide --input (file must exist).${RESET}"; exit 1 + fi + local org=$(jq -r '.org' "$input") + local user=$(jq -r '.user' "$input") + local whitelist=($(jq -r '.whitelist[]' "$input")) + local repos=($(jq -r '.repos[]' "$input")) + if [[ -z "$org" || -z "$user" || ${#whitelist[@]} -eq 0 || ${#repos[@]} -eq 0 ]]; then + echo "${RED}❌ input.json must contain 'org', 'user', 'whitelist', and 'repos'.${RESET}"; exit 1 + fi + for repo in "${repos[@]}"; do + echo "${BLUE}🔍 Checking repo: $repo${RESET}" + local collaborators=$(curl -s -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/repos/$org/$repo/collaborators" | jq -r '.[].login') + local non_whitelisted=() + for collab in $collaborators; do + if [[ ! " ${whitelist[@]} " =~ " ${collab} " ]]; then + non_whitelisted+=("$collab") + fi + done + if [[ ${#non_whitelisted[@]} -gt 0 ]]; then + echo "${YELLOW}🚨 Repository: $repo${RESET}" + echo "${RED}❌ Non-Whitelisted Collaborators:${RESET}" + printf '%s\n' "${non_whitelisted[@]}" + for user in "${non_whitelisted[@]}"; do + read -p "Do you want to remove collaborator '$user' from '$repo'? (yes/no): " confirm + if [[ "$confirm" == "yes" ]]; then + response=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/repos/$org/$repo/collaborators/$user") + if [[ "$response" -eq 204 ]]; then + echo "${GREEN}✅ Successfully removed $user from repository $repo.${RESET}" + else + echo "${YELLOW}⚠️ Failed to remove $user from repository $repo (HTTP Status: $response).${RESET}" + fi + else + echo "${YELLOW}🚫 Skipped removal of $user from $repo.${RESET}" + fi + done + echo "--------------------------------------------" + fi + done +} + +export_json() { + local type=""; local output="" + while [[ $# -gt 0 ]]; do + case $1 in + --type) + type="$2"; shift 2;; + --output) + output="$2"; shift 2;; + *) shift;; + esac + done + if [[ -z "$type" || -z "$output" ]]; then + echo "${RED}❌ Please provide --type and --output .${RESET}"; exit 1 + fi + if [[ "$type" == "repos" ]]; then + jq . repos.json > "$output" + echo "${GREEN}✅ Exported repos to $output${RESET}" + elif [[ "$type" == "users" ]]; then + jq . users.json > "$output" + echo "${GREEN}✅ Exported users to $output${RESET}" + else + echo "${RED}❌ Unknown export type: $type${RESET}" + exit 1 + fi +} + +remove_user_from_all_repos() { + local user=""; local input="github_repos.json" + while [[ $# -gt 0 ]]; do + case $1 in + --user) + user="$2"; shift 2;; + --input) + input="$2"; shift 2;; + *) shift;; + esac + done + if [[ -z "$user" ]]; then + echo "${RED}❌ Please provide --user .${RESET}"; exit 1 + fi + if [[ ! -f "$input" ]]; then + echo "${RED}❌ Input file '$input' not found.${RESET}"; exit 1 + fi + local org=$(jq -r '.org' "$input") + local repos=($(jq -r '.repos[]' "$input")) + if [[ -z "$org" || ${#repos[@]} -eq 0 ]]; then + echo "${RED}❌ Input file must contain 'org' and 'repos'.${RESET}"; exit 1 + fi + for repo in "${repos[@]}"; do + echo "${BLUE}🔗 Removing user '$user' from repo: $repo${RESET}" + response=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/repos/$org/$repo/collaborators/$user") + if [[ "$response" -eq 204 ]]; then + echo "${GREEN}✅ Successfully removed $user from $repo.${RESET}" + elif [[ "$response" -eq 404 ]]; then + echo "${YELLOW}⚠️ $user is not a collaborator on $repo or repo not found.${RESET}" + else + echo "${RED}❌ Failed to remove $user from $repo (HTTP Status: $response).${RESET}" + fi + done +} + +interactive_menu() { + echo "${BLUE}Bytelyst CLI Interactive Menu${RESET}" + select opt in "List Public Repos" "List Private Repos" "Check Collaborators" "Export JSON" "Remove User from All Repos" "Exit"; do + case $REPLY in + 1) read -p "Enter GitHub username: " user; list_public_repos --user "$user";; + 2) read -p "Enter GitHub org: " org; list_private_repos --org "$org";; + 3) read -p "Enter path to input.json: " input; check_collaborators --input "$input";; + 4) read -p "Export type (repos/users): " type; read -p "Output file: " output; export_json --type "$type" --output "$output";; + 5) read -p "Enter GitHub username: " user; remove_user_from_all_repos --user "$user";; + 6) exit 0;; + *) echo "Invalid option.";; + esac + done +} + +# Main CLI dispatcher +if [[ $# -eq 0 ]]; then + interactive_menu + exit 0 +fi + +case $1 in + list-public-repos) shift; list_public_repos "$@";; + list-private-repos) shift; list_private_repos "$@";; + check-collaborators) shift; check_collaborators "$@";; + export) shift; export_json "$@";; + remove-user-from-all-repos) shift; remove_user_from_all_repos "$@";; + help|--help|-h) usage;; + *) echo "${RED}Unknown command: $1${RESET}"; usage; exit 1;; +esac \ No newline at end of file diff --git a/delete_team_interactive.sh b/delete_team_interactive.sh new file mode 100644 index 0000000..1224570 --- /dev/null +++ b/delete_team_interactive.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +RED=$(tput setaf 1) +GREEN=$(tput setaf 2) +YELLOW=$(tput setaf 3) +BLUE=$(tput setaf 4) +RESET=$(tput sgr0) + +usage() { + echo "${BLUE}Usage:${RESET} $0 [--org ] [--team ]" + echo " --org GitHub organization/account (or will prompt)" + echo " --team Team slug (or will prompt)" + echo "" + echo "GITHUB_TOKEN must be set in your environment." +} + +# Parse arguments +ORG="" +TEAM_SLUG="" +while [[ $# -gt 0 ]]; do + case $1 in + --org) ORG="$2"; shift 2;; + --team) TEAM_SLUG="$2"; shift 2;; + -h|--help) usage; exit 0;; + *) echo "${RED}Unknown argument: $1${RESET}"; usage; exit 1;; + esac + done + +if [[ -z "$GITHUB_TOKEN" ]]; then + echo "${RED}❌ GITHUB_TOKEN is not set in your environment.${RESET}" + exit 1 +fi + +# Prompt for org if not provided +if [[ -z "$ORG" ]]; then + read -p "Enter GitHub organization/account: " ORG +fi + +# Prompt for team slug if not provided +if [[ -z "$TEAM_SLUG" ]]; then + read -p "Enter team slug: " TEAM_SLUG +fi + +read -p "Are you sure you want to delete team '$TEAM_SLUG' from org '$ORG'? (yes/no): " CONFIRM +if [[ "$CONFIRM" != "yes" ]]; then + echo "${YELLOW}Aborted by user.${RESET}" + exit 0 +fi + +echo "${BLUE}Attempting to delete team '$TEAM_SLUG' from organization '$ORG'...${RESET}" +RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE \ + -H "Authorization: token $GITHUB_TOKEN" \ + "https://api.github.com/orgs/$ORG/teams/$TEAM_SLUG") + +if [[ "$RESPONSE" -eq 204 ]]; then + echo "${GREEN}✅ Successfully deleted team '$TEAM_SLUG' from '$ORG'.${RESET}" +elif [[ "$RESPONSE" -eq 404 ]]; then + echo "${YELLOW}⚠️ Team '$TEAM_SLUG' not found in organization '$ORG'.${RESET}" +else + echo "${RED}❌ Failed to delete team '$TEAM_SLUG' from '$ORG' (HTTP Status: $RESPONSE).${RESET}" +fi \ No newline at end of file diff --git a/github_acc_input.json b/github_acc_input.json new file mode 100644 index 0000000..baa7dec --- /dev/null +++ b/github_acc_input.json @@ -0,0 +1,67 @@ +{ + "org": "saravanakumardb", + "user": "saravanakumardb", + "whitelist": [ + "saravanakumardb", + "saravanange", + "abhinaisai2002", + "akshaj-us", + "saravanakumardb1", + "bytelyst-ai", + "umadev0931" + ], + "repos": [ + "activetracker", + "bytelyst-minutemaster-web", + "bytelyst-nomgap-web", + "voiceapp", + "SendToEpiCodeNinja", + "ByteListTask", + "devopsdash", + "taskify", + "bytelyst-backend-micro-services", + "bytelyst-chore-rewards-agent-intern-assignment-caren", + "bytelyst-commons-api", + "bytelyst-devops-dashboard-web", + "bytelyst-ds-intern-akhil-Rephrase-Assignment", + "bytelyst-gaslesspad-web", + "bytelyst-github-fastapi", + "bytelyst-micro-service", + "bytelyst-mockr-api", + "bytelyst-mockr-web-aditya", + "bytelyst-nomgap-api", + "bytelyst-note-intelligent-mcp-intern-navneet", + "bytelyst-notelett", + "bytelyst-notelett-api", + "bytelyst-notelett-bolt", + "bytelyst-notes-intern-parth-ios-switft", + "bytelyst-photobox-intern-assignment-sachin", + "bytelyst-quiz-flashcard-gen-web", + "bytelyst-reactnative-intern-parth", + "bytelyst-saas_analytics_yashoratnam_assignment", + "bytelyst-screen-select-web", + "bytelyst-tap-chat-web", + "bytelyst-taskmgmt-api-intern-assignment-Aditya", + "bytelyst-timer-intern-assignment-Akash", + "bytelyst-timer-intern-assignment-zia", + "bytelyst-trigglo-web" + ], + "users": [ + "Kmann22", + "ADPatel07", + "Aditya108786", + "sandho", + "CarenVictor", + "srinija06", + "malvika112", + "navneet1251", + "ParthSharma05", + "Sachin-kumar-jha", + "Yashoratnam-om", + "pal-boy", + "ziamd117", + "EpiCodeNinja", + "i-ayushh18", + "rougue1" + ] +} \ No newline at end of file diff --git a/github_repos.json b/github_repos.json new file mode 100644 index 0000000..5c13024 --- /dev/null +++ b/github_repos.json @@ -0,0 +1,49 @@ +{ + "org": "saravanakumardb", + "user": "saravanakumardb", + "whitelist": [ + "saravanakumardb", + "saravanange", + "abhinaisai2002", + "akshaj-us", + "saravanakumardb1", + "bytelyst-ai", + "umadev0931" + ], + "repos": [ + "activetracker", + "bytelyst-minutemaster-web", + "bytelyst-nomgap-web", + "voiceapp", + "SendToEpiCodeNinja", + "ByteListTask", + "devopsdash", + "taskify", + "bytelyst-backend-micro-services", + "bytelyst-chore-rewards-agent-intern-assignment-caren", + "bytelyst-commons-api", + "bytelyst-devops-dashboard-web", + "bytelyst-ds-intern-akhil-Rephrase-Assignment", + "bytelyst-gaslesspad-web", + "bytelyst-github-fastapi", + "bytelyst-micro-service", + "bytelyst-mockr-api", + "bytelyst-mockr-web-aditya", + "bytelyst-nomgap-api", + "bytelyst-note-intelligent-mcp-intern-navneet", + "bytelyst-notelett", + "bytelyst-notelett-api", + "bytelyst-notelett-bolt", + "bytelyst-notes-intern-parth-ios-switft", + "bytelyst-photobox-intern-assignment-sachin", + "bytelyst-quiz-flashcard-gen-web", + "bytelyst-reactnative-intern-parth", + "bytelyst-saas_analytics_yashoratnam_assignment", + "bytelyst-screen-select-web", + "bytelyst-tap-chat-web", + "bytelyst-taskmgmt-api-intern-assignment-Aditya", + "bytelyst-timer-intern-assignment-Akash", + "bytelyst-timer-intern-assignment-zia", + "bytelyst-trigglo-web" + ] +} \ No newline at end of file diff --git a/list_all_public_repos.sh b/list_all_public_repos.sh index f696732..6abe660 100755 --- a/list_all_public_repos.sh +++ b/list_all_public_repos.sh @@ -2,85 +2,118 @@ # Color codes using tput for better terminal compatibility RED=$(tput setaf 1) +GREEN=$(tput setaf 2) +YELLOW=$(tput setaf 3) +BLUE=$(tput setaf 4) RESET=$(tput sgr0) +# Usage instructions +usage() { + echo "${BLUE}Usage:${RESET} $0" + echo "Lists all public repositories owned by the authenticated user and their organizations." + echo "\nMake sure GITHUB_TOKEN is set in your environment (with 'public_repo' or 'repo' scope)." + echo "You can set GITHUB_TOKEN in your ~/.zshrc (for Zsh users), ~/.bashrc (for Bash users), or in a .env file in this directory." + echo "\nOptions:" + echo " -h, --help Show this help message and exit." +} + +# Check for help flag +if [[ "$1" == "-h" || "$1" == "--help" ]]; then + usage + exit 0 +fi + +# Check for required tools +for tool in jq curl; do + if ! command -v $tool &>/dev/null; then + echo "${RED}❌ Error: Required tool '$tool' is not installed. Please install it and try again.${RESET}" + exit 1 + fi +done + # Load environment variables -GITHUB_TOKEN="${GITHUB_TOKEN:?❌ Error: GITHUB_TOKEN is not set in ~/.zshrc}" +if [[ -f .env ]]; then + export $(grep -v '^#' .env | xargs) +fi + +if [[ -z "$GITHUB_TOKEN" ]]; then + echo "${RED}❌ Error: GITHUB_TOKEN is not set.\nSet it in your environment (e.g., export GITHUB_TOKEN=... in ~/.zshrc or ~/.bashrc) or in a .env file.${RESET}" + exit 1 +fi # Function to check for API errors check_api_error() { local response="$1" - # First check if it's an object with a message field (error response) local error_message=$(echo "$response" | jq -r 'if type == "object" and has("message") then .message else empty end') - if [[ -n "$error_message" ]]; then - echo "❌ GitHub API Error: $error_message" + echo "${RED}❌ GitHub API Error: $error_message${RESET}" return 1 fi - - # Then check if it's an array (expected response type) local is_array=$(echo "$response" | jq -r 'if type == "array" then "true" else "false" end') if [[ "$is_array" != "true" ]]; then - echo "❌ GitHub API Error: Unexpected response format" + echo "${RED}❌ GitHub API Error: Unexpected response format${RESET}" return 1 fi - return 0 } -echo "🔍 Fetching all public repositories owned by user..." +# Validate GitHub token before proceeding +VALIDATE=$(curl -s -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/user) +TOKEN_ERROR=$(echo "$VALIDATE" | jq -r '.message // empty') +if [[ -n "$TOKEN_ERROR" ]]; then + echo "${RED}❌ Invalid or unauthorized GITHUB_TOKEN: $TOKEN_ERROR${RESET}" + echo "${YELLOW}👉 Please check your token value and permissions at https://github.com/settings/tokens${RESET}" + echo "${BLUE}💡 Make sure to set your GITHUB_TOKEN in your ~/.zshrc (for Zsh), ~/.bashrc (for Bash), or a .env file in this directory.${RESET}" + exit 1 +fi + +# Fetch user public repos +echo "${BLUE}🔍 Fetching all public repositories owned by user...${RESET}" RESPONSE=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \ "https://api.github.com/user/repos?per_page=100&type=public") - -# Check for API errors if check_api_error "$RESPONSE"; then USER_PUBLIC_REPOS=$(echo "$RESPONSE" | jq -r '.[].full_name') - if [[ -z "$USER_PUBLIC_REPOS" ]]; then - echo "❌ No public repositories found for user." + echo "${YELLOW}🚫 No public repositories found for user.${RESET}" else - printf "${RED}=> 📂 Public Repositories%s${RESET}\n" " (User-Owned)" > /dev/tty + printf "${GREEN}=> 📂 Public Repositories%s${RESET}\n" " (User-Owned)" > /dev/tty echo "$USER_PUBLIC_REPOS" echo "--------------------------------------------" fi else - echo "❌ Failed to fetch user repositories." + echo "${RED}❌ Failed to fetch user repositories.${RESET}" fi -echo "🔍 Fetching organizations..." +# Fetch organizations +echo "${BLUE}🔍 Fetching organizations...${RESET}" RESPONSE=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \ "https://api.github.com/user/orgs") - -# Check for API errors if check_api_error "$RESPONSE"; then ORG_LIST=$(echo "$RESPONSE" | jq -r '.[].login') - if [[ -z "$ORG_LIST" ]]; then - echo "❌ No organizations found for user." + echo "${YELLOW}🚫 No organizations found for user.${RESET}" exit 0 fi else - echo "❌ Failed to fetch organizations." + echo "${RED}❌ Failed to fetch organizations.${RESET}" exit 1 fi -echo "🔍 Fetching all public repositories under organizations..." +# Fetch org public repos +echo "${BLUE}🔍 Fetching all public repositories under organizations...${RESET}" for ORG in $ORG_LIST; do RESPONSE=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \ "https://api.github.com/orgs/$ORG/repos?per_page=100&type=public") - - # Check for API errors if check_api_error "$RESPONSE"; then ORG_PUBLIC_REPOS=$(echo "$RESPONSE" | jq -r '.[].full_name') - if [[ -z "$ORG_PUBLIC_REPOS" ]]; then - echo "🚫 No public repositories found in organization: $ORG" + echo "${YELLOW}🚫 No public repositories found in organization: $ORG${RESET}" else - printf "${RED}=> 📂 Public Repositories%s${RESET}\n" " ($ORG)" > /dev/tty + printf "${GREEN}=> 📂 Public Repositories%s${RESET}\n" " ($ORG)" > /dev/tty echo "$ORG_PUBLIC_REPOS" fi else - echo "❌ Failed to fetch repositories for organization: $ORG" + echo "${RED}❌ Failed to fetch repositories for organization: $ORG${RESET}" fi echo "--------------------------------------------" done diff --git a/list_orgs_teams_members.sh b/list_orgs_teams_members.sh new file mode 100644 index 0000000..23f1d0a --- /dev/null +++ b/list_orgs_teams_members.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +# list_teams_and_members.sh: List all teams and their members for a GitHub organization +# Usage: ./list_teams_and_members.sh --org + +set -e + +RED=$(tput setaf 1) +GREEN=$(tput setaf 2) +YELLOW=$(tput setaf 3) +BLUE=$(tput setaf 4) +RESET=$(tput sgr0) + +if ! command -v jq &>/dev/null; then + echo "${RED}❌ Error: 'jq' is required but not installed.${RESET}" + exit 1 +fi + +if [[ -z "$GITHUB_TOKEN" ]]; then + echo "${RED}❌ GITHUB_TOKEN is not set in your environment.${RESET}" + exit 1 +fi + +echo "${BLUE}Fetching organizations for the authenticated user...${RESET}" +ORGS=$(curl -s -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/user/orgs" | jq -r '.[].login') + +if [[ -z "$ORGS" ]]; then + echo "${YELLOW}No organizations found for this user.${RESET}" + exit 0 +fi + +for ORG in $ORGS; do + echo -e "${GREEN}Organization: $ORG${RESET}" + TEAMS=$(curl -s -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/orgs/$ORG/teams" | jq -r '.[].slug') + if [[ -z "$TEAMS" ]]; then + echo " ${YELLOW}No teams found in $ORG${RESET}" + continue + fi + for TEAM in $TEAMS; do + echo " ${BLUE}Team: $TEAM${RESET}" + MEMBERS=$(curl -s -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/orgs/$ORG/teams/$TEAM/members" | jq -r '.[].login') + if [[ -z "$MEMBERS" ]]; then + echo " ${YELLOW}No members found in $TEAM${RESET}" + continue + fi + for MEMBER in $MEMBERS; do + echo " Member: $MEMBER" + done + done +done \ No newline at end of file diff --git a/list_repos_contributors.sh b/list_repos_contributors.sh new file mode 100644 index 0000000..dfcf3ba --- /dev/null +++ b/list_repos_contributors.sh @@ -0,0 +1,175 @@ +#!/bin/bash + +RED=$(tput setaf 1) +GREEN=$(tput setaf 2) +YELLOW=$(tput setaf 3) +BLUE=$(tput setaf 4) +RESET=$(tput sgr0) + +usage() { + echo "${BLUE}Usage:${RESET} $0" + echo " No input.json required." + echo " GITHUB_TOKEN must be set in your environment (e.g., in ~/.zshrc, ~/.bashrc, or .env)." +} + +if [[ "$1" == "-h" || "$1" == "--help" ]]; then + usage + exit 0 +fi + +# Check for required tools +for tool in jq curl; do + if ! command -v $tool &>/dev/null; then + echo "${RED}❌ Error: Required tool '$tool' is not installed. Please install it and try again.${RESET}" + exit 1 + fi +done + +# Load environment variables (token only) +if [[ -f .env ]]; then + export $(grep -v '^#' .env | xargs) +fi + +if [[ -z "$GITHUB_TOKEN" ]]; then + echo "${RED}❌ Error: GITHUB_TOKEN is not set.\nSet it in your environment (e.g., export GITHUB_TOKEN=... in ~/.zshrc, ~/.bashrc, or .env).${RESET}" + exit 1 +fi + +# Get authenticated username +AUTH_USER=$(curl -s -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/user | jq -r '.login') +if [[ -z "$AUTH_USER" || "$AUTH_USER" == "null" ]]; then + echo "${RED}❌ Could not determine authenticated user. Check your GITHUB_TOKEN.${RESET}" + exit 1 +fi + +# Prompt for org (default to authenticated user) +read -p "Enter GitHub organization (leave blank for your user '$AUTH_USER'): " GITHUB_ORG +if [[ -z "$GITHUB_ORG" ]]; then + GITHUB_ORG="$AUTH_USER" +fi + +# Prompt for whitelist (comma-separated, default to authenticated user) +read -p "Enter whitelist usernames (comma-separated, leave blank for '$AUTH_USER'): " WHITELIST_INPUT +if [[ -z "$WHITELIST_INPUT" ]]; then + WHITELIST=("$AUTH_USER") +else + IFS=',' read -ra WHITELIST <<< "$WHITELIST_INPUT" + for i in "${!WHITELIST[@]}"; do + WHITELIST[$i]="${WHITELIST[$i]// /}" + done +fi + +# Prompt for interactive review +default_review="no" +read -p "Interactive review? (yes/no, default: $default_review): " INTERACTIVE_REVIEW +if [[ -z "$INTERACTIVE_REVIEW" ]]; then + INTERACTIVE_REVIEW="$default_review" +fi +INTERACTIVE_REVIEW=$(echo "$INTERACTIVE_REVIEW" | tr '[:upper:]' '[:lower:]') +if [[ "$INTERACTIVE_REVIEW" == "yes" ]]; then + INTERACTIVE_REVIEW="true" +else + INTERACTIVE_REVIEW="false" +fi + +# Fetch all private repositories where the user is an owner or collaborator +REPO_DATA=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \ + "https://api.github.com/user/repos?per_page=100&affiliation=owner,collaborator&visibility=private") + +# Extract repository names +REPO_LIST=$(echo "$REPO_DATA" | jq -r '.[].name') + +# Exit if no repositories found +if [[ -z "$REPO_LIST" ]]; then + echo "${YELLOW}❌ No private repositories found or token is missing the 'repo' scope.${RESET}" + exit 1 +fi + +echo "${BLUE}🔍 Checking repositories for non-whitelisted collaborators...${RESET}" +for REPO in $REPO_LIST; do + # Determine if repo is under organization or user + REPO_OWNER=$(echo "$REPO_DATA" | jq -r --arg REPO "$REPO" '.[] | select(.name==$REPO) | .owner.login') + + # If repo belongs to the org, use $GITHUB_ORG instead of user + if [[ "$REPO_OWNER" == "$GITHUB_ORG" ]]; then + REPO_OWNER="$GITHUB_ORG" + fi + + # Fetch all collaborators (includes users even if they haven't committed) + ALL_COLLABORATORS=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \ + "https://api.github.com/repos/$REPO_OWNER/$REPO/collaborators" | jq -r '.[].login') + + # Identify non-whitelisted collaborators + NON_WHITELISTED_COLLABS=() + for COLLAB in $ALL_COLLABORATORS; do + if [[ ! " ${WHITELIST[@]} " =~ " ${COLLAB} " ]]; then + NON_WHITELISTED_COLLABS+=("$COLLAB") + fi + done + + # Only show repositories where non-whitelisted collaborators exist + if [[ ${#NON_WHITELISTED_COLLABS[@]} -gt 0 ]]; then + echo "${YELLOW}🚨 Repository: $REPO (Owner: $REPO_OWNER)${RESET}" + echo "${RED}❌ Non-Whitelisted Collaborators:${RESET}" + printf '%s\n' "${NON_WHITELISTED_COLLABS[@]}" + echo "--------------------------------------------" + + if [[ "$INTERACTIVE_REVIEW" == "true" ]]; then + # Ask for confirmation and delete non-whitelisted collaborators + for USER in "${NON_WHITELISTED_COLLABS[@]}"; do + read -p "Do you want to remove collaborator '$USER' from '$REPO'? (yes/no): " CONFIRM + if [[ "$CONFIRM" == "yes" ]]; then + # Attempt to remove as a direct repository collaborator + RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE -H "Authorization: token $GITHUB_TOKEN" \ + "https://api.github.com/repos/$REPO_OWNER/$REPO/collaborators/$USER") + + if [[ "$RESPONSE" -eq 204 ]]; then + echo "${GREEN}✅ Successfully removed $USER from repository $REPO.${RESET}" + else + echo "${YELLOW}⚠️ Failed to remove $USER from repository $REPO (HTTP Status: $RESPONSE). Checking if they are an org member...${RESET}" + + # Check if the user is an organization member + ORG_MEMBER_STATUS=$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: token $GITHUB_TOKEN" \ + "https://api.github.com/orgs/$GITHUB_ORG/memberships/$USER") + + if [[ "$ORG_MEMBER_STATUS" -eq 200 ]]; then + read -p "❗ $USER is an organization member. Remove them from org '$GITHUB_ORG'? (yes/no): " CONFIRM_ORG + if [[ "$CONFIRM_ORG" == "yes" ]]; then + ORG_REMOVE_RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE -H "Authorization: token $GITHUB_TOKEN" \ + "https://api.github.com/orgs/$GITHUB_ORG/memberships/$USER") + + if [[ "$ORG_REMOVE_RESPONSE" -eq 204 ]]; then + echo "${GREEN}✅ Successfully removed $USER from organization '$GITHUB_ORG'.${RESET}" + else + echo "${RED}❌ Failed to remove $USER from the organization (HTTP Status: $ORG_REMOVE_RESPONSE). Checking if they are in a team...${RESET}" + + # If removal from org fails, check if the user is in a team + TEAMS=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \ + "https://api.github.com/orgs/$GITHUB_ORG/teams" | jq -r '.[].slug') + + for TEAM in $TEAMS; do + TEAM_REMOVE_RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE -H "Authorization: token $GITHUB_TOKEN" \ + "https://api.github.com/orgs/$GITHUB_ORG/teams/$TEAM/memberships/$USER") + + if [[ "$TEAM_REMOVE_RESPONSE" -eq 204 ]]; then + echo "${GREEN}✅ Successfully removed $USER from team '$TEAM'.${RESET}" + break + fi + done + fi + else + echo "${YELLOW}🚫 Skipped removal of $USER from organization.${RESET}" + fi + else + echo "${RED}❌ $USER is neither a direct collaborator, nor an organization member, nor a team member. No action taken.${RESET}" + fi + fi + else + echo "${YELLOW}🚫 Skipped removal of $USER from $REPO.${RESET}" + fi + done + echo "--------------------------------------------" + fi + fi + +done diff --git a/list_repos_contributors_by_user.sh b/list_repos_contributors_by_user.sh index c87b14d..c1d511d 100644 --- a/list_repos_contributors_by_user.sh +++ b/list_repos_contributors_by_user.sh @@ -1,12 +1,63 @@ #!/bin/bash -# Load environment variables -GITHUB_TOKEN="${GITHUB_TOKEN:?❌ Error: GITHUB_TOKEN is not set in ~/.zshrc}" -GITHUB_ORG="${GITHUB_ORG:?❌ Error: GITHUB_ORG is not set in ~/.zshrc}" -GITHUB_USER="${GITHUB_USER:?❌ Error: GITHUB_USER is not set in ~/.zshrc}" +RED=$(tput setaf 1) +GREEN=$(tput setaf 2) +YELLOW=$(tput setaf 3) +BLUE=$(tput setaf 4) +RESET=$(tput sgr0) -# Define the whitelist of allowed collaborators -WHITELIST=("saravanakumardb" "saravanange" "abhinaisai2002" "sandho" "akshaj-us" "saravanakumardb1" "bytelyst-ai" "umadev0931") +usage() { + echo "${BLUE}Usage:${RESET} $0 " + echo " Path to JSON file with parameters (org, user, whitelist)" + echo "" + echo "GITHUB_TOKEN must be set in your environment (e.g., in ~/.zshrc, ~/.bashrc, or .env)." +} + +if [[ "$1" == "-h" || "$1" == "--help" ]]; then + usage + exit 0 +fi + +if [[ $# -ne 1 ]]; then + usage + exit 1 +fi + +INPUT_JSON="$1" + +if [[ ! -f "$INPUT_JSON" ]]; then + echo "${RED}❌ Error: Input file '$INPUT_JSON' not found.${RESET}" + exit 1 +fi + +# Check for required tools +for tool in jq curl; do + if ! command -v $tool &>/dev/null; then + echo "${RED}❌ Error: Required tool '$tool' is not installed. Please install it and try again.${RESET}" + exit 1 + fi +done + +# Load environment variables (token only) +if [[ -f .env ]]; then + export $(grep -v '^#' .env | xargs) +fi + +if [[ -z "$GITHUB_TOKEN" ]]; then + echo "${RED}❌ Error: GITHUB_TOKEN is not set.\nSet it in your environment (e.g., export GITHUB_TOKEN=... in ~/.zshrc, ~/.bashrc, or .env).${RESET}" + exit 1 +fi + +# Parse JSON input +GITHUB_ORG=$(jq -r '.org // empty' "$INPUT_JSON") +GITHUB_USER=$(jq -r '.user // empty' "$INPUT_JSON") +WHITELIST=($(jq -r '.whitelist[]?' "$INPUT_JSON")) +INTERACTIVE_REVIEW=$(jq -r '.interactive_review // "false"' "$INPUT_JSON") + +if [[ -z "$GITHUB_ORG" || -z "$GITHUB_USER" || ${#WHITELIST[@]} -eq 0 ]]; then + echo "${RED}❌ Error: 'org', 'user', and 'whitelist' must be specified in the JSON file.${RESET}" + exit 1 +fi # Fetch all private repositories where the user is an owner or collaborator REPO_DATA=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \ @@ -17,11 +68,11 @@ REPO_LIST=$(echo "$REPO_DATA" | jq -r '.[].name') # Exit if no repositories found if [[ -z "$REPO_LIST" ]]; then - echo "❌ No private repositories found or token is missing the 'repo' scope." + echo "${YELLOW}❌ No private repositories found or token is missing the 'repo' scope.${RESET}" exit 1 fi -echo "🔍 Checking repositories for non-whitelisted collaborators..." +echo "${BLUE}🔍 Checking repositories for non-whitelisted collaborators...${RESET}" for REPO in $REPO_LIST; do # Determine if repo is under organization or user REPO_OWNER=$(echo "$REPO_DATA" | jq -r --arg REPO "$REPO" '.[] | select(.name==$REPO) | .owner.login') @@ -45,64 +96,67 @@ for REPO in $REPO_LIST; do # Only show repositories where non-whitelisted collaborators exist if [[ ${#NON_WHITELISTED_COLLABS[@]} -gt 0 ]]; then - echo "🚨 Repository: $REPO (Owner: $REPO_OWNER)" - echo "❌ Non-Whitelisted Collaborators:" + echo "${YELLOW}🚨 Repository: $REPO (Owner: $REPO_OWNER)${RESET}" + echo "${RED}❌ Non-Whitelisted Collaborators:${RESET}" printf '%s\n' "${NON_WHITELISTED_COLLABS[@]}" echo "--------------------------------------------" - # Ask for confirmation and delete non-whitelisted collaborators - for USER in "${NON_WHITELISTED_COLLABS[@]}"; do - read -p "Do you want to remove collaborator '$USER' from '$REPO'? (yes/no): " CONFIRM - if [[ "$CONFIRM" == "yes" ]]; then - # Attempt to remove as a direct repository collaborator - RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE -H "Authorization: token $GITHUB_TOKEN" \ - "https://api.github.com/repos/$REPO_OWNER/$REPO/collaborators/$USER") + if [[ "$INTERACTIVE_REVIEW" == "true" ]]; then + # Ask for confirmation and delete non-whitelisted collaborators + for USER in "${NON_WHITELISTED_COLLABS[@]}"; do + read -p "Do you want to remove collaborator '$USER' from '$REPO'? (yes/no): " CONFIRM + if [[ "$CONFIRM" == "yes" ]]; then + # Attempt to remove as a direct repository collaborator + RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE -H "Authorization: token $GITHUB_TOKEN" \ + "https://api.github.com/repos/$REPO_OWNER/$REPO/collaborators/$USER") - if [[ "$RESPONSE" -eq 204 ]]; then - echo "✅ Successfully removed $USER from repository $REPO." - else - echo "⚠️ Failed to remove $USER from repository $REPO (HTTP Status: $RESPONSE). Checking if they are an org member..." + if [[ "$RESPONSE" -eq 204 ]]; then + echo "${GREEN}✅ Successfully removed $USER from repository $REPO.${RESET}" + else + echo "${YELLOW}⚠️ Failed to remove $USER from repository $REPO (HTTP Status: $RESPONSE). Checking if they are an org member...${RESET}" - # Check if the user is an organization member - ORG_MEMBER_STATUS=$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: token $GITHUB_TOKEN" \ - "https://api.github.com/orgs/$GITHUB_ORG/memberships/$USER") + # Check if the user is an organization member + ORG_MEMBER_STATUS=$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: token $GITHUB_TOKEN" \ + "https://api.github.com/orgs/$GITHUB_ORG/memberships/$USER") - if [[ "$ORG_MEMBER_STATUS" -eq 200 ]]; then - read -p "❗ $USER is an organization member. Remove them from org '$GITHUB_ORG'? (yes/no): " CONFIRM_ORG - if [[ "$CONFIRM_ORG" == "yes" ]]; then - ORG_REMOVE_RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE -H "Authorization: token $GITHUB_TOKEN" \ - "https://api.github.com/orgs/$GITHUB_ORG/memberships/$USER") + if [[ "$ORG_MEMBER_STATUS" -eq 200 ]]; then + read -p "❗ $USER is an organization member. Remove them from org '$GITHUB_ORG'? (yes/no): " CONFIRM_ORG + if [[ "$CONFIRM_ORG" == "yes" ]]; then + ORG_REMOVE_RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE -H "Authorization: token $GITHUB_TOKEN" \ + "https://api.github.com/orgs/$GITHUB_ORG/memberships/$USER") - if [[ "$ORG_REMOVE_RESPONSE" -eq 204 ]]; then - echo "✅ Successfully removed $USER from organization '$GITHUB_ORG'." + if [[ "$ORG_REMOVE_RESPONSE" -eq 204 ]]; then + echo "${GREEN}✅ Successfully removed $USER from organization '$GITHUB_ORG'.${RESET}" + else + echo "${RED}❌ Failed to remove $USER from the organization (HTTP Status: $ORG_REMOVE_RESPONSE). Checking if they are in a team...${RESET}" + + # If removal from org fails, check if the user is in a team + TEAMS=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \ + "https://api.github.com/orgs/$GITHUB_ORG/teams" | jq -r '.[].slug') + + for TEAM in $TEAMS; do + TEAM_REMOVE_RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE -H "Authorization: token $GITHUB_TOKEN" \ + "https://api.github.com/orgs/$GITHUB_ORG/teams/$TEAM/memberships/$USER") + + if [[ "$TEAM_REMOVE_RESPONSE" -eq 204 ]]; then + echo "${GREEN}✅ Successfully removed $USER from team '$TEAM'.${RESET}" + break + fi + done + fi else - echo "❌ Failed to remove $USER from the organization (HTTP Status: $ORG_REMOVE_RESPONSE). Checking if they are in a team..." - - # If removal from org fails, check if the user is in a team - TEAMS=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \ - "https://api.github.com/orgs/$GITHUB_ORG/teams" | jq -r '.[].slug') - - for TEAM in $TEAMS; do - TEAM_REMOVE_RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE -H "Authorization: token $GITHUB_TOKEN" \ - "https://api.github.com/orgs/$GITHUB_ORG/teams/$TEAM/memberships/$USER") - - if [[ "$TEAM_REMOVE_RESPONSE" -eq 204 ]]; then - echo "✅ Successfully removed $USER from team '$TEAM'." - break - fi - done + echo "${YELLOW}🚫 Skipped removal of $USER from organization.${RESET}" fi else - echo "🚫 Skipped removal of $USER from organization." + echo "${RED}❌ $USER is neither a direct collaborator, nor an organization member, nor a team member. No action taken.${RESET}" fi - else - echo "❌ $USER is neither a direct collaborator, nor an organization member, nor a team member. No action taken." fi + else + echo "${YELLOW}🚫 Skipped removal of $USER from $REPO.${RESET}" fi - else - echo "🚫 Skipped removal of $USER from $REPO." - fi - done - echo "--------------------------------------------" + done + echo "--------------------------------------------" + fi fi + done diff --git a/input.json b/list_repos_contributors_by_user_saravanakumardb.json similarity index 89% rename from input.json rename to list_repos_contributors_by_user_saravanakumardb.json index ba1dffd..4dee3d4 100644 --- a/input.json +++ b/list_repos_contributors_by_user_saravanakumardb.json @@ -4,7 +4,6 @@ "whitelist": [ "saravanakumardb", "saravanange", - "abhinaisai2002", "akshaj-us", "saravanakumardb1", "bytelyst-ai",