|
1 | 1 | #!/bin/bash
|
| 2 | +set -euo pipefail |
2 | 3 |
|
3 | 4 | # Script Name: fetch_github_repos_names.sh
|
4 | 5 | # Description: Fetches and lists all repositories of a GitHub user.
|
5 |
| -# It lists both public and private repositories if a personal access token is provided. |
6 |
| -# Usage: fetch_github_repos.sh [github_username] [github_token] |
7 |
| -# github_username - Optional. The GitHub username for which to fetch repositories. |
8 |
| -# github_token - Optional. A GitHub personal access token for accessing private repositories. |
9 |
| -# Example: ./fetch_github_repos_names.sh johnsmith [token] |
| 6 | +# Lists both public and private repositories if a personal access token is provided. |
| 7 | +# Usage: ./fetch_github_repos_names.sh [github_username] [github_token] |
| 8 | +# Example: ./fetch_github_repos_names.sh johnsmith YOUR_GITHUB_TOKEN |
| 9 | + |
| 10 | +# Display usage message and exit |
| 11 | +usage() { |
| 12 | + echo "Usage: $0 [github_username] [github_token]" |
| 13 | + echo " github_username - Optional. GitHub username to fetch repositories for." |
| 14 | + echo " github_token - Optional. Personal access token to access private repositories." |
| 15 | + exit 1 |
| 16 | +} |
10 | 17 |
|
11 | 18 | echo "GitHub Repository Fetcher"
|
12 | 19 |
|
13 |
| -# Function to check if jq is installed |
| 20 | +# Check if jq is installed |
14 | 21 | check_jq_installed() {
|
15 | 22 | if ! command -v jq &>/dev/null; then
|
16 | 23 | echo "Error: jq is not installed. Please install jq to run this script."
|
17 | 24 | exit 1
|
18 | 25 | fi
|
19 | 26 | }
|
20 | 27 |
|
21 |
| -# Function to get authenticated user's login |
| 28 | +# Get authenticated user's login using provided token |
22 | 29 | get_authenticated_user() {
|
23 |
| - local token=$1 |
24 |
| - local auth_header="" |
25 |
| - local user_login="" |
| 30 | + local token="$1" |
| 31 | + local auth_header="Authorization: token $token" |
| 32 | + local user_login |
| 33 | + user_login=$(curl -s -H "$auth_header" https://api.github.com/user | jq -r '.login') |
| 34 | + echo "$user_login" |
| 35 | +} |
26 | 36 |
|
27 |
| - if [ -n "$token" ]; then |
28 |
| - auth_header="Authorization: token $token" |
29 |
| - user_login=$(curl -s -H "$auth_header" https://api.github.com/user | jq -r '.login') |
| 37 | +# Global variable for authorization header (set in main) |
| 38 | +auth_header="" |
| 39 | + |
| 40 | +# Fetch a page with a single curl call to get both headers and body |
| 41 | +# The function echoes the body and sets the global variable 'next_url' if more pages exist. |
| 42 | +fetch_page() { |
| 43 | + local url="$1" |
| 44 | + # Fetch headers and body together |
| 45 | + local response |
| 46 | + response=$(curl -s -D - "$url" -H "$auth_header") |
| 47 | + # Separate headers (everything until the first blank line) |
| 48 | + local header |
| 49 | + header=$(printf "%s" "$response" | sed -n '1,/^$/p') |
| 50 | + # Separate body (everything after the first blank line) |
| 51 | + local body |
| 52 | + body=$(printf "%s" "$response" | sed -n '/^$/,$p' | sed '1d') |
| 53 | + # Extract next page URL from the Link header, if available |
| 54 | + if [[ "$header" =~ \<([^>]+)\>\;\ *rel=\"next\" ]]; then |
| 55 | + next_url="${BASH_REMATCH[1]}" |
| 56 | + else |
| 57 | + next_url="" |
30 | 58 | fi
|
31 |
| - |
32 |
| - echo "$user_login" |
| 59 | + echo "$body" |
33 | 60 | }
|
34 | 61 |
|
35 | 62 | # Main function
|
36 | 63 | main() {
|
37 | 64 | check_jq_installed
|
38 | 65 |
|
39 | 66 | if [ "$#" -gt 2 ]; then
|
40 |
| - echo "Usage: $0 [github_username] [github_token]" |
41 |
| - exit 1 |
| 67 | + usage |
42 | 68 | fi
|
43 | 69 |
|
44 |
| - local USERNAME=${1:-} |
45 |
| - local GITHUB_TOKEN=${2:-} |
| 70 | + local USERNAME="${1:-}" |
| 71 | + local GITHUB_TOKEN="${2:-}" |
46 | 72 | local AUTHENTICATED_USER=""
|
47 | 73 |
|
48 | 74 | if [ -n "$GITHUB_TOKEN" ]; then
|
| 75 | + auth_header="Authorization: token $GITHUB_TOKEN" |
49 | 76 | AUTHENTICATED_USER=$(get_authenticated_user "$GITHUB_TOKEN")
|
50 | 77 | if [ -z "$AUTHENTICATED_USER" ] || [ "$AUTHENTICATED_USER" = "null" ]; then
|
51 | 78 | echo "Error: Invalid or expired GitHub token."
|
52 | 79 | exit 1
|
53 | 80 | fi
|
| 81 | + else |
| 82 | + auth_header="" |
54 | 83 | fi
|
55 | 84 |
|
56 |
| - # Determine which endpoint to use |
57 | 85 | local URL=""
|
| 86 | + # Determine API endpoint to use |
58 | 87 | if [ -n "$GITHUB_TOKEN" ] && { [ -z "$USERNAME" ] || [ "$USERNAME" = "$AUTHENTICATED_USER" ]; }; then
|
59 |
| - # Fetch all repos (public and private) of authenticated user |
60 | 88 | URL="https://api.github.com/user/repos?per_page=100"
|
61 | 89 | echo "Fetching repositories for authenticated user '$AUTHENTICATED_USER'..."
|
62 | 90 | elif [ -n "$USERNAME" ]; then
|
63 |
| - # Fetch public repos of specified user |
64 | 91 | URL="https://api.github.com/users/$USERNAME/repos?per_page=100"
|
65 | 92 | echo "Fetching public repositories for user '$USERNAME'..."
|
66 | 93 | else
|
67 | 94 | echo "Error: Username required if no token is provided."
|
68 |
| - exit 1 |
| 95 | + usage |
69 | 96 | fi
|
70 | 97 |
|
71 | 98 | echo "--------------------------------"
|
72 | 99 |
|
73 |
| - local auth_header="" |
74 |
| - if [ -n "$GITHUB_TOKEN" ]; then |
75 |
| - auth_header="Authorization: token $GITHUB_TOKEN" |
76 |
| - fi |
77 |
| - |
78 |
| - # Fetch repos with pagination |
| 100 | + # Fetch repositories with pagination |
79 | 101 | while [ -n "$URL" ]; do
|
80 |
| - response=$(curl -s -H "$auth_header" "$URL") |
81 |
| - echo "$response" | jq -r '.[] | .name' |
82 |
| - |
83 |
| - # Get the 'next' URL from the 'Link' header |
84 |
| - link_header=$(curl -s -I -H "$auth_header" "$URL" | grep -i '^Link: ' | tr -d '\r\n') |
85 |
| - if [[ $link_header =~ \<([^>]+)\>\;[[:space:]]rel=\"next\" ]]; then |
86 |
| - URL="${BASH_REMATCH[1]}" |
87 |
| - else |
88 |
| - URL="" |
89 |
| - fi |
| 102 | + local page_body |
| 103 | + page_body=$(fetch_page "$URL") |
| 104 | + echo "$page_body" | jq -r '.[] | .name' |
| 105 | + URL="$next_url" |
90 | 106 | done
|
91 | 107 |
|
92 | 108 | echo "--------------------------------"
|
|
0 commit comments