gantt-board/scripts/sprint-auto-status.sh

278 lines
7.4 KiB
Bash
Executable File

#!/bin/bash
# Sprint Auto-Status and Rollover Script
# Updates sprint statuses based on current date and rolls over incomplete tasks
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/lib/api_client.sh"
TODAY=$(date +%Y-%m-%d)
LOG_FILE="${LOG_FILE:-/tmp/sprint-auto-status.log}"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
# Get current date in ISO format
get_today() {
date +%Y-%m-%d
}
# Get all sprints
get_all_sprints() {
api_call GET "/sprints" | jq -r '.sprints // []'
}
# Determine what status a sprint should have based on date
get_sprint_target_status() {
local start_date="$1"
local end_date="$2"
local today="${3:-$(get_today)}"
if [[ "$today" < "$start_date" ]]; then
echo "planning"
elif [[ "$today" > "$end_date" ]]; then
echo "completed"
else
echo "active"
fi
}
# Update sprint status
update_sprint_status() {
local sprint_id="$1"
local new_status="$2"
log "Updating sprint $sprint_id to status: $new_status"
local payload
payload=$(jq -n --arg id "$sprint_id" --arg status "$new_status" '{id: $id, status: $status}')
if api_call PATCH "/sprints" "$payload" > /dev/null 2>&1; then
log "✓ Successfully updated sprint $sprint_id to $new_status"
return 0
else
log "✗ Failed to update sprint $sprint_id"
return 1
fi
}
# Get incomplete tasks for a sprint (status not in done, canceled, closed)
get_incomplete_tasks() {
local sprint_id="$1"
api_call GET "/tasks?scope=all" | \
jq --arg sid "$sprint_id" '
.tasks
| map(select(
.sprintId == $sid
and (.status != "done" and .status != "canceled" and .status != "closed" and .status != "archived")
))
'
}
# Get current active sprint (the one containing today)
get_current_active_sprint() {
local today="${1:-$(get_today)}"
api_call GET "/sprints" | \
jq --arg today "$today" '
.sprints
| map(select(.start_date <= $today and .end_date >= $today))
| .[0]
'
}
# Move task to new sprint
move_task_to_sprint() {
local task_id="$1"
local new_sprint_id="$2"
local old_sprint_name="$3"
log "Moving task $task_id to sprint $new_sprint_id (from $old_sprint_name)"
# Get existing task
local task
task=$(api_call GET "/tasks?taskId=$(urlencode "$task_id")&include=detail" | jq '.tasks[0]')
if [[ -z "$task" || "$task" == "null" ]]; then
log "✗ Task $task_id not found"
return 1
fi
# Update sprint ID and add comment
local now
now=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
local comment
comment="Auto-rolled over from $old_sprint_name on $(get_today)"
local updated_task
updated_task=$(echo "$task" | \
jq --arg sid "$new_sprint_id" \
--arg comment "$comment" \
--arg createdAt "$now" \
--arg commentId "$(date +%s)-$RANDOM" '
.sprintId = $sid |
.comments = (.comments // []) + [{
id: $commentId,
text: $comment,
createdAt: $createdAt,
commentAuthorId: "system",
replies: []
}]
')
if api_call POST "/tasks" "{\"task\": $updated_task}" > /dev/null 2>&1; then
log "✓ Successfully moved task $task_id"
return 0
else
log "✗ Failed to move task $task_id"
return 1
fi
}
# Main function to process sprint updates
process_sprint_updates() {
log "=== Starting Sprint Auto-Status Update ==="
log "Today: $(get_today)"
# Get all sprints
local sprints
sprints=$(get_all_sprints)
if [[ -z "$sprints" || "$sprints" == "[]" ]]; then
log "No sprints found"
return 0
fi
local updated_count=0
local rollover_count=0
# Process each sprint
while IFS= read -r sprint; do
[[ -z "$sprint" ]] && continue
local sprint_id
local current_status
local start_date
local end_date
local sprint_name
sprint_id=$(echo "$sprint" | jq -r '.id // empty')
current_status=$(echo "$sprint" | jq -r '.status // empty')
start_date=$(echo "$sprint" | jq -r '.start_date // .startDate // empty')
end_date=$(echo "$sprint" | jq -r '.end_date // .endDate // empty')
sprint_name=$(echo "$sprint" | jq -r '.name // "Unnamed"')
[[ -z "$sprint_id" ]] && continue
# Determine target status
local target_status
target_status=$(get_sprint_target_status "$start_date" "$end_date")
log "Sprint: $sprint_name (ID: $sprint_id) - Current: $current_status, Target: $target_status"
# Update if different
if [[ "$current_status" != "$target_status" ]]; then
if update_sprint_status "$sprint_id" "$target_status"; then
((updated_count++))
# If sprint was just completed, roll over incomplete tasks
if [[ "$target_status" == "completed" ]]; then
log "Sprint $sprint_name completed - checking for tasks to roll over"
# Get the new current sprint
local current_sprint
current_sprint=$(get_current_active_sprint)
if [[ -n "$current_sprint" && "$current_sprint" != "null" ]]; then
local new_sprint_id
new_sprint_id=$(echo "$current_sprint" | jq -r '.id')
# Get incomplete tasks
local incomplete_tasks
incomplete_tasks=$(get_incomplete_tasks "$sprint_id")
local task_count
task_count=$(echo "$incomplete_tasks" | jq 'length')
if [[ "$task_count" -gt 0 ]]; then
log "Found $task_count incomplete tasks to roll over"
# Move each task
while IFS= read -r task_id; do
[[ -z "$task_id" ]] && continue
if move_task_to_sprint "$task_id" "$new_sprint_id" "$sprint_name"; then
((rollover_count++))
fi
done < <(echo "$incomplete_tasks" | jq -r '.[].id' 2>/dev/null)
else
log "No incomplete tasks found"
fi
else
log "Warning: No current active sprint found for rollover"
fi
fi
fi
else
log "Status is correct, no update needed"
fi
done < <(echo "$sprints" | jq -c '.[]' 2>/dev/null)
log "=== Sprint Update Complete ==="
log "Updated: $updated_count sprints"
log "Rolled over: $rollover_count tasks"
return 0
}
# Show help
show_help() {
cat << 'HELP'
Sprint Auto-Status and Rollover Script
USAGE:
./sprint-auto-status.sh [command]
COMMANDS:
run Run the auto-status update and rollover process
dry-run Show what would happen without making changes
cleanup Clean up old log files
help Show this help message
ENVIRONMENT:
LOG_FILE Path to log file (default: /tmp/sprint-auto-status.log)
API_URL Gantt Board API URL (default: http://localhost:3000/api)
EXAMPLES:
./sprint-auto-status.sh run
LOG_FILE=/var/log/sprint-status.log ./sprint-auto-status.sh run
HELP
}
# Main execution
case "${1:-}" in
run)
process_sprint_updates
;;
dry-run)
log "=== DRY RUN MODE - No changes will be made ==="
# In dry-run mode, we'd print what would happen
log "Would check all sprints and update statuses based on $(get_today)"
log "Would roll over incomplete tasks from completed sprints"
;;
cleanup)
rm -f /tmp/sprint-auto-status.log
log "Cleaned up log files"
;;
help|--help|-h|"")
show_help
;;
*)
log_error "Unknown command: $1"
show_help
exit 1
;;
esac