@cloudkinetix/bmad-enhanced
Version:
Cloud-Kinetix enhanced fork of BMAD-METHOD - Breakthrough Method of Agile AI-driven Development with robust versioning and unified validation.
366 lines (295 loc) âĸ 11 kB
Markdown
# CI Status Parser Utility
## Intelligent GitLab CI/CD Data Parsing and Formatting
This utility provides standardized parsing and formatting of GitLab CI/CD data for consistent consumption across the expansion pack and integration with other BMAD components.
## Core Parsing Functions
### Pipeline Status Parsing
#### Extract Pipeline Summary
```bash
# Parse pipeline data into standardized summary format
parse_pipeline_summary() {
local branch=${1:-$(git branch --show-current)}
local format=${2:-"standard"} # standard, json, csv, jira-comment
local PIPELINE_DATA=$(glab ci get --output json --branch "$branch" 2>/dev/null)
if [ $? -eq 0 ] && [ "$PIPELINE_DATA" != "" ]; then
# Extract core fields
local ID=$(echo "$PIPELINE_DATA" | jq -r '.id // "unknown"')
local STATUS=$(echo "$PIPELINE_DATA" | jq -r '.status // "unknown"')
local REF=$(echo "$PIPELINE_DATA" | jq -r '.ref // "unknown"')
local DURATION=$(echo "$PIPELINE_DATA" | jq -r '.duration // 0')
local WEB_URL=$(echo "$PIPELINE_DATA" | jq -r '.web_url // ""')
local CREATED_AT=$(echo "$PIPELINE_DATA" | jq -r '.created_at // ""')
local UPDATED_AT=$(echo "$PIPELINE_DATA" | jq -r '.updated_at // ""')
case "$format" in
"json")
echo "{\"id\":\"$ID\",\"status\":\"$STATUS\",\"ref\":\"$REF\",\"duration\":$DURATION,\"web_url\":\"$WEB_URL\",\"created_at\":\"$CREATED_AT\",\"updated_at\":\"$UPDATED_AT\"}"
;;
"csv")
echo "$ID,$STATUS,$REF,$DURATION,$WEB_URL,$CREATED_AT,$UPDATED_AT"
;;
"jira-comment")
echo "đ *CI Pipeline Status*"
echo ""
echo "âĸ *Status:* $STATUS"
echo "âĸ *Branch:* $REF"
echo "âĸ *Duration:* ${DURATION}s"
echo "âĸ *Pipeline:* [$ID|$WEB_URL]"
echo "âĸ *Updated:* $UPDATED_AT"
;;
*)
echo "Pipeline Summary:"
echo "=================="
echo "ID: $ID"
echo "Status: $STATUS"
echo "Branch: $REF"
echo "Duration: ${DURATION}s"
echo "URL: $WEB_URL"
echo "Created: $CREATED_AT"
echo "Updated: $UPDATED_AT"
;;
esac
else
case "$format" in
"json") echo '{"error":"no_pipeline_data"}' ;;
"csv") echo "error,no_pipeline_data,,,,,," ;;
*) echo "No pipeline data available for branch: $branch" ;;
esac
fi
}
```
#### Extract Job Status Summary
```bash
# Parse job statuses into organized summary
parse_job_summary() {
local branch=${1:-$(git branch --show-current)}
local format=${2:-"standard"}
local PIPELINE_DATA=$(glab ci get --output json --branch "$branch" 2>/dev/null)
if [ $? -eq 0 ] && [ "$PIPELINE_DATA" != "" ]; then
case "$format" in
"json")
echo "$PIPELINE_DATA" | jq -r '.jobs[] | {name: .name, status: .status, stage: .stage, duration: .duration}'
;;
"csv")
echo "name,status,stage,duration"
echo "$PIPELINE_DATA" | jq -r '.jobs[] | "\(.name),\(.status),\(.stage),\(.duration // 0)"'
;;
"jira-comment")
echo "đ *Job Status Summary*"
echo ""
# Group by status
local SUCCESS_JOBS=$(echo "$PIPELINE_DATA" | jq -r '.jobs[] | select(.status == "success") | .name' | wc -l)
local FAILED_JOBS=$(echo "$PIPELINE_DATA" | jq -r '.jobs[] | select(.status == "failed") | .name' | wc -l)
local RUNNING_JOBS=$(echo "$PIPELINE_DATA" | jq -r '.jobs[] | select(.status == "running") | .name' | wc -l)
local PENDING_JOBS=$(echo "$PIPELINE_DATA" | jq -r '.jobs[] | select(.status == "pending") | .name' | wc -l)
echo "âĸ â
Successful: $SUCCESS_JOBS"
echo "âĸ â Failed: $FAILED_JOBS"
echo "âĸ đ Running: $RUNNING_JOBS"
echo "âĸ âŗ Pending: $PENDING_JOBS"
# List failed jobs if any
if [ "$FAILED_JOBS" -gt 0 ]; then
echo ""
echo "*Failed Jobs:*"
echo "$PIPELINE_DATA" | jq -r '.jobs[] | select(.status == "failed") | "âĸ \(.name)"'
fi
;;
*)
echo "Job Status Summary:"
echo "=================="
echo "$PIPELINE_DATA" | jq -r '.jobs[] | "\(.name): \(.status) (\(.stage)) - \(.duration // 0)s"'
echo ""
echo "Status Counts:"
echo "$PIPELINE_DATA" | jq -r '.jobs[] | .status' | sort | uniq -c | sort -nr
;;
esac
else
case "$format" in
"json") echo '{"error":"no_job_data"}' ;;
"csv") echo "error,no_job_data,,," ;;
*) echo "No job data available for branch: $branch" ;;
esac
fi
}
```
### Status Conversion Functions
#### Convert Status to Emoji
```bash
# Convert CI status to emoji representation
status_to_emoji() {
local status="$1"
case "$status" in
"success"|"passed") echo "â
" ;;
"failed"|"failure") echo "â" ;;
"running"|"started") echo "đ" ;;
"pending"|"created") echo "âŗ" ;;
"canceled"|"cancelled") echo "âšī¸" ;;
"skipped") echo "âī¸" ;;
"manual") echo "đ¤" ;;
"scheduled") echo "đ
" ;;
*) echo "â" ;;
esac
}
```
#### Convert Status to Color Code
```bash
# Convert CI status to color codes for terminal output
status_to_color() {
local status="$1"
case "$status" in
"success"|"passed") echo "\033[0;32m" ;; # Green
"failed"|"failure") echo "\033[0;31m" ;; # Red
"running"|"started") echo "\033[0;34m" ;; # Blue
"pending"|"created") echo "\033[0;33m" ;; # Yellow
"canceled"|"cancelled") echo "\033[0;90m" ;; # Gray
"skipped") echo "\033[0;36m" ;; # Cyan
*) echo "\033[0m" ;; # Reset
esac
}
```
#### Convert Duration to Human Readable
```bash
# Convert duration seconds to human readable format
format_duration() {
local seconds="$1"
if [ "$seconds" = "null" ] || [ -z "$seconds" ] || [ "$seconds" = "0" ]; then
echo "0s"
return
fi
local hours=$((seconds / 3600))
local minutes=$(((seconds % 3600) / 60))
local secs=$((seconds % 60))
if [ "$hours" -gt 0 ]; then
echo "${hours}h ${minutes}m ${secs}s"
elif [ "$minutes" -gt 0 ]; then
echo "${minutes}m ${secs}s"
else
echo "${secs}s"
fi
}
```
## Integration-Specific Parsing
### JIRA Integration Formatting
```bash
# Format pipeline status for JIRA comment/description
format_for_jira() {
local branch=${1:-$(git branch --show-current)}
echo "h3. đ GitLab CI/CD Status"
echo ""
# Pipeline summary in JIRA format
parse_pipeline_summary "$branch" "jira-comment"
echo ""
# Job summary in JIRA format
parse_job_summary "$branch" "jira-comment"
echo ""
# Add timestamp
echo "_{color:gray}Last updated: $(date){color}_"
}
```
### Parallel Development Coordination Format
```bash
# Format CI status for parallel development coordination
format_for_parallel_dev() {
echo "Parallel Development CI Status"
echo "============================="
# Check multiple worktrees if they exist
if command -v git >/dev/null 2>&1; then
git worktree list 2>/dev/null | while read worktree_info; do
local WORKTREE_PATH=$(echo "$worktree_info" | awk '{print $1}')
local BRANCH=$(echo "$worktree_info" | awk '{print $3}' | tr -d '[]')
if [ -n "$BRANCH" ] && [ "$BRANCH" != "detached" ]; then
echo ""
echo "Branch: $BRANCH"
echo "Path: $WORKTREE_PATH"
# Get CI status for this branch
local STATUS=$(glab ci get --output json --branch "$BRANCH" 2>/dev/null | jq -r '.status // "no-pipeline"')
local EMOJI=$(status_to_emoji "$STATUS")
echo "CI Status: $EMOJI $STATUS"
# Show job summary if pipeline exists
if [ "$STATUS" != "no-pipeline" ]; then
local FAILED_COUNT=$(glab ci get --output json --branch "$BRANCH" 2>/dev/null | jq -r '.jobs[] | select(.status == "failed") | .name' | wc -l)
local TOTAL_COUNT=$(glab ci get --output json --branch "$BRANCH" 2>/dev/null | jq -r '.jobs[] | .name' | wc -l)
echo "Jobs: $((TOTAL_COUNT - FAILED_COUNT))/$TOTAL_COUNT passing"
fi
fi
done
else
echo "Git not available for worktree analysis"
fi
}
```
## Data Export Functions
### Export to CSV
```bash
# Export pipeline and job data to CSV format
export_to_csv() {
local branch=${1:-$(git branch --show-current)}
local output_file=${2:-"ci_status_$(date +%Y%m%d_%H%M%S).csv"}
echo "Exporting CI data to: $output_file"
# Pipeline header
echo "=== PIPELINE DATA ===" > "$output_file"
echo "id,status,ref,duration,web_url,created_at,updated_at" >> "$output_file"
parse_pipeline_summary "$branch" "csv" >> "$output_file"
# Job data
echo "" >> "$output_file"
echo "=== JOB DATA ===" >> "$output_file"
parse_job_summary "$branch" "csv" >> "$output_file"
echo "Export completed: $output_file"
}
```
### Export to JSON
```bash
# Export comprehensive CI data to JSON format
export_to_json() {
local branch=${1:-$(git branch --show-current)}
local output_file=${2:-"ci_status_$(date +%Y%m%d_%H%M%S).json"}
local PIPELINE_DATA=$(glab ci get --output json --branch "$branch" 2>/dev/null)
if [ $? -eq 0 ] && [ "$PIPELINE_DATA" != "" ]; then
# Add metadata
echo "{" > "$output_file"
echo " \"export_timestamp\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"," >> "$output_file"
echo " \"branch\": \"$branch\"," >> "$output_file"
echo " \"pipeline_data\": $PIPELINE_DATA" >> "$output_file"
echo "}" >> "$output_file"
echo "JSON export completed: $output_file"
else
echo "No pipeline data available for JSON export"
fi
}
```
## Health Check Functions
### Quick Status Check
```bash
# Quick one-line status check
quick_status() {
local branch=${1:-$(git branch --show-current)}
local STATUS=$(glab ci get --output json --branch "$branch" 2>/dev/null | jq -r '.status // "no-pipeline"')
local EMOJI=$(status_to_emoji "$STATUS")
local FAILED_JOBS=$(glab ci get --output json --branch "$branch" 2>/dev/null | jq -r '.jobs[] | select(.status == "failed") | .name' | wc -l)
if [ "$STATUS" = "no-pipeline" ]; then
echo "âĒ No pipeline found for branch: $branch"
elif [ "$FAILED_JOBS" -gt 0 ]; then
echo "$EMOJI $STATUS ($FAILED_JOBS failed jobs) - $branch"
else
echo "$EMOJI $STATUS - $branch"
fi
}
```
## Usage Examples
```bash
# Standard pipeline summary
parse_pipeline_summary main
# Job summary in JSON format
parse_job_summary develop json
# JIRA-formatted status
format_for_jira feature-branch
# Quick status check
quick_status
# Export to CSV
export_to_csv main ci_report.csv
# Parallel development status
format_for_parallel_dev
```
## Integration Notes
- **JIRA Integration**: Use format_for_jira() for JIRA comment updates
- **Parallel Development**: Use format_for_parallel_dev() for multi-worktree coordination
- **Automation**: All functions designed for non-interactive operation
- **Error Handling**: Graceful fallbacks for missing data
- **Format Flexibility**: Multiple output formats for different consumption needs