changelog generator & diff tool
stormlightlabs.github.io/git-storm/
changelog
changeset
markdown
golang
git
1---
2title: Testing Workflow
3updated: 2025-11-08
4version: 3
5---
6
7"Ride the lightning."
8
9This document provides a comprehensive testing workflow for the `storm` changelog manager.
10All tests should be run within this repository to validate functionality against real Git
11history.
12
13## Setup
14
15```bash
16# Build the CLI
17task build
18```
19
20## Non-TTY Environment Handling
21
22Storm automatically detects whether it's running in an interactive terminal (TTY) or a
23non-interactive environment (CI pipelines, scripts, pipes). Commands gracefully degrade
24or provide helpful error messages.
25
26### TTY Detection
27
28The CLI checks for:
29
30- Terminal availability on stdin/stdout
31- Common CI environment variables (GITHUB_ACTIONS, GITLAB_CI, CIRCLECI, etc.)
32
33### Command Behavior
34
35#### `generate --interactive`
36
37**Interactive (TTY):** Launches TUI for commit selection
38**Non-Interactive:** Returns error with suggestion to use non-interactive mode
39
40```bash
41# CI/Non-TTY
42storm generate HEAD~5 HEAD --interactive
43# Error: flag '--interactive' requires an interactive terminal (detected GitHub Actions environment)
44```
45
46**Workaround:**
47
48```bash
49# Use without --interactive flag for automatic processing
50storm generate HEAD~5 HEAD
51```
52
53#### `unreleased review`
54
55**Interactive (TTY):** Launches TUI for reviewing entries
56**Non-Interactive:** Returns error with alternatives
57
58```bash
59# CI/Non-TTY
60storm unreleased review
61# Error: command 'storm unreleased review' requires an interactive terminal (detected CI environment)
62#
63# Alternatives:
64# - Use 'storm unreleased list' to view entries in plain text
65# - Use 'storm unreleased list --json' for JSON output
66```
67
68#### `diff`
69
70**Interactive (TTY):** Launches TUI for navigating diffs
71**Non-Interactive:** Outputs plain text diff to stdout
72
73```bash
74# CI/Non-TTY - automatically outputs plain text
75storm diff HEAD~1 HEAD
76# === File 1/3 ===
77# --- HEAD~1:file.go
78# +++ HEAD:file.go
79# [plain text diff output]
80```
81
82### Testing Non-TTY Behavior
83
84#### Simulate CI environment
85
86```bash
87CI=true storm unreleased review
88# Should error with CI-friendly message
89```
90
91#### Pipe output
92
93```bash
94storm diff HEAD~1 HEAD | less
95# Should output plain text diff (not TUI)
96```
97
98#### Redirect to file
99
100```bash
101storm diff HEAD~1 HEAD > changes.diff
102# Should write plain text to file
103```
104
105**Expected Behaviors:**
106
107- Clear error messages indicating TTY requirement
108- Suggestions for alternative commands
109- CI system name detection (e.g., "detected GitHub Actions environment")
110- Automatic fallback to plain text for `diff` command
111- No ANSI escape codes in piped/redirected output
112
113## Core Workflow
114
115### Manual Entry Creation (`unreleased add`)
116
117Create entries manually without linking to commits.
118
119#### Basic entry creation
120
121```bash
122storm unreleased add --type added --summary "Test manual entry"
123```
124
125**Expected:**
126
127- Creates `.changes/<timestamp>-test-manual-entry.md`
128- File contains YAML frontmatter with type and summary
129- Styled success message displays created file path
130
131#### Entry with scope
132
133```bash
134storm unreleased add --type fixed --scope api --summary "Fix authentication bug"
135```
136
137**Expected:**
138
139- Includes `scope: api` in frontmatter
140- Filename slugifies to `...-fix-authentication-bug.md`
141
142#### Collision handling
143
144```bash
145# Run same command twice rapidly
146storm unreleased add --type added --summary "Duplicate test"
147storm unreleased add --type added --summary "Duplicate test"
148```
149
150**Expected:**
151
152- Two different files created (second has `-1` suffix)
153- Both files exist and are readable
154
155**Edge Cases:**
156
157- Invalid type (should error with helpful message)
158- Missing required flags (should error)
159- Very long summary (should truncate to 50 chars)
160- Special characters in summary (should slugify correctly)
161- Empty summary (should error)
162
163### Commit-Linked Entry Creation (`unreleased partial`)
164
165Create entries linked to specific commits with auto-detection.
166
167#### Basic partial from commit
168
169```bash
170# Use a recent commit hash
171storm unreleased partial HEAD
172```
173
174**Expected:**
175
176- Auto-detects type from conventional commit format
177- Creates `.changes/<sha7>.<type>.md`
178- Includes `commit_hash` in frontmatter
179- Shows styled success message
180
181#### Override auto-detection
182
183```bash
184storm unreleased partial HEAD~1 --type fixed --summary "Custom summary"
185```
186
187**Expected:**
188
189- Uses provided type instead of auto-detected
190- Uses custom summary
191- Preserves commit hash in frontmatter
192
193#### Non-conventional commit
194
195```bash
196# Try a commit without conventional format
197storm unreleased partial <old-commit>
198```
199
200**Expected:**
201
202- Error message: "could not auto-detect change type"
203- Suggests using `--type` flag
204
205#### Duplicate prevention
206
207```bash
208storm unreleased partial HEAD
209storm unreleased partial HEAD # Run again
210```
211
212**Expected:**
213
214- Second command fails with "file already exists" error
215
216**Edge Cases:**
217
218- Invalid commit ref (should error)
219- Merge commit (should handle gracefully)
220- Initial commit with no parent (should work)
221- Commit with multi-line message (should parse correctly)
222- Commit with breaking change marker (should set `breaking: true`)
223
224### Listing Entries (`unreleased list`)
225
226Display all unreleased changes.
227
228#### Text output
229
230```bash
231storm unreleased list
232```
233
234**Expected:**
235
236- Color-coded type labels ([added], [fixed], etc.)
237- Shows scope if present
238- Displays filename
239- Shows breaking change indicator if applicable
240- Empty state message if no entries
241
242#### JSON output
243
244```bash
245storm unreleased list --json
246```
247
248**Expected:**
249
250- Valid JSON array
251- Each entry has type, scope, summary, filename
252- Can be piped to `jq` for processing
253
254**Edge Cases:**
255
256- Empty `.changes/` directory
257- Malformed YAML in entry file
258- Mixed entry types (manual + partial)
259
260### Generating Entries from Git History (`generate`)
261
262Scan commit ranges and create changelog entries.
263
264#### Range generation
265
266```bash
267# Generate from last 5 commits
268storm generate HEAD~5 HEAD
269```
270
271**Expected:**
272
273- Lists N commits found
274- Creates entries for conventional commits
275- Skips non-conventional commits
276- Shows created count and skipped count
277- Uses diff-based deduplication
278
279#### Interactive selection
280
281```bash
282storm generate HEAD~10 HEAD --interactive
283```
284
285**Expected:**
286
287- Launches TUI with commit list
288- Shows parsed metadata (type, scope, summary)
289- Allows selection/deselection
290- Creates only selected entries
291- Handles cancellation (Ctrl+C)
292- Errors gracefully in non-TTY with helpful message
293
294#### Since tag
295
296```bash
297storm generate --since v0.1.0
298```
299
300**Expected:**
301
302- Generates entries from v0.1.0 to HEAD
303- Auto-detects tag as starting point
304
305#### Deduplication
306
307```bash
308storm generate HEAD~3 HEAD
309storm generate HEAD~3 HEAD # Run again
310```
311
312**Expected:**
313
314- First run creates N entries
315- Second run shows "Skipped N duplicates"
316- No duplicate files created
317
318#### Rebased commits
319
320```bash
321# Simulate rebase by checking metadata
322storm generate <range-with-rebased-commits>
323```
324
325**Expected:**
326
327- Detects same diff, different commit hash
328- Updates metadata with new commit hash
329- Shows "Updated N rebased commits"
330
331**Edge Cases:**
332
333- No commits in range (should show "No commits found")
334- Range with only merge commits
335- Range with revert commits (should skip)
336- Commits with `[nochanges]` marker (should skip)
337- Non-existent refs (should error)
338
339### Reviewing Entries (`unreleased review`)
340
341Interactive TUI for reviewing unreleased changes.
342
343#### Basic review
344
345```bash
346storm unreleased review
347```
348
349**Expected:**
350
351- Launches TUI with list of entries
352- Shows entry details on selection
353- Keyboard navigation works (j/k or arrows)
354- Can mark entries with actions:
355 - Press `x` to mark for deletion
356 - Press `e` to mark for editing
357 - Press `space` to keep (undo marks)
358- Action indicators shown: [✓] keep, [✗] delete, [✎] edit
359- Footer shows action counts
360- Exit with q or ESC to cancel, Enter to confirm
361
362#### Deleting entries
363
364```bash
365storm unreleased review
366# Press 'x' on unwanted entries, then Enter to confirm
367```
368
369**Expected:**
370
371- Entries marked with [✗] are deleted from `.changes/`
372- Shows "Deleted: `<filename>`" for each removed entry
373- Final count: "Review completed: N deleted, M edited"
374- Files are permanently removed
375
376#### Editing entries
377
378```bash
379storm unreleased review
380# Press 'e' on an entry, then Enter to confirm
381```
382
383**Expected:**
384
385- Launches inline editor TUI for each marked entry
386- Editor shows:
387 - Type (cycle with Ctrl+T through: added, changed, fixed, removed, security)
388 - Scope (text input field)
389 - Summary (text input field)
390 - Breaking change status
391- Navigate fields with Tab/Shift+Tab
392- Save with Enter or Ctrl+S
393- Cancel with Esc (skips editing that entry)
394- Shows "Updated: `<filename>`" for saved changes
395- CommitHash and DiffHash preserved
396
397#### Review workflow
398
399```bash
400# Full workflow: mark multiple actions
401storm unreleased review
402# 1. Navigate with j/k
403# 2. Mark first entry with 'x' (delete)
404# 3. Mark second entry with 'e' (edit)
405# 4. Mark third entry with 'x' (delete)
406# 5. Press Enter to confirm
407```
408
409**Expected:**
410
411- All delete actions processed first
412- Then edit TUI launched for each edit action
413- Can cancel individual edits with Esc
414- Final summary shows both delete and edit counts
415- If no actions marked, shows "No changes requested"
416
417**Edge Cases:**
418
419- Empty changes directory (should show message, not crash)
420- Corrupted entry file (should handle gracefully)
421- Non-TTY environment (detects and errors with alternatives)
422- CI environment (detects CI system name in error message)
423- Cancel review (Esc/q) - no changes applied
424- Delete file that no longer exists (should error gracefully)
425- Edit with empty fields (fields preserve original if empty)
426
427### CI Validation (`check`)
428
429Validate that commits have changelog entries.
430
431#### All commits documented
432
433```bash
434# After running generate for a range
435storm check HEAD~5 HEAD
436```
437
438**Expected:**
439
440- Shows "✓ All commits have changelog entries"
441- Exit code 0
442
443#### Missing entries
444
445```bash
446# Create new commits without entries
447git commit --allow-empty -m "feat: undocumented feature"
448storm check HEAD~1 HEAD
449```
450
451**Expected:**
452
453- Shows "✗ N commits missing changelog entries"
454- Lists missing commit SHAs and subjects
455- Suggests commands to fix
456- Exit code 1
457
458#### Skip markers
459
460```bash
461git commit --allow-empty -m "chore: update deps [nochanges]"
462storm check HEAD~1 HEAD
463```
464
465**Expected:**
466
467- Skips commit with marker
468- Shows "Skipped N commits with [nochanges] marker"
469- Exit code 0
470
471#### Since tag
472
473```bash
474storm check --since v0.1.0
475```
476
477**Expected:**
478
479- Checks all commits since tag
480- Reports missing entries
481
482**Edge Cases:**
483
484- Empty commit range (should succeed with 0 checks)
485- Range with all skipped commits
486- Invalid tag/ref (should error)
487
488### Release Generation (`release`)
489
490Promote unreleased changes to CHANGELOG.
491
492#### Basic release
493
494```bash
495storm release --version 1.2.0
496```
497
498**Expected:**
499
500- Creates/updates CHANGELOG.md
501- Adds version header with date
502- Groups entries by type (Added, Changed, Fixed, etc.)
503- Maintains Keep a Changelog format
504- Preserves existing changelog content
505
506#### Dry run
507
508```bash
509storm release --version 1.2.0 --dry-run
510```
511
512**Expected:**
513
514- Shows preview of changes
515- No files modified
516- Styled output shows what would be written
517
518#### Clear changes
519
520```bash
521storm release --version 1.2.0 --clear-changes
522```
523
524**Expected:**
525
526- Moves entries from `.changes/` to CHANGELOG
527- Deletes `.changes/*.md` files after release
528- Keeps `.changes/data/` metadata
529
530#### Git tagging
531
532```bash
533storm release --version 1.2.0 --tag
534```
535
536**Expected:**
537
538- Creates annotated Git tag `v1.2.0`
539- Includes release notes in tag message
540- Validates tag doesn't exist
541
542**Edge Cases:**
543
544- No unreleased entries (should warn)
545- Existing version in CHANGELOG (should append)
546- Malformed CHANGELOG.md (should handle)
547- Tag already exists (should error)
548- Custom date format with `--date`
549
550### Diff Viewing (`diff`)
551
552Display inline diffs between refs.
553
554#### Basic diff
555
556```bash
557storm diff HEAD~1 HEAD
558```
559
560**Expected:**
561
562- TTY: Launches interactive TUI with navigation
563- Non-TTY: Outputs plain text diff to stdout
564- Shows diff with syntax highlighting (TTY only)
565- Iceberg theme colors (TTY only)
566- Context lines displayed
567- File headers shown
568
569#### File filtering
570
571```bash
572storm diff HEAD~1 HEAD -- "*.go"
573```
574
575**Expected:**
576
577- Shows only Go file changes
578- Respects glob patterns
579
580**Edge Cases:**
581
582- No changes between refs
583- Binary files (should indicate)
584- Large diffs (should handle gracefully)
585- Non-TTY environment (automatic plain text output)
586- Piped output (plain text format)
587- Redirected to file (plain text format)