🗓️ Changelog
All notable changes to Laravel Migration Linter are documented here.
This project follows Semantic Versioning.
🚀 [v2.1.0] — 2025-12-24
🆕 Added
-
New Rule:
RenamingColumnWithoutIndex— Detects column rename operations that can cause table locks and downtime- Warns when using
$table->renameColumn()on large tables - Provides 3-phase zero-downtime migration strategy
- Configurable to check large tables only or all tables
- Supports safe comment bypass:
// safe rename
- Warns when using
-
New Rule:
ChangeColumnTypeOnLargeTable— Detects column type changes that can cause table locks- Detects 25+ column type methods with
->change()modifier (string, integer, decimal, text, datetime, boolean, enum, etc.) - Default severity: error (high impact operation)
- Provides 3 migration strategies: zero-downtime, maintenance window, pt-online-schema-change
- Supports safe comment bypass:
// safe change,// maintenance window
- Detects 25+ column type methods with
-
New Flag:
--no-suggestions— Hide migration suggestions for cleaner output- Useful when you only want to see the warnings table
- Can be combined with
--summaryfor minimal output
-
New Flag:
--html=— Generate interactive HTML reports- Beautiful, responsive HTML reports with charts and visualizations
- Searchable and filterable issue table
- Grouped suggestions organized by rule type
- Rule breakdown with statistics
- Perfect for sharing with team members and CI/CD artifacts
- Example:
php artisan migrate:lint --html=storage/report.html
⚙️ Improved
-
Enhanced MigrationParser — Now properly skips commented-out lines
- Lines starting with
//or/*are ignored during parsing - Prevents false positives from commented code
- Tracks previous line context for safe comment detection
- Lines starting with
-
Better Safe Comment Detection — Comments on line above operations are now recognized
// safe renameon line before operation works correctly/* safe rename */before operation works correctly- Inline comments continue to work:
$table->renameColumn(...); // safe rename
-
Improved Suggestion Output Formatting — Cleaner, more organized display
- Suggestions now grouped by rule type instead of repeated for each occurrence
- Added visual hierarchy with section headers and separators
- Shows occurrence count per rule (e.g., "3 occurrences")
- Better indentation and color coding for readability
- Professional CLI output with proper spacing
🧰 Developer
- Added 13 comprehensive unit tests for
RenamingColumnWithoutIndexrule - Added 16 comprehensive unit tests for
ChangeColumnTypeOnLargeTablerule - Added 12 comprehensive unit tests for
HtmlReporterclass - Total: 84 tests passing (200 assertions)
- Parser improvements benefit all existing rules
- Enhanced rawCode context includes previous line for better analysis
- New
HtmlReporterclass for generating interactive reports
🚀 [1.0.0] — 2025-10-15
🆕 Added
- Core Artisan command:
php artisan migrate:lint
Base rules:
- AddNonNullableColumnWithoutDefault
- MissingIndexOnForeignKey
- Config publishing (php artisan vendor:publish --tag="migration-linter-config")
- Baseline file support (--generate-baseline, --baseline=path)
- JSON output mode (--json)
- Compact report output for smaller terminals.
🧩 [1.1.0] — 2025-10-21
🆕 Added
DropColumnWithoutBackuprule — warns when columns are dropped without confirmation or backup.AddUniqueConstraintOnNonEmptyColumnrule — warns when adding unique constraints that might fail on existing data.FloatColumnForMoneyrule — warns when usingfloat()for monetary fields; recommendsdecimal(10,2)instead.
⚙️ Improved
- Enhanced output formatting for compact mode (
--compact) on smaller terminals. - Configuration system now supports custom rules from any namespace (e.g.,
App\MigrationRules).
🧰 Developer
- Added rule discovery improvements in
RuleEngine. - Documentation updates (
rules.md,writing-custom-rules.md, andconfiguration.md).
New Rules
Initial public release with baseline rule set:
- AddNonNullableColumnWithoutDefault
- MissingIndexOnForeignKey
- DropColumnWithoutBackup
- AddUniqueConstraintOnNonEmptyColumn
- FloatColumnForMoney
[v1.2.0] — 2025-10-30
✨ Added
- AddNonNullableColumnWithoutDefault
- Detects
.change()on existing columns. - Skips
Schema::create()(safe for new tables).
- Detects
- MissingIndexOnForeignKey
- Detects
foreignId()without->constrained(). - Detects
morphs()/nullableMorphs()without->index(). - Detects composite
foreign([...])without matchingindex([...]).
- Detects
- DropColumnWithoutBackup
- Detects multiple column drops.
- Supports safe comment whitelist (
// safe dropor/* safe-drop */).
- AddUniqueConstraintOnNonEmptyColumn
- Detects composite unique constraints.
- Detects inline
->unique()and->unique()->change(). - Configurable
check_compositeflag.
- FloatColumnForMoney
- Detects
float(),double(), andreal()for money-like columns. - Smarter pattern matching (price, amount, total, tax, etc.).
- Configurable toggles:
check_doubleandcheck_real.
- Detects
🧰 Improved
- Unified severity handling via config.
- More informative lint messages for each rule.
- Enhanced documentation and configuration examples.
🐛 Fixed
- Config overrides now correctly respect
enabled = false. - RuleEngine dynamically skips disabled rules during lint runs.
�️ [2.0.0] — 2025-11-20
✨ Added (SOLID Principles Refactoring)
- 8 Core Interfaces — Dependency injection contracts
ConfigInterface,FormatterInterface,ParserInterface,RuleInterface,RuleEngineInterfaceSeverityResolverInterface,ReporterInterface,BaselineInterface
- 3 Service Classes — Reusable business logic
LaravelConfigProvider— Bridges Laravel config to contractsSeverityResolver— Priority-based severity determinationLintService— Orchestrates entire linting workflow
- 5 Formatter Classes — Modular output system
TableFormatter— Console table format (with Symfony Table component)JsonFormatter— JSON output for CI/CDCompactFormatter— Single-line compact formatSummaryFormatter— Table + statisticsBaseFormatter— Shared utilities for all formatters
🔧 Improved
- SOLID Principles throughout:
- Single Responsibility — Each formatter, service, rule has one job
- Open/Closed — Add new formatters/services without modifying existing code
- Liskov Substitution — All formatters interchangeable via interface
- Interface Segregation — Small, focused contracts
- Dependency Inversion — Depend on interfaces, not implementations
- Table Formatting — Fixed color code alignment
- Switched to Symfony's native
Tablecomponent - Perfect column alignment regardless of content
- Proper text wrapping and spacing
- Switched to Symfony's native
- Dependency Injection — Service provider auto-wiring
- Laravel container bindings for all services
- Automatic resolver injection into rules
- Testable with mocked interfaces
✅ Quality
- 144 tests passing (259 assertions)
- 100% backward compatible (zero breaking changes)
- ~95% code coverage (excellent test quality)
🔄 Migration
All commands work identically — no breaking changes:
php artisan migrate:lint # Still works
php artisan migrate:lint --json # Still works
php artisan migrate:lint --compact # Still works
php artisan migrate:lint --summary # Still works
php artisan migrate:lint --rules # Still works
�🎯 [1.4.0] — 2025-11-15
✨ Added (Phase 3: UX Improvements + New Rule)
- Actionable Suggestions — Every issue now includes
suggestionfield with fix recommendations- Suggestions appear in CLI output after the lint table with
[Suggestion #N]headers - Suggestions included in JSON output as
suggestionfield for tool integration - Each suggestion provides clear, actionable next steps
- Suggestions appear in CLI output after the lint table with
- Documentation Links — Issues now include optional
docsUrlfield- Links appear in CLI with 📖 icon and full URL
- JSON output includes
docs_urlfield for programmatic access - All built-in rules updated with relevant documentation links
- New Rule: SoftDeletesOnProduction — Warns about soft deletes on large tables
- Detects
softDeletes()on tables inlarge_table_namesconfig - Provides 3 alternatives: archive, hard delete, or add index on deleted_at
- Includes suggestions and documentation links
- Detects
- Enhanced AbstractRule.warn() — Signature extended to accept
$suggestionand$docsUrlparameters- Fully backward compatible (optional parameters)
- Enables custom rule authors to provide rich feedback
🧰 Improved
- Reporter System: Enhanced
renderTable()andrenderJson()to display/include suggestions - Built-in Rules Updated: AddNonNullableColumnWithoutDefault and MissingIndexOnForeignKey now include actionable suggestions
- Documentation: Updated usage.md, rules.md, writing-custom-rules.md, ci-cd.md with new features and rules
- Developer Experience: Custom rule authors can now provide suggestions via
warn()method
📊 Example Output
[warning] SoftDeletesOnProduction
→ Using soft deletes on the 'users' table may impact query performance over time.
[Suggestion #1] SoftDeletesOnProduction:
Option 1: Archive old data to a separate table
Option 2: Use hard deletes if retention isn't required
Option 3: Add an index on 'deleted_at' to improve query performance
📖 Learn more: https://docs.example.com/rules#-softdeletesonproduction
✨ Overview
- Changes fully backward compatible with v1.3.x
- Total rule count: 6 rules (5 original + 1 new)
🧠 Tip: You can always check your installed version via Composer:
composer show sufyandev/laravel-migration-linter
Or compare changes on GitHub:
👉 muhammad-sufyan5/sufyan-laravel-migration-lint-package