From c57113002988a3494cb57e02058397e32373e140 Mon Sep 17 00:00:00 2001 From: Max Date: Wed, 25 Feb 2026 08:13:55 -0600 Subject: [PATCH] Signed-off-by: Max --- scripts/sprint-auto-status.sh | 278 ++++++++++++++++++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100755 scripts/sprint-auto-status.sh diff --git a/scripts/sprint-auto-status.sh b/scripts/sprint-auto-status.sh new file mode 100755 index 0000000..b5b5dab --- /dev/null +++ b/scripts/sprint-auto-status.sh @@ -0,0 +1,278 @@ +#!/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 \ No newline at end of file