-
Notifications
You must be signed in to change notification settings - Fork 120
Add seed tracking. #939
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add seed tracking. #939
Changes from 5 commits
8e35170
fbe3526
4841a7b
a986999
510bfd0
299996f
159f7ef
b23c614
1f9a62e
d1ddd58
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -181,14 +181,104 @@ The Run Method | |
| ============== | ||
|
|
||
| The run method is automatically invoked by Migrations when you execute the | ||
| ``cake migration seed`` command. You should use this method to insert your test | ||
| ``seeds run`` command. You should use this method to insert your test | ||
| data. | ||
|
|
||
| Seed Execution Tracking | ||
| ======================== | ||
|
|
||
| Seeds track their execution state in the ``cake_seeds`` database table. By default, | ||
| a seed will only run once. If you attempt to run a seed that has already been | ||
| executed, it will be skipped with an "already executed" message. | ||
|
|
||
| To re-run a seed that has already been executed, use the ``--force`` flag: | ||
|
|
||
| .. code-block:: bash | ||
|
|
||
| bin/cake seeds run Users --force | ||
|
|
||
| You can check which seeds have been executed using the status command: | ||
|
|
||
| .. code-block:: bash | ||
|
|
||
| bin/cake seeds status | ||
|
|
||
| To reset all seeds' execution state (allowing them to run again without ``--force``): | ||
|
|
||
| .. code-block:: bash | ||
|
|
||
| bin/cake seeds reset | ||
|
|
||
| .. note:: | ||
|
|
||
| Unlike with migrations, seeds do not keep track of which seed classes have | ||
| been run. This means database seeds can be run repeatedly. Keep this in | ||
| mind when developing them. | ||
| When re-running seeds with ``--force``, be careful to ensure your seeds are | ||
| idempotent (safe to run multiple times) or they may create duplicate data. | ||
|
|
||
| Idempotent Seeds | ||
| ================ | ||
|
|
||
| Some seeds are designed to be run multiple times safely (idempotent), such as seeds | ||
| that update configuration or reference data. For these seeds, you can override the | ||
| ``isIdempotent()`` method to skip tracking entirely: | ||
|
|
||
| .. code-block:: php | ||
|
|
||
| <?php | ||
| declare(strict_types=1); | ||
|
|
||
| use Migrations\BaseSeed; | ||
|
|
||
| class ConfigSeed extends BaseSeed | ||
| { | ||
| /** | ||
| * Mark this seed as idempotent. | ||
| * It will run every time without being tracked. | ||
| */ | ||
| public function isIdempotent(): bool | ||
| { | ||
| return true; | ||
| } | ||
|
Comment on lines
+253
to
+256
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens if a non-idempotent seed is run with the 'old' command? It seems like the result would be incorrect behavior.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what old command? you mean migrations v4? PS: Thats already the case anway right now, it blindly runs everything all the time.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Sure, but couldn't we retain at least a help message for the old command, or retain it with warnings? People likely have scripts, tooling and muscle memory that we'll be breaking.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would prefer we provide the guides I included and a clear release note for the major. |
||
|
|
||
| public function run(): void | ||
| { | ||
| // This seed will run every time, so make it safe to run multiple times | ||
| $this->execute(" | ||
| INSERT INTO settings (setting_key, setting_value) | ||
| VALUES ('app_version', '2.0.0') | ||
| ON DUPLICATE KEY UPDATE setting_value = '2.0.0' | ||
| "); | ||
|
|
||
| // Or check before inserting | ||
| $exists = $this->fetchRow( | ||
| "SELECT COUNT(*) as count FROM settings WHERE setting_key = 'maintenance_mode'" | ||
| ); | ||
|
|
||
| if ($exists['count'] == 0) { | ||
| $this->table('settings')->insert([ | ||
| 'setting_key' => 'maintenance_mode', | ||
| 'setting_value' => 'false', | ||
| ])->save(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| When ``isIdempotent()`` returns ``true``: | ||
|
|
||
| - The seed will **not** be tracked in the ``cake_seeds`` table | ||
| - The seed will run **every time** you execute ``seeds run`` | ||
| - You must ensure the seed's ``run()`` method handles duplicate executions safely | ||
|
|
||
| This is useful for: | ||
|
|
||
| - Configuration seeds that should always reflect current values | ||
| - Reference data that may need periodic updates | ||
| - Seeds that use ``INSERT ... ON DUPLICATE KEY UPDATE`` or similar patterns | ||
| - Development/testing seeds that need to run repeatedly | ||
|
|
||
| .. warning:: | ||
|
|
||
| Only mark a seed as idempotent if you've verified it's safe to run multiple times. | ||
| Otherwise, you may create duplicate data or other unexpected behavior. | ||
|
|
||
| The Init Method | ||
| =============== | ||
|
|
@@ -246,10 +336,28 @@ You can also use the full seed name including the ``Seed`` suffix: | |
|
|
||
| Both forms are supported and work identically. | ||
|
|
||
| Automatic Dependency Execution | ||
| ------------------------------- | ||
|
|
||
| When you run a seed that has dependencies, the system will automatically check if | ||
| those dependencies have been executed. If any dependencies haven't run yet, they | ||
| will be executed automatically before the current seed runs. This ensures proper | ||
| execution order and prevents foreign key constraint violations. | ||
|
|
||
| For example, if you run: | ||
|
|
||
| .. code-block:: bash | ||
|
|
||
| bin/cake seeds run ShoppingCartSeed | ||
|
|
||
| And ``ShoppingCartSeed`` depends on ``UserSeed`` and ``ShopItemSeed``, the system | ||
| will automatically execute those dependencies first if they haven't been run yet. | ||
|
|
||
| .. note:: | ||
|
|
||
| Dependencies are only considered when executing all seed classes (default behavior). | ||
| They won't be considered when running specific seed classes. | ||
| Dependencies that have already been executed (according to the ``cake_seeds`` | ||
| table) will be skipped, unless you use the ``--force`` flag which will | ||
| re-execute all seeds including dependencies. | ||
|
|
||
|
|
||
| Calling a Seed from another Seed | ||
|
|
@@ -371,37 +479,37 @@ SQL `TRUNCATE` command: | |
| Executing Seed Classes | ||
| ====================== | ||
|
|
||
| This is the easy part. To seed your database, simply use the ``migrations seed`` command: | ||
| This is the easy part. To seed your database, simply use the ``seeds run`` command: | ||
|
|
||
| .. code-block:: bash | ||
|
|
||
| $ bin/cake migrations seed | ||
| $ bin/cake seeds run | ||
|
|
||
| By default, Migrations will execute all available seed classes. If you would like to | ||
| run a specific class, simply pass in the name of it using the ``--seed`` parameter. | ||
| run a specific seed, simply pass in the seed name as an argument. | ||
| You can use either the short name (without the ``Seed`` suffix) or the full name: | ||
|
|
||
| .. code-block:: bash | ||
|
|
||
| $ bin/cake migrations seed --seed User | ||
| $ bin/cake seeds run User | ||
| # or | ||
| $ bin/cake migrations seed --seed UserSeed | ||
| $ bin/cake seeds run UserSeed | ||
|
|
||
| Both commands work identically. | ||
|
|
||
| You can also run multiple seeds: | ||
| You can also run multiple seeds by separating them with commas: | ||
|
|
||
| .. code-block:: bash | ||
|
|
||
| $ bin/cake migrations seed --seed User --seed Permission --seed Log | ||
| $ bin/cake seeds run User,Permission,Log | ||
| # or with full names | ||
| $ bin/cake migrations seed --seed UserSeed --seed PermissionSeed --seed LogSeed | ||
| $ bin/cake seeds run UserSeed,PermissionSeed,LogSeed | ||
|
|
||
| You can also use the `-v` parameter for more output verbosity: | ||
|
|
||
| .. code-block:: bash | ||
|
|
||
| $ bin/cake migrations seed -v | ||
| $ bin/cake seeds run -v | ||
|
|
||
| The Migrations seed functionality provides a simple mechanism to easily and repeatably | ||
| insert test data into your database, this is great for development environment | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,7 +39,7 @@ class SeedCommand extends Command | |
| */ | ||
| public static function defaultName(): string | ||
| { | ||
| return 'migrations seed'; | ||
| return 'seeds run'; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about the old command? How does that continue working?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They dont It is also simple enough IMO to understand. Those are simple commands that people can overwrite locally if they want to retain the old commands.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added a migration guide and a guide on how to easily restore the old way if needed. |
||
| } | ||
|
|
||
| /** | ||
|
|
@@ -55,10 +55,10 @@ public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionPar | |
| '', | ||
| 'Runs a seeder script that can populate the database with data, or run mutations:', | ||
| '', | ||
| '<info>migrations seed Posts</info>', | ||
| '<info>migrations seed Users,Posts</info>', | ||
| '<info>migrations seed --plugin Demo</info>', | ||
| '<info>migrations seed --connection secondary</info>', | ||
| '<info>seeds run Posts</info>', | ||
| '<info>seeds run Users,Posts</info>', | ||
| '<info>seeds run --plugin Demo</info>', | ||
| '<info>seeds run --connection secondary</info>', | ||
| '', | ||
| 'Runs all seeds if no seed names are specified. When running all seeds', | ||
| 'in an interactive terminal, a confirmation prompt is shown.', | ||
|
|
@@ -87,6 +87,11 @@ public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionPar | |
| 'short' => 's', | ||
| 'default' => ConfigInterface::DEFAULT_SEED_FOLDER, | ||
| 'help' => 'The folder where your seeds are.', | ||
| ]) | ||
| ->addOption('force', [ | ||
| 'short' => 'f', | ||
| 'help' => 'Force re-running seeds that have already been executed', | ||
| 'boolean' => true, | ||
| ]); | ||
|
|
||
| return $parser; | ||
|
|
@@ -184,9 +189,13 @@ protected function executeSeeds(Arguments $args, ConsoleIo $io): ?int | |
| $io->out(' - ' . $seedName); | ||
| } | ||
| $io->out(''); | ||
| $io->out('<warning>Note:</warning> Seeds do not track execution state. They will run'); | ||
| $io->out('regardless of whether they have been executed before. Ensure your'); | ||
| $io->out('seeds are idempotent or manually verify they should be (re)run.'); | ||
| if (!(bool)$args->getOption('force')) { | ||
| $io->out('<info>Note:</info> Seeds that have already been executed will be skipped.'); | ||
| $io->out('Use --force to re-run seeds.'); | ||
| } else { | ||
| $io->out('<warning>Warning:</warning> Running with --force will re-execute all seeds,'); | ||
| $io->out('potentially creating duplicate data. Ensure your seeds are idempotent.'); | ||
| } | ||
| $io->out(''); | ||
|
|
||
| // Ask for confirmation | ||
|
|
@@ -199,11 +208,11 @@ protected function executeSeeds(Arguments $args, ConsoleIo $io): ?int | |
| } | ||
|
|
||
| // run all the seed(ers) | ||
| $manager->seed(); | ||
| $manager->seed(null, (bool)$args->getOption('force')); | ||
| } else { | ||
| // run seed(ers) specified as arguments | ||
| foreach ($seeds as $seed) { | ||
| $manager->seed(trim($seed)); | ||
| $manager->seed(trim($seed), (bool)$args->getOption('force')); | ||
| } | ||
| } | ||
| $end = microtime(true); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.