Signed-off-by: Max <ai-agent@topdoglabs.com>
This commit is contained in:
parent
75aef25ba3
commit
c571130029
278
scripts/sprint-auto-status.sh
Executable file
278
scripts/sprint-auto-status.sh
Executable file
@ -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
|
||||||
Loading…
Reference in New Issue
Block a user