@pjmendonca/devflow 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/CHANGELOG.md +526 -0
  2. package/LICENSE +21 -0
  3. package/README.md +620 -0
  4. package/bin/devflow-checkpoint.js +10 -0
  5. package/bin/devflow-collab.js +10 -0
  6. package/bin/devflow-cost.js +10 -0
  7. package/bin/devflow-create-persona.js +10 -0
  8. package/bin/devflow-init.js +10 -0
  9. package/bin/devflow-memory.js +10 -0
  10. package/bin/devflow-new-doc.js +10 -0
  11. package/bin/devflow-personalize.js +10 -0
  12. package/bin/devflow-setup-checkpoint.js +10 -0
  13. package/bin/devflow-story.js +10 -0
  14. package/bin/devflow-tech-debt.js +10 -0
  15. package/bin/devflow-validate-overrides.js +10 -0
  16. package/bin/devflow-validate.js +10 -0
  17. package/bin/devflow-version.js +10 -0
  18. package/lib/constants.js +30 -0
  19. package/lib/exec-python.js +78 -0
  20. package/lib/python-check.js +178 -0
  21. package/package.json +64 -0
  22. package/tooling/.automation/agents/architect.md +135 -0
  23. package/tooling/.automation/agents/ba.md +70 -0
  24. package/tooling/.automation/agents/dev.md +79 -0
  25. package/tooling/.automation/agents/maintainer.md +97 -0
  26. package/tooling/.automation/agents/pm.md +116 -0
  27. package/tooling/.automation/agents/reviewer.md +141 -0
  28. package/tooling/.automation/agents/sm.md +61 -0
  29. package/tooling/.automation/agents/writer.md +193 -0
  30. package/tooling/.automation/config.ps1.template +61 -0
  31. package/tooling/.automation/config.sh.template +48 -0
  32. package/tooling/.automation/memory/.gitkeep +6 -0
  33. package/tooling/.automation/memory/knowledge/kg_integration-test.json +94 -0
  34. package/tooling/.automation/memory/knowledge/kg_test-story.json +300 -0
  35. package/tooling/.automation/memory/shared/shared_integration-test.json +30 -0
  36. package/tooling/.automation/memory/shared/shared_test-story.json +78 -0
  37. package/tooling/.automation/overrides/templates/README.md +113 -0
  38. package/tooling/.automation/overrides/templates/architect/README.md +27 -0
  39. package/tooling/.automation/overrides/templates/architect/cloud-native.yaml +92 -0
  40. package/tooling/.automation/overrides/templates/architect/enterprise-architect.yaml +85 -0
  41. package/tooling/.automation/overrides/templates/architect/pragmatic-minimalist.yaml +88 -0
  42. package/tooling/.automation/overrides/templates/ba/README.md +27 -0
  43. package/tooling/.automation/overrides/templates/ba/agile-storyteller.yaml +86 -0
  44. package/tooling/.automation/overrides/templates/ba/domain-expert.yaml +91 -0
  45. package/tooling/.automation/overrides/templates/ba/requirements-engineer.yaml +89 -0
  46. package/tooling/.automation/overrides/templates/dev/README.md +32 -0
  47. package/tooling/.automation/overrides/templates/dev/junior-mentored.yaml +39 -0
  48. package/tooling/.automation/overrides/templates/dev/performance-engineer.yaml +43 -0
  49. package/tooling/.automation/overrides/templates/dev/rapid-prototyper.yaml +52 -0
  50. package/tooling/.automation/overrides/templates/dev/security-focused.yaml +43 -0
  51. package/tooling/.automation/overrides/templates/dev/senior-fullstack.yaml +39 -0
  52. package/tooling/.automation/overrides/templates/maintainer/README.md +27 -0
  53. package/tooling/.automation/overrides/templates/maintainer/devops-maintainer.yaml +113 -0
  54. package/tooling/.automation/overrides/templates/maintainer/legacy-steward.yaml +94 -0
  55. package/tooling/.automation/overrides/templates/maintainer/oss-maintainer.yaml +94 -0
  56. package/tooling/.automation/overrides/templates/pm/README.md +27 -0
  57. package/tooling/.automation/overrides/templates/pm/agile-pm.yaml +91 -0
  58. package/tooling/.automation/overrides/templates/pm/hybrid-delivery.yaml +87 -0
  59. package/tooling/.automation/overrides/templates/pm/traditional-pm.yaml +91 -0
  60. package/tooling/.automation/overrides/templates/reviewer/README.md +11 -0
  61. package/tooling/.automation/overrides/templates/reviewer/mentoring-reviewer.yaml +45 -0
  62. package/tooling/.automation/overrides/templates/reviewer/quick-sanity.yaml +50 -0
  63. package/tooling/.automation/overrides/templates/reviewer/thorough-critic.yaml +48 -0
  64. package/tooling/.automation/overrides/templates/sm/README.md +11 -0
  65. package/tooling/.automation/overrides/templates/sm/agile-coach.yaml +52 -0
  66. package/tooling/.automation/overrides/templates/sm/startup-pm.yaml +50 -0
  67. package/tooling/.automation/overrides/templates/sm/technical-lead.yaml +47 -0
  68. package/tooling/.automation/overrides/templates/user-profile.template.yaml +62 -0
  69. package/tooling/.automation/overrides/templates/writer/README.md +27 -0
  70. package/tooling/.automation/overrides/templates/writer/api-documentarian.yaml +99 -0
  71. package/tooling/.automation/overrides/templates/writer/docs-as-code.yaml +108 -0
  72. package/tooling/.automation/overrides/templates/writer/user-guide-author.yaml +100 -0
  73. package/tooling/completions/DevflowCompletion.ps1 +213 -0
  74. package/tooling/completions/_run-story +116 -0
  75. package/tooling/completions/run-story-completion.bash +136 -0
  76. package/tooling/docs/DOC-STANDARD.md +717 -0
  77. package/tooling/docs/sprint-status.yaml.template +24 -0
  78. package/tooling/docs/templates/bug-report.md +234 -0
  79. package/tooling/docs/templates/migration-spec.md +274 -0
  80. package/tooling/docs/templates/refactor-spec.md +86 -0
  81. package/tooling/docs/templates/tech-debt.md +86 -0
  82. package/tooling/scripts/context_checkpoint.py +556 -0
  83. package/tooling/scripts/cost_dashboard.py +617 -0
  84. package/tooling/scripts/create-persona.py +690 -0
  85. package/tooling/scripts/create-persona.sh +435 -0
  86. package/tooling/scripts/init-project-workflow.ps1 +651 -0
  87. package/tooling/scripts/init-project-workflow.py +70 -0
  88. package/tooling/scripts/init-project-workflow.sh +746 -0
  89. package/tooling/scripts/lib/__init__.py +35 -0
  90. package/tooling/scripts/lib/agent_handoff.py +526 -0
  91. package/tooling/scripts/lib/agent_router.py +698 -0
  92. package/tooling/scripts/lib/checkpoint-integration.ps1 +245 -0
  93. package/tooling/scripts/lib/checkpoint-integration.sh +191 -0
  94. package/tooling/scripts/lib/claude-cli.ps1 +952 -0
  95. package/tooling/scripts/lib/claude-cli.sh +1293 -0
  96. package/tooling/scripts/lib/cost_config.py +222 -0
  97. package/tooling/scripts/lib/cost_display.py +443 -0
  98. package/tooling/scripts/lib/cost_tracker.py +710 -0
  99. package/tooling/scripts/lib/currency_converter.py +328 -0
  100. package/tooling/scripts/lib/errors.py +438 -0
  101. package/tooling/scripts/lib/override-loader.sh +286 -0
  102. package/tooling/scripts/lib/pair_programming.py +589 -0
  103. package/tooling/scripts/lib/shared_memory.py +637 -0
  104. package/tooling/scripts/lib/swarm_orchestrator.py +689 -0
  105. package/tooling/scripts/memory_summarize.py +324 -0
  106. package/tooling/scripts/new-doc.ps1 +405 -0
  107. package/tooling/scripts/new-doc.py +93 -0
  108. package/tooling/scripts/new-doc.sh +534 -0
  109. package/tooling/scripts/personalize_agent.py +385 -0
  110. package/tooling/scripts/rollback-migration.sh +540 -0
  111. package/tooling/scripts/run-collab.ps1 +251 -0
  112. package/tooling/scripts/run-collab.py +605 -0
  113. package/tooling/scripts/run-collab.sh +110 -0
  114. package/tooling/scripts/run-story.ps1 +490 -0
  115. package/tooling/scripts/run-story.py +387 -0
  116. package/tooling/scripts/run-story.sh +467 -0
  117. package/tooling/scripts/setup-checkpoint-service.ps1 +219 -0
  118. package/tooling/scripts/setup-checkpoint-service.py +87 -0
  119. package/tooling/scripts/setup-checkpoint-service.sh +236 -0
  120. package/tooling/scripts/tech-debt-tracker.py +608 -0
  121. package/tooling/scripts/update_version.py +244 -0
  122. package/tooling/scripts/validate-overrides.py +511 -0
  123. package/tooling/scripts/validate-overrides.sh +432 -0
  124. package/tooling/scripts/validate_setup.py +539 -0
@@ -0,0 +1,540 @@
1
+ #!/usr/bin/env bash
2
+ ################################################################################
3
+ # Rollback Migration - Automated Migration Rollback
4
+ #
5
+ # This script provides automated rollback capabilities for migrations.
6
+ # It can:
7
+ # - Create rollback checkpoints before migrations
8
+ # - Execute rollback steps defined in migration specs
9
+ # - Restore from git-based checkpoints
10
+ # - Handle dependency rollbacks
11
+ #
12
+ # Usage:
13
+ # ./rollback-migration.sh <migration-id> # Rollback a migration
14
+ # ./rollback-migration.sh <migration-id> --dry-run # Preview rollback
15
+ # ./rollback-migration.sh <migration-id> --force # Force rollback
16
+ # ./rollback-migration.sh --list # List rollback points
17
+ # ./rollback-migration.sh --create <name> # Create rollback point
18
+ #
19
+ ################################################################################
20
+
21
+ set -e
22
+
23
+ # Colors
24
+ RED='\033[0;31m'
25
+ GREEN='\033[0;32m'
26
+ YELLOW='\033[1;33m'
27
+ BLUE='\033[0;34m'
28
+ CYAN='\033[0;36m'
29
+ BOLD='\033[1m'
30
+ NC='\033[0m'
31
+
32
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
33
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
34
+ ROLLBACK_DIR="$PROJECT_ROOT/.automation/rollbacks"
35
+ CHECKPOINTS_DIR="$PROJECT_ROOT/.automation/checkpoints"
36
+ MIGRATIONS_DIR="$PROJECT_ROOT/docs/migrations"
37
+
38
+ ################################################################################
39
+ # Helper Functions
40
+ ################################################################################
41
+
42
+ print_header() {
43
+ echo ""
44
+ echo -e "${CYAN}═══════════════════════════════════════════════════════════════${NC}"
45
+ echo -e "${CYAN} MIGRATION ROLLBACK TOOL${NC}"
46
+ echo -e "${CYAN}═══════════════════════════════════════════════════════════════${NC}"
47
+ echo ""
48
+ }
49
+
50
+ error() {
51
+ echo -e "${RED}✗ ERROR:${NC} $1"
52
+ exit 1
53
+ }
54
+
55
+ warning() {
56
+ echo -e "${YELLOW}⚠ WARNING:${NC} $1"
57
+ }
58
+
59
+ success() {
60
+ echo -e "${GREEN}✓${NC} $1"
61
+ }
62
+
63
+ info() {
64
+ echo -e "${BLUE}ℹ${NC} $1"
65
+ }
66
+
67
+ confirm() {
68
+ local message="$1"
69
+ echo -e "${YELLOW}$message${NC}"
70
+ echo -n "Continue? [y/N] "
71
+ read -r response
72
+ [[ "$response" =~ ^[Yy]$ ]]
73
+ }
74
+
75
+ ################################################################################
76
+ # Rollback Point Management
77
+ ################################################################################
78
+
79
+ # Create a rollback point
80
+ create_rollback_point() {
81
+ local name="$1"
82
+ local timestamp=$(date '+%Y%m%d_%H%M%S')
83
+ local rollback_name="${timestamp}_${name}"
84
+ local rollback_path="$ROLLBACK_DIR/$rollback_name"
85
+
86
+ mkdir -p "$rollback_path"
87
+
88
+ echo -e "${CYAN}Creating rollback point: $rollback_name${NC}"
89
+
90
+ # Save git state
91
+ local current_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
92
+ local current_commit=$(git rev-parse HEAD 2>/dev/null || echo "unknown")
93
+ local has_changes=$(git status --porcelain 2>/dev/null | wc -l | tr -d ' ')
94
+
95
+ # Create manifest
96
+ cat > "$rollback_path/manifest.json" << EOF
97
+ {
98
+ "name": "$name",
99
+ "created": "$(date -Iseconds)",
100
+ "branch": "$current_branch",
101
+ "commit": "$current_commit",
102
+ "has_uncommitted_changes": $([[ $has_changes -gt 0 ]] && echo "true" || echo "false"),
103
+ "type": "migration-rollback"
104
+ }
105
+ EOF
106
+
107
+ # Save uncommitted changes if any
108
+ if [[ $has_changes -gt 0 ]]; then
109
+ info "Saving uncommitted changes..."
110
+ git stash push -m "rollback-$rollback_name" --include-untracked 2>/dev/null || true
111
+ git stash show -p > "$rollback_path/uncommitted.patch" 2>/dev/null || true
112
+ git stash pop 2>/dev/null || true
113
+ fi
114
+
115
+ # Save package state
116
+ if [[ -f "$PROJECT_ROOT/package.json" ]]; then
117
+ cp "$PROJECT_ROOT/package.json" "$rollback_path/"
118
+ info "Saved package.json"
119
+ fi
120
+
121
+ if [[ -f "$PROJECT_ROOT/package-lock.json" ]]; then
122
+ cp "$PROJECT_ROOT/package-lock.json" "$rollback_path/"
123
+ info "Saved package-lock.json"
124
+ fi
125
+
126
+ if [[ -f "$PROJECT_ROOT/pubspec.yaml" ]]; then
127
+ cp "$PROJECT_ROOT/pubspec.yaml" "$rollback_path/"
128
+ info "Saved pubspec.yaml"
129
+ fi
130
+
131
+ if [[ -f "$PROJECT_ROOT/pubspec.lock" ]]; then
132
+ cp "$PROJECT_ROOT/pubspec.lock" "$rollback_path/"
133
+ info "Saved pubspec.lock"
134
+ fi
135
+
136
+ if [[ -f "$PROJECT_ROOT/requirements.txt" ]]; then
137
+ cp "$PROJECT_ROOT/requirements.txt" "$rollback_path/"
138
+ info "Saved requirements.txt"
139
+ fi
140
+
141
+ success "Rollback point created: $rollback_path"
142
+ echo "$rollback_name"
143
+ }
144
+
145
+ # List available rollback points
146
+ list_rollback_points() {
147
+ echo -e "${BOLD}Available Rollback Points:${NC}"
148
+ echo ""
149
+
150
+ if [[ ! -d "$ROLLBACK_DIR" ]] || [[ -z "$(ls -A "$ROLLBACK_DIR" 2>/dev/null)" ]]; then
151
+ info "No rollback points found."
152
+ return 0
153
+ fi
154
+
155
+ printf "%-25s %-20s %-15s %s\n" "NAME" "CREATED" "COMMIT" "BRANCH"
156
+ printf "%s\n" "$(printf '─%.0s' {1..80})"
157
+
158
+ for dir in "$ROLLBACK_DIR"/*/; do
159
+ if [[ -d "$dir" ]]; then
160
+ local name=$(basename "$dir")
161
+ local manifest="$dir/manifest.json"
162
+
163
+ if [[ -f "$manifest" ]]; then
164
+ local created=$(grep '"created"' "$manifest" | sed 's/.*: *"\([^"]*\)".*/\1/' | cut -c1-19)
165
+ local commit=$(grep '"commit"' "$manifest" | sed 's/.*: *"\([^"]*\)".*/\1/' | cut -c1-8)
166
+ local branch=$(grep '"branch"' "$manifest" | sed 's/.*: *"\([^"]*\)".*/\1/')
167
+
168
+ printf "%-25s %-20s %-15s %s\n" "$name" "$created" "$commit" "$branch"
169
+ fi
170
+ fi
171
+ done
172
+ echo ""
173
+ }
174
+
175
+ # Delete old rollback points (keep last N)
176
+ cleanup_rollback_points() {
177
+ local keep="${1:-10}"
178
+
179
+ if [[ ! -d "$ROLLBACK_DIR" ]]; then
180
+ return 0
181
+ fi
182
+
183
+ local count=$(ls -d "$ROLLBACK_DIR"/*/ 2>/dev/null | wc -l | tr -d ' ')
184
+
185
+ if [[ $count -gt $keep ]]; then
186
+ local to_delete=$((count - keep))
187
+ info "Cleaning up $to_delete old rollback point(s)..."
188
+
189
+ ls -d "$ROLLBACK_DIR"/*/ 2>/dev/null | head -n "$to_delete" | while read dir; do
190
+ rm -rf "$dir"
191
+ success "Deleted: $(basename "$dir")"
192
+ done
193
+ fi
194
+ }
195
+
196
+ ################################################################################
197
+ # Rollback Execution
198
+ ################################################################################
199
+
200
+ # Find migration spec file
201
+ find_migration_spec() {
202
+ local migration_id="$1"
203
+
204
+ # Search in common locations
205
+ local search_paths=(
206
+ "$MIGRATIONS_DIR/${migration_id}.md"
207
+ "$PROJECT_ROOT/docs/${migration_id}.md"
208
+ "$PROJECT_ROOT/tooling/docs/migrations/${migration_id}.md"
209
+ )
210
+
211
+ for path in "${search_paths[@]}"; do
212
+ if [[ -f "$path" ]]; then
213
+ echo "$path"
214
+ return 0
215
+ fi
216
+ done
217
+
218
+ # Search by pattern
219
+ local found=$(find "$PROJECT_ROOT" -name "*${migration_id}*.md" -path "*/migrations/*" 2>/dev/null | head -1)
220
+ if [[ -n "$found" ]]; then
221
+ echo "$found"
222
+ return 0
223
+ fi
224
+
225
+ return 1
226
+ }
227
+
228
+ # Parse rollback steps from migration spec
229
+ parse_rollback_steps() {
230
+ local spec_file="$1"
231
+
232
+ # Extract rollback steps section
233
+ awk '/^### Rollback Steps/,/^##[^#]/' "$spec_file" 2>/dev/null | \
234
+ grep -E '^\s*[0-9]+\.' | \
235
+ sed 's/^\s*[0-9]*\.\s*//'
236
+ }
237
+
238
+ # Execute git-based rollback
239
+ rollback_to_commit() {
240
+ local commit="$1"
241
+ local dry_run="$2"
242
+
243
+ if [[ "$dry_run" == "true" ]]; then
244
+ info "Would reset to commit: $commit"
245
+ git log --oneline -1 "$commit"
246
+ return 0
247
+ fi
248
+
249
+ info "Rolling back to commit: $commit"
250
+
251
+ # Check for uncommitted changes
252
+ if [[ -n "$(git status --porcelain)" ]]; then
253
+ warning "You have uncommitted changes. These will be stashed."
254
+ git stash push -m "pre-rollback-$(date +%s)"
255
+ fi
256
+
257
+ # Perform rollback
258
+ git checkout "$commit" -- .
259
+ success "Rolled back to commit: $commit"
260
+ }
261
+
262
+ # Rollback from a rollback point
263
+ rollback_from_point() {
264
+ local point_name="$1"
265
+ local dry_run="$2"
266
+ local point_path="$ROLLBACK_DIR/$point_name"
267
+
268
+ if [[ ! -d "$point_path" ]]; then
269
+ error "Rollback point not found: $point_name"
270
+ fi
271
+
272
+ local manifest="$point_path/manifest.json"
273
+ if [[ ! -f "$manifest" ]]; then
274
+ error "Invalid rollback point (no manifest): $point_name"
275
+ fi
276
+
277
+ local commit=$(grep '"commit"' "$manifest" | sed 's/.*: *"\([^"]*\)".*/\1/')
278
+
279
+ echo ""
280
+ info "Rollback Point Details:"
281
+ cat "$manifest" | grep -E '"(name|created|branch|commit)"' | sed 's/^/ /'
282
+ echo ""
283
+
284
+ if [[ "$dry_run" == "true" ]]; then
285
+ info "[DRY RUN] Would restore from rollback point: $point_name"
286
+
287
+ if [[ -f "$point_path/package.json" ]]; then
288
+ info "[DRY RUN] Would restore package.json"
289
+ fi
290
+ if [[ -f "$point_path/pubspec.yaml" ]]; then
291
+ info "[DRY RUN] Would restore pubspec.yaml"
292
+ fi
293
+
294
+ return 0
295
+ fi
296
+
297
+ if ! confirm "This will rollback to the saved state. Continue?"; then
298
+ info "Rollback cancelled."
299
+ return 0
300
+ fi
301
+
302
+ # Restore files
303
+ if [[ -f "$point_path/package.json" ]]; then
304
+ cp "$point_path/package.json" "$PROJECT_ROOT/"
305
+ success "Restored package.json"
306
+ fi
307
+
308
+ if [[ -f "$point_path/package-lock.json" ]]; then
309
+ cp "$point_path/package-lock.json" "$PROJECT_ROOT/"
310
+ success "Restored package-lock.json"
311
+ fi
312
+
313
+ if [[ -f "$point_path/pubspec.yaml" ]]; then
314
+ cp "$point_path/pubspec.yaml" "$PROJECT_ROOT/"
315
+ success "Restored pubspec.yaml"
316
+ fi
317
+
318
+ if [[ -f "$point_path/pubspec.lock" ]]; then
319
+ cp "$point_path/pubspec.lock" "$PROJECT_ROOT/"
320
+ success "Restored pubspec.lock"
321
+ fi
322
+
323
+ if [[ -f "$point_path/requirements.txt" ]]; then
324
+ cp "$point_path/requirements.txt" "$PROJECT_ROOT/"
325
+ success "Restored requirements.txt"
326
+ fi
327
+
328
+ # Rollback git if commit is available
329
+ if [[ -n "$commit" && "$commit" != "unknown" ]]; then
330
+ info "Rolling back git state..."
331
+ rollback_to_commit "$commit" "false"
332
+ fi
333
+
334
+ # Reinstall dependencies
335
+ echo ""
336
+ info "Dependencies may need to be reinstalled:"
337
+ if [[ -f "$PROJECT_ROOT/package.json" ]]; then
338
+ echo " npm install"
339
+ fi
340
+ if [[ -f "$PROJECT_ROOT/pubspec.yaml" ]]; then
341
+ echo " flutter pub get"
342
+ fi
343
+ if [[ -f "$PROJECT_ROOT/requirements.txt" ]]; then
344
+ echo " pip install -r requirements.txt"
345
+ fi
346
+
347
+ echo ""
348
+ success "Rollback complete!"
349
+ }
350
+
351
+ # Main rollback function for migrations
352
+ rollback_migration() {
353
+ local migration_id="$1"
354
+ local dry_run="$2"
355
+ local force="$3"
356
+
357
+ echo -e "${BOLD}Rolling back migration: $migration_id${NC}"
358
+ echo ""
359
+
360
+ # Look for a rollback point for this migration
361
+ local rollback_point=$(ls -d "$ROLLBACK_DIR"/*"$migration_id"* 2>/dev/null | tail -1)
362
+
363
+ if [[ -n "$rollback_point" && -d "$rollback_point" ]]; then
364
+ info "Found rollback point: $(basename "$rollback_point")"
365
+ rollback_from_point "$(basename "$rollback_point")" "$dry_run"
366
+ return 0
367
+ fi
368
+
369
+ # Look for migration spec with rollback instructions
370
+ local spec_file=$(find_migration_spec "$migration_id")
371
+
372
+ if [[ -n "$spec_file" ]]; then
373
+ info "Found migration spec: $spec_file"
374
+
375
+ local steps=$(parse_rollback_steps "$spec_file")
376
+
377
+ if [[ -n "$steps" ]]; then
378
+ echo ""
379
+ echo -e "${BOLD}Rollback Steps:${NC}"
380
+ echo "$steps" | nl
381
+ echo ""
382
+
383
+ if [[ "$dry_run" == "true" ]]; then
384
+ info "[DRY RUN] Would execute the above rollback steps"
385
+ return 0
386
+ fi
387
+
388
+ if ! confirm "Execute these rollback steps?"; then
389
+ info "Rollback cancelled."
390
+ return 0
391
+ fi
392
+
393
+ # Execute steps (basic implementation - just displays them)
394
+ info "Please execute the following steps manually:"
395
+ echo "$steps" | nl
396
+ else
397
+ warning "No rollback steps found in migration spec"
398
+ fi
399
+ else
400
+ warning "No migration spec found for: $migration_id"
401
+ fi
402
+
403
+ # Offer git-based rollback
404
+ echo ""
405
+ info "You can also rollback using git:"
406
+ echo " 1. Find the commit before the migration:"
407
+ echo " git log --oneline --all | head -20"
408
+ echo ""
409
+ echo " 2. Rollback to that commit:"
410
+ echo " git checkout <commit> -- ."
411
+ echo ""
412
+ echo " 3. Or use this tool with a specific rollback point:"
413
+ echo " ./rollback-migration.sh --list"
414
+ echo " ./rollback-migration.sh --restore <point-name>"
415
+ }
416
+
417
+ ################################################################################
418
+ # Main
419
+ ################################################################################
420
+
421
+ print_usage() {
422
+ echo "Usage: ./rollback-migration.sh <migration-id> [options]"
423
+ echo ""
424
+ echo "Commands:"
425
+ echo " <migration-id> Rollback a specific migration"
426
+ echo " --list List available rollback points"
427
+ echo " --create <name> Create a new rollback point"
428
+ echo " --restore <point> Restore from a specific rollback point"
429
+ echo " --cleanup [keep-count] Delete old rollback points (default: keep 10)"
430
+ echo ""
431
+ echo "Options:"
432
+ echo " --dry-run Preview rollback without executing"
433
+ echo " --force Force rollback without confirmation"
434
+ echo " --help Show this help message"
435
+ echo ""
436
+ echo "Examples:"
437
+ echo " ./rollback-migration.sh react-18 # Rollback react-18 migration"
438
+ echo " ./rollback-migration.sh react-18 --dry-run # Preview the rollback"
439
+ echo " ./rollback-migration.sh --create before-upgrade # Create rollback point"
440
+ echo " ./rollback-migration.sh --list # List rollback points"
441
+ echo ""
442
+ }
443
+
444
+ main() {
445
+ local command=""
446
+ local dry_run="false"
447
+ local force="false"
448
+ local create_name=""
449
+ local restore_point=""
450
+ local cleanup_keep=""
451
+
452
+ # Parse arguments
453
+ while [[ $# -gt 0 ]]; do
454
+ case "$1" in
455
+ --list|-l)
456
+ command="list"
457
+ ;;
458
+ --create|-c)
459
+ command="create"
460
+ shift
461
+ create_name="$1"
462
+ ;;
463
+ --restore|-r)
464
+ command="restore"
465
+ shift
466
+ restore_point="$1"
467
+ ;;
468
+ --cleanup)
469
+ command="cleanup"
470
+ shift
471
+ if [[ "$1" =~ ^[0-9]+$ ]]; then
472
+ cleanup_keep="$1"
473
+ else
474
+ # Not a number, don't consume
475
+ cleanup_keep="10"
476
+ continue
477
+ fi
478
+ ;;
479
+ --dry-run)
480
+ dry_run="true"
481
+ ;;
482
+ --force|-f)
483
+ force="true"
484
+ ;;
485
+ --help|-h)
486
+ print_usage
487
+ exit 0
488
+ ;;
489
+ -*)
490
+ error "Unknown option: $1"
491
+ ;;
492
+ *)
493
+ if [[ -z "$command" ]]; then
494
+ command="rollback"
495
+ fi
496
+ [[ -z "$migration_id" ]] && migration_id="$1"
497
+ ;;
498
+ esac
499
+ shift
500
+ done
501
+
502
+ print_header
503
+
504
+ # Ensure rollback directory exists
505
+ mkdir -p "$ROLLBACK_DIR"
506
+
507
+ case "$command" in
508
+ list)
509
+ list_rollback_points
510
+ ;;
511
+ create)
512
+ if [[ -z "$create_name" ]]; then
513
+ error "Please provide a name for the rollback point"
514
+ fi
515
+ create_rollback_point "$create_name"
516
+ ;;
517
+ restore)
518
+ if [[ -z "$restore_point" ]]; then
519
+ error "Please provide a rollback point name"
520
+ fi
521
+ rollback_from_point "$restore_point" "$dry_run"
522
+ ;;
523
+ cleanup)
524
+ cleanup_rollback_points "${cleanup_keep:-10}"
525
+ ;;
526
+ rollback)
527
+ if [[ -z "$migration_id" ]]; then
528
+ print_usage
529
+ exit 1
530
+ fi
531
+ rollback_migration "$migration_id" "$dry_run" "$force"
532
+ ;;
533
+ *)
534
+ print_usage
535
+ exit 1
536
+ ;;
537
+ esac
538
+ }
539
+
540
+ main "$@"