title: Testing Workflow updated: 2025-11-08 version: 3#
"Ride the lightning."
This document provides a comprehensive testing workflow for the storm changelog manager.
All tests should be run within this repository to validate functionality against real Git
history.
Setup#
# Build the CLI
task build
Non-TTY Environment Handling#
Storm automatically detects whether it's running in an interactive terminal (TTY) or a non-interactive environment (CI pipelines, scripts, pipes). Commands gracefully degrade or provide helpful error messages.
TTY Detection#
The CLI checks for:
- Terminal availability on stdin/stdout
- Common CI environment variables (GITHUB_ACTIONS, GITLAB_CI, CIRCLECI, etc.)
Command Behavior#
generate --interactive#
Interactive (TTY): Launches TUI for commit selection Non-Interactive: Returns error with suggestion to use non-interactive mode
# CI/Non-TTY
storm generate HEAD~5 HEAD --interactive
# Error: flag '--interactive' requires an interactive terminal (detected GitHub Actions environment)
Workaround:
# Use without --interactive flag for automatic processing
storm generate HEAD~5 HEAD
unreleased review#
Interactive (TTY): Launches TUI for reviewing entries Non-Interactive: Returns error with alternatives
# CI/Non-TTY
storm unreleased review
# Error: command 'storm unreleased review' requires an interactive terminal (detected CI environment)
#
# Alternatives:
# - Use 'storm unreleased list' to view entries in plain text
# - Use 'storm unreleased list --json' for JSON output
diff#
Interactive (TTY): Launches TUI for navigating diffs Non-Interactive: Outputs plain text diff to stdout
# CI/Non-TTY - automatically outputs plain text
storm diff HEAD~1 HEAD
# === File 1/3 ===
# --- HEAD~1:file.go
# +++ HEAD:file.go
# [plain text diff output]
Testing Non-TTY Behavior#
Simulate CI environment#
CI=true storm unreleased review
# Should error with CI-friendly message
Pipe output#
storm diff HEAD~1 HEAD | less
# Should output plain text diff (not TUI)
Redirect to file#
storm diff HEAD~1 HEAD > changes.diff
# Should write plain text to file
Expected Behaviors:
- Clear error messages indicating TTY requirement
- Suggestions for alternative commands
- CI system name detection (e.g., "detected GitHub Actions environment")
- Automatic fallback to plain text for
diffcommand - No ANSI escape codes in piped/redirected output
Core Workflow#
Manual Entry Creation (unreleased add)#
Create entries manually without linking to commits.
Basic entry creation#
storm unreleased add --type added --summary "Test manual entry"
Expected:
- Creates
.changes/<timestamp>-test-manual-entry.md - File contains YAML frontmatter with type and summary
- Styled success message displays created file path
Entry with scope#
storm unreleased add --type fixed --scope api --summary "Fix authentication bug"
Expected:
- Includes
scope: apiin frontmatter - Filename slugifies to
...-fix-authentication-bug.md
Collision handling#
# Run same command twice rapidly
storm unreleased add --type added --summary "Duplicate test"
storm unreleased add --type added --summary "Duplicate test"
Expected:
- Two different files created (second has
-1suffix) - Both files exist and are readable
Edge Cases:
- Invalid type (should error with helpful message)
- Missing required flags (should error)
- Very long summary (should truncate to 50 chars)
- Special characters in summary (should slugify correctly)
- Empty summary (should error)
Commit-Linked Entry Creation (unreleased partial)#
Create entries linked to specific commits with auto-detection.
Basic partial from commit#
# Use a recent commit hash
storm unreleased partial HEAD
Expected:
- Auto-detects type from conventional commit format
- Creates
.changes/<sha7>.<type>.md - Includes
commit_hashin frontmatter - Shows styled success message
Override auto-detection#
storm unreleased partial HEAD~1 --type fixed --summary "Custom summary"
Expected:
- Uses provided type instead of auto-detected
- Uses custom summary
- Preserves commit hash in frontmatter
Non-conventional commit#
# Try a commit without conventional format
storm unreleased partial <old-commit>
Expected:
- Error message: "could not auto-detect change type"
- Suggests using
--typeflag
Duplicate prevention#
storm unreleased partial HEAD
storm unreleased partial HEAD # Run again
Expected:
- Second command fails with "file already exists" error
Edge Cases:
- Invalid commit ref (should error)
- Merge commit (should handle gracefully)
- Initial commit with no parent (should work)
- Commit with multi-line message (should parse correctly)
- Commit with breaking change marker (should set
breaking: true)
Listing Entries (unreleased list)#
Display all unreleased changes.
Text output#
storm unreleased list
Expected:
- Color-coded type labels ([added], [fixed], etc.)
- Shows scope if present
- Displays filename
- Shows breaking change indicator if applicable
- Empty state message if no entries
JSON output#
storm unreleased list --json
Expected:
- Valid JSON array
- Each entry has type, scope, summary, filename
- Can be piped to
jqfor processing
Edge Cases:
- Empty
.changes/directory - Malformed YAML in entry file
- Mixed entry types (manual + partial)
Generating Entries from Git History (generate)#
Scan commit ranges and create changelog entries.
Range generation#
# Generate from last 5 commits
storm generate HEAD~5 HEAD
Expected:
- Lists N commits found
- Creates entries for conventional commits
- Skips non-conventional commits
- Shows created count and skipped count
- Uses diff-based deduplication
Interactive selection#
storm generate HEAD~10 HEAD --interactive
Expected:
- Launches TUI with commit list
- Shows parsed metadata (type, scope, summary)
- Allows selection/deselection
- Creates only selected entries
- Handles cancellation (Ctrl+C)
- Errors gracefully in non-TTY with helpful message
Since tag#
storm generate --since v0.1.0
Expected:
- Generates entries from v0.1.0 to HEAD
- Auto-detects tag as starting point
Deduplication#
storm generate HEAD~3 HEAD
storm generate HEAD~3 HEAD # Run again
Expected:
- First run creates N entries
- Second run shows "Skipped N duplicates"
- No duplicate files created
Rebased commits#
# Simulate rebase by checking metadata
storm generate <range-with-rebased-commits>
Expected:
- Detects same diff, different commit hash
- Updates metadata with new commit hash
- Shows "Updated N rebased commits"
Edge Cases:
- No commits in range (should show "No commits found")
- Range with only merge commits
- Range with revert commits (should skip)
- Commits with
[nochanges]marker (should skip) - Non-existent refs (should error)
Reviewing Entries (unreleased review)#
Interactive TUI for reviewing unreleased changes.
Basic review#
storm unreleased review
Expected:
- Launches TUI with list of entries
- Shows entry details on selection
- Keyboard navigation works (j/k or arrows)
- Can mark entries with actions:
- Press
xto mark for deletion - Press
eto mark for editing - Press
spaceto keep (undo marks)
- Press
- Action indicators shown: [✓] keep, [✗] delete, [✎] edit
- Footer shows action counts
- Exit with q or ESC to cancel, Enter to confirm
Deleting entries#
storm unreleased review
# Press 'x' on unwanted entries, then Enter to confirm
Expected:
- Entries marked with [✗] are deleted from
.changes/ - Shows "Deleted:
<filename>" for each removed entry - Final count: "Review completed: N deleted, M edited"
- Files are permanently removed
Editing entries#
storm unreleased review
# Press 'e' on an entry, then Enter to confirm
Expected:
- Launches inline editor TUI for each marked entry
- Editor shows:
- Type (cycle with Ctrl+T through: added, changed, fixed, removed, security)
- Scope (text input field)
- Summary (text input field)
- Breaking change status
- Navigate fields with Tab/Shift+Tab
- Save with Enter or Ctrl+S
- Cancel with Esc (skips editing that entry)
- Shows "Updated:
<filename>" for saved changes - CommitHash and DiffHash preserved
Review workflow#
# Full workflow: mark multiple actions
storm unreleased review
# 1. Navigate with j/k
# 2. Mark first entry with 'x' (delete)
# 3. Mark second entry with 'e' (edit)
# 4. Mark third entry with 'x' (delete)
# 5. Press Enter to confirm
Expected:
- All delete actions processed first
- Then edit TUI launched for each edit action
- Can cancel individual edits with Esc
- Final summary shows both delete and edit counts
- If no actions marked, shows "No changes requested"
Edge Cases:
- Empty changes directory (should show message, not crash)
- Corrupted entry file (should handle gracefully)
- Non-TTY environment (detects and errors with alternatives)
- CI environment (detects CI system name in error message)
- Cancel review (Esc/q) - no changes applied
- Delete file that no longer exists (should error gracefully)
- Edit with empty fields (fields preserve original if empty)
CI Validation (check)#
Validate that commits have changelog entries.
All commits documented#
# After running generate for a range
storm check HEAD~5 HEAD
Expected:
- Shows "✓ All commits have changelog entries"
- Exit code 0
Missing entries#
# Create new commits without entries
git commit --allow-empty -m "feat: undocumented feature"
storm check HEAD~1 HEAD
Expected:
- Shows "✗ N commits missing changelog entries"
- Lists missing commit SHAs and subjects
- Suggests commands to fix
- Exit code 1
Skip markers#
git commit --allow-empty -m "chore: update deps [nochanges]"
storm check HEAD~1 HEAD
Expected:
- Skips commit with marker
- Shows "Skipped N commits with [nochanges] marker"
- Exit code 0
Since tag#
storm check --since v0.1.0
Expected:
- Checks all commits since tag
- Reports missing entries
Edge Cases:
- Empty commit range (should succeed with 0 checks)
- Range with all skipped commits
- Invalid tag/ref (should error)
Release Generation (release)#
Promote unreleased changes to CHANGELOG.
Basic release#
storm release --version 1.2.0
Expected:
- Creates/updates CHANGELOG.md
- Adds version header with date
- Groups entries by type (Added, Changed, Fixed, etc.)
- Maintains Keep a Changelog format
- Preserves existing changelog content
Dry run#
storm release --version 1.2.0 --dry-run
Expected:
- Shows preview of changes
- No files modified
- Styled output shows what would be written
Clear changes#
storm release --version 1.2.0 --clear-changes
Expected:
- Moves entries from
.changes/to CHANGELOG - Deletes
.changes/*.mdfiles after release - Keeps
.changes/data/metadata
Git tagging#
storm release --version 1.2.0 --tag
Expected:
- Creates annotated Git tag
v1.2.0 - Includes release notes in tag message
- Validates tag doesn't exist
Edge Cases:
- No unreleased entries (should warn)
- Existing version in CHANGELOG (should append)
- Malformed CHANGELOG.md (should handle)
- Tag already exists (should error)
- Custom date format with
--date
Diff Viewing (diff)#
Display inline diffs between refs.
Basic diff#
storm diff HEAD~1 HEAD
Expected:
- TTY: Launches interactive TUI with navigation
- Non-TTY: Outputs plain text diff to stdout
- Shows diff with syntax highlighting (TTY only)
- Iceberg theme colors (TTY only)
- Context lines displayed
- File headers shown
File filtering#
storm diff HEAD~1 HEAD -- "*.go"
Expected:
- Shows only Go file changes
- Respects glob patterns
Edge Cases:
- No changes between refs
- Binary files (should indicate)
- Large diffs (should handle gracefully)
- Non-TTY environment (automatic plain text output)
- Piped output (plain text format)
- Redirected to file (plain text format)