1+ #! /bin/bash
2+
3+ echo " GITHUBMONITOR variable is set to: ${GITHUBMONITOR} "
4+ github_monitor=" ${GITHUBMONITOR:- true} "
5+ if [ " ${github_monitor} " != " true" ]; then
6+ echo " Skipping GitHub monitor script as per configuration"
7+ exit 0
8+ fi
9+
10+ # GitHub Repository Monitor
11+ # Displays recent commits and open PRs for a list of public GitHub repositories
12+
13+ # Configuration
14+ DEFAULT_COMMIT_COUNT=5
15+ GITHUB_API_BASE=" https://api.github.com"
16+
17+ # Dynamic repository discovery configuration
18+ DEFAULT_GITHUB_ORG=" NHSDigital" # Default GitHub organization to search
19+ DEFAULT_REPO_PREFIX=" nhs-notify" # Default repository name prefix to filter by
20+
21+ # Colors for output
22+ RED=' \033[0;31m'
23+ GREEN=' \033[0;32m'
24+ YELLOW=' \033[1;33m'
25+ BLUE=' \033[0;34m'
26+ PURPLE=' \033[0;35m'
27+ CYAN=' \033[0;36m'
28+ WHITE=' \033[1;37m'
29+ BOLD=' \033[1m'
30+ NC=' \033[0m' # No Color
31+
32+ # List of repositories to monitor (format: "owner/repo")
33+ # Add your repositories here
34+ REPOSITORIES=(
35+ " NHSDigital/nhs-notify-repository-template"
36+ " NHSDigital/nhs-notify-devcontainers"
37+ # Add more repositories as needed
38+ )
39+
40+ # Function to check if required tools are available
41+ check_dependencies () {
42+ local missing_tools=()
43+
44+ if ! command -v curl & > /dev/null; then
45+ missing_tools+=(" curl" )
46+ fi
47+
48+ if ! command -v jq & > /dev/null; then
49+ missing_tools+=(" jq" )
50+ fi
51+
52+ if [ ${# missing_tools[@]} -ne 0 ]; then
53+ echo -e " ${RED} Error: Missing required tools: ${missing_tools[*]}${NC} "
54+ echo " Please install the missing tools and try again."
55+ return 1
56+ fi
57+
58+ return 0
59+ }
60+
61+ # Function to fetch repositories from GitHub organization with prefix filter
62+ fetch_repositories_from_org () {
63+ local org=" $1 "
64+ local prefix=" $2 "
65+ local repos=()
66+ local page=1
67+ local per_page=100
68+
69+ echo -e " ${CYAN} Fetching repositories from organization: $org with prefix: $prefix ${NC} " >&2
70+
71+ while true ; do
72+ local api_url=" $GITHUB_API_BASE /orgs/$org /repos?type=public&per_page=$per_page &page=$page "
73+ local repos_data
74+
75+ repos_data=$( github_api_request " $api_url " )
76+ if [ $? -ne 0 ]; then
77+ echo -e " ${RED} Failed to fetch repositories from organization: $org ${NC} " >&2
78+ return 1
79+ fi
80+
81+ # Check if we got any results
82+ local repo_count=$( echo " $repos_data " | jq ' . | length' )
83+ if [ " $repo_count " -eq 0 ]; then
84+ break
85+ fi
86+
87+ # Filter repositories by prefix and add to array
88+ local filtered_repos
89+ filtered_repos=$( echo " $repos_data " | jq -r " .[] | select(.name | startswith(\" $prefix \" )) | .full_name" )
90+
91+ while IFS= read -r repo; do
92+ if [ -n " $repo " ]; then
93+ repos+=(" $repo " )
94+ fi
95+ done <<< " $filtered_repos"
96+
97+ # If we got less than per_page results, we're on the last page
98+ if [ " $repo_count " -lt " $per_page " ]; then
99+ break
100+ fi
101+
102+ (( page++ ))
103+ done
104+
105+ if [ ${# repos[@]} -eq 0 ]; then
106+ echo -e " ${YELLOW} No repositories found in organization '$org ' with prefix '$prefix '${NC} " >&2
107+ return 1
108+ fi
109+
110+ echo -e " ${GREEN} Found ${# repos[@]} repositories matching prefix '$prefix '${NC} " >&2
111+
112+ # Output the repositories (one per line for easy parsing)
113+ printf " %s\n" " ${repos[@]} "
114+ return 0
115+ }
116+
117+ # Function to initialize repository list
118+ initialize_repositories () {
119+ local use_dynamic=" $1 "
120+ local github_org=" $2 "
121+ local repo_prefix=" $3 "
122+
123+ if [ " $use_dynamic " = " true" ]; then
124+ echo -e " ${CYAN} Using dynamic repository discovery...${NC} " >&2
125+
126+ local dynamic_repos
127+ dynamic_repos=$( fetch_repositories_from_org " $github_org " " $repo_prefix " )
128+
129+ if [ $? -eq 0 ] && [ -n " $dynamic_repos " ]; then
130+ # Convert newline-separated list to array
131+ mapfile -t REPOSITORIES <<< " $dynamic_repos"
132+ echo -e " ${GREEN} Successfully loaded ${# REPOSITORIES[@]} repositories dynamically${NC} " >&2
133+ else
134+ echo -e " ${YELLOW} Failed to fetch repositories dynamically, falling back to default list${NC} " >&2
135+ # Keep the default REPOSITORIES array as fallback
136+ fi
137+ else
138+ echo -e " ${CYAN} Using configured repository list${NC} " >&2
139+ fi
140+ }
141+
142+ # Function to make GitHub API request with error handling
143+ github_api_request () {
144+ local url=" $1 "
145+ local response
146+ local http_code
147+
148+ response=$( curl -s -w " HTTPSTATUS:%{http_code}" " $url " )
149+ http_code=$( echo " $response " | tr -d ' \n' | sed -e ' s/.*HTTPSTATUS://' )
150+ response=$( echo " $response " | sed -e ' s/HTTPSTATUS:.*//g' )
151+
152+ if [ " $http_code " -ne 200 ]; then
153+ echo -e " ${RED} API request failed with status $http_code for: $url ${NC} " >&2
154+ return 1
155+ fi
156+
157+ echo " $response "
158+ return 0
159+ }
160+
161+ # Function to format date for better readability
162+ format_date () {
163+ local iso_date=" $1 "
164+ if command -v date & > /dev/null; then
165+ # Try to format the date nicely
166+ if date -d " $iso_date " " +%Y-%m-%d %H:%M" 2> /dev/null; then
167+ return 0
168+ else
169+ # Fallback for systems where -d doesn't work (like macOS)
170+ echo " $iso_date " | cut -d' T' -f1,2 | tr ' T' ' ' | cut -d' :' -f1,2
171+ fi
172+ else
173+ echo " $iso_date "
174+ fi
175+ }
176+
177+ # Function to get recent commits for a repository
178+ get_recent_commits () {
179+ local repo=" $1 "
180+ local count=" ${2:- $DEFAULT_COMMIT_COUNT } "
181+
182+ echo -e " ${CYAN} 📝 Recent commits for ${BOLD} $repo ${NC}${CYAN} :${NC} "
183+
184+ local commits_data
185+ commits_data=$( github_api_request " $GITHUB_API_BASE /repos/$repo /commits?per_page=$count " )
186+
187+ if [ $? -ne 0 ]; then
188+ echo -e " ${RED} Failed to fetch commits${NC} "
189+ return 1
190+ fi
191+
192+ if [ " $commits_data " = " []" ] || [ -z " $commits_data " ]; then
193+ echo -e " ${YELLOW} No commits found${NC} "
194+ return 0
195+ fi
196+
197+ # Parse and display commits
198+ echo " $commits_data " | jq -r ' .[] | " \(.sha[0:7]) \(.commit.author.date) \(.commit.author.name): \(.commit.message | split("\n")[0])"' | while read -r commit_line; do
199+ local sha=$( echo " $commit_line " | awk ' {print $1}' )
200+ local date=$( echo " $commit_line " | awk ' {print $2}' )
201+ local author_and_message=$( echo " $commit_line " | cut -d' ' -f4-)
202+
203+ local formatted_date=$( format_date " $date " )
204+ echo -e " ${GREEN} $sha ${NC} ${BLUE} $formatted_date ${NC} $author_and_message "
205+ done
206+
207+ echo
208+ }
209+
210+ # Function to get open pull requests for a repository
211+ get_open_prs () {
212+ local repo=" $1 "
213+
214+ echo -e " ${PURPLE} 🔀 Open pull requests for ${BOLD} $repo ${NC}${PURPLE} :${NC} "
215+
216+ local prs_data
217+ prs_data=$( github_api_request " $GITHUB_API_BASE /repos/$repo /pulls?state=open" )
218+
219+ if [ $? -ne 0 ]; then
220+ echo -e " ${RED} Failed to fetch pull requests${NC} "
221+ return 1
222+ fi
223+
224+ if [ " $prs_data " = " []" ] || [ -z " $prs_data " ]; then
225+ echo -e " ${YELLOW} No open pull requests${NC} "
226+ echo
227+ return 0
228+ fi
229+
230+ # Parse and display PRs
231+ echo " $prs_data " | jq -r ' .[] | "#\(.number) \(.created_at) \(.user.login): \(.title)"' | while read -r pr_line; do
232+ local pr_number=$( echo " $pr_line " | awk ' {print $1}' )
233+ local date=$( echo " $pr_line " | awk ' {print $2}' )
234+ local author_and_title=$( echo " $pr_line " | cut -d' ' -f4-)
235+
236+ local formatted_date=$( format_date " $date " )
237+ echo -e " ${YELLOW} $pr_number ${NC} ${BLUE} $formatted_date ${NC} $author_and_title "
238+ done
239+
240+ echo
241+ }
242+
243+ # Function to display repository information
244+ show_repo_info () {
245+ local repo=" $1 "
246+ local commit_count=" ${2:- $DEFAULT_COMMIT_COUNT } "
247+
248+ echo -e " ${WHITE}${BOLD} ═══════════════════════════════════════════════════════════════════════════════${NC} "
249+ echo -e " ${WHITE}${BOLD} Repository: $repo ${NC} "
250+ echo -e " ${WHITE}${BOLD} ═══════════════════════════════════════════════════════════════════════════════${NC} "
251+ echo
252+
253+ get_recent_commits " $repo " " $commit_count "
254+ get_open_prs " $repo "
255+ }
256+
257+ # Function to display help
258+ show_help () {
259+ echo " GitHub Repository Monitor"
260+ echo
261+ echo " Usage: $0 [OPTIONS]"
262+ echo
263+ echo " Options:"
264+ echo " -c, --commits NUM Number of recent commits to show (default: $DEFAULT_COMMIT_COUNT )"
265+ echo " -r, --repo REPO Monitor specific repository (format: owner/repo)"
266+ echo " -o, --org ORG GitHub organization for dynamic discovery (default: $DEFAULT_GITHUB_ORG )"
267+ echo " -p, --prefix PREFIX Repository name prefix filter (default: $DEFAULT_REPO_PREFIX )"
268+ echo " -d, --dynamic Use dynamic repository discovery instead of configured list"
269+ echo " -l, --list List configured/discovered repositories"
270+ echo " -h, --help Show this help message"
271+ echo
272+ echo " Examples:"
273+ echo " $0 # Monitor configured repositories"
274+ echo " $0 -c 10 # Show 10 recent commits for each repo"
275+ echo " $0 -r NHSDigital/nhs-notify-template # Monitor only specific repository"
276+ echo " $0 -d # Auto-discover repos with default settings"
277+ echo " $0 -d -p nhs-notify-web # Discover repos with 'nhs-notify-web' prefix"
278+ echo " $0 -d -o MyOrg -p api # Discover 'api*' repos in 'MyOrg' organization"
279+ echo " $0 -d -l # List discovered repositories"
280+ echo
281+ }
282+
283+ # Function to list configured repositories
284+ list_repositories () {
285+ echo " Configured repositories:"
286+ for repo in " ${REPOSITORIES[@]} " ; do
287+ echo " - $repo "
288+ done
289+ }
290+
291+ # Main function
292+ main () {
293+ local commit_count=$DEFAULT_COMMIT_COUNT
294+ local specific_repo=" "
295+ local github_org=" $DEFAULT_GITHUB_ORG "
296+ local repo_prefix=" $DEFAULT_REPO_PREFIX "
297+ local use_dynamic=" false"
298+ local list_only=" false"
299+
300+ # Parse command line arguments
301+ while [[ $# -gt 0 ]]; do
302+ case $1 in
303+ -c|--commits)
304+ commit_count=" $2 "
305+ if ! [[ " $commit_count " =~ ^[0-9]+$ ]]; then
306+ echo -e " ${RED} Error: Commit count must be a number${NC} "
307+ exit 1
308+ fi
309+ shift 2
310+ ;;
311+ -r|--repo)
312+ specific_repo=" $2 "
313+ shift 2
314+ ;;
315+ -o|--org)
316+ github_org=" $2 "
317+ shift 2
318+ ;;
319+ -p|--prefix)
320+ repo_prefix=" $2 "
321+ shift 2
322+ ;;
323+ -d|--dynamic)
324+ use_dynamic=" true"
325+ shift
326+ ;;
327+ -l|--list)
328+ list_only=" true"
329+ shift
330+ ;;
331+ -h|--help)
332+ show_help
333+ exit 0
334+ ;;
335+ * )
336+ echo -e " ${RED} Unknown option: $1 ${NC} "
337+ show_help
338+ exit 1
339+ ;;
340+ esac
341+ done
342+
343+ # Check dependencies
344+ if ! check_dependencies; then
345+ exit 1
346+ fi
347+
348+ # Handle list-only mode
349+ if [ " $list_only " = " true" ]; then
350+ initialize_repositories " $use_dynamic " " $github_org " " $repo_prefix "
351+ list_repositories
352+ exit 0
353+ fi
354+
355+ # Initialize repository list (may fetch dynamically)
356+ initialize_repositories " $use_dynamic " " $github_org " " $repo_prefix "
357+
358+ echo -e " ${CYAN}${BOLD} GitHub Repository Monitor${NC} "
359+ echo -e " ${CYAN} Monitoring repositories for recent activity...${NC} "
360+ echo
361+
362+ # Monitor specific repository or all configured repositories
363+ if [ -n " $specific_repo " ]; then
364+ show_repo_info " $specific_repo " " $commit_count "
365+ else
366+ if [ ${# REPOSITORIES[@]} -eq 0 ]; then
367+ echo -e " ${YELLOW} No repositories configured. Please edit the script to add repositories.${NC} "
368+ exit 1
369+ fi
370+
371+ for repo in " ${REPOSITORIES[@]} " ; do
372+ show_repo_info " $repo " " $commit_count "
373+ done
374+ fi
375+
376+ echo -e " ${GREEN}${BOLD} Monitoring complete!${NC} "
377+ }
378+
379+ # Run the main function with all arguments
380+ main " $@ "
0 commit comments