Skip to content

Conversation

@dereuromark
Copy link
Member

@dereuromark dereuromark commented Nov 3, 2025

Completing #935 I want to introduce seed logs.

This makes seeds a bit more useful in everyday dev life:

  • New seeds can run automatically without the rest getting compromised
  • Clear execution runs also for dependent seeds (so far adding one as dependency would also cause reruns there)

Proposed API: seeds on its on high level, as this is not necessarily directly linked to migrations, but more to (demo) data.

# bin/cake
migrations:
 - bake migration
 - bake migration_diff
 - bake migration_snapshot
 - bake seed
 - migrations
 - migrations dump
 - migrations mark_migrated
 - migrations migrate
 - migrations rollback
 - migrations status
 - seeds
 - seeds reset
 - seeds run
 - seeds status

Details:

  1. Database Schema (cake_seeds table)
  • id (auto-increment primary key)
  • plugin (nullable string) - Tracks which plugin the seed belongs to
  • seed_name (string) - The seed class name
  • executed_at (timestamp) - When the seed was executed
  1. Seed Execution Tracking
  • Seeds now track whether they've been executed in the cake_seeds table
  • By default, seeds only run once (prevents duplicate data)
  • Already-executed seeds show "already executed" message and are skipped
  1. Force Re-execution
  • Added --force flag to migrations seed command
  • Allows re-running seeds that have already been executed
  • Useful when seeds are idempotent
  1. Automatic Dependency Execution
  • When a seed has dependencies (via getDependencies()), the system checks if they've been executed
  • Missing dependencies are automatically executed before the current seed
  • Prevents foreign key constraint violations
  • Respects execution state (already-executed dependencies are skipped unless using --force)
  1. New Commands

seeds status

  • Shows which seeds have been executed and which are pending
  • Supports both text and JSON output formats
  • Displays execution timestamps

seeds reset

  • Removes seed execution records from the log
  • Supports resetting single seeds, multiple seeds (comma-separated), or all seeds (--all)
  • Includes confirmation prompt
  • Supports --dry-run flag

How It Works

  1. First Execution: Seed runs normally and execution is recorded in cake_seeds
  2. Subsequent Runs: Seed is skipped with "already executed" message
  3. Force Re-run: Use --force flag to re-execute
  4. Check Status: seeds status shows execution state
  5. Reset State: seeds reset SeedName removes from log, allowing re-execution without --force

@dereuromark dereuromark marked this pull request as draft November 3, 2025 02:28
@dereuromark
Copy link
Member Author

dereuromark commented Nov 3, 2025

The error

There was 1 error:

1) Migrations\Test\TestCase\Command\SeedCommandTest::testSeedResetCommand
InvalidArgumentException: You can use `$input` only if `$_in` property is null and will be reset.

/home/runner/work/migrations/migrations/vendor/cakephp/cakephp/src/Console/TestSuite/ConsoleIntegrationTestTrait.php:92
/home/runner/work/migrations/migrations/tests/TestCase/Command/SeedCommandTest.php:519

will go away with release of bugfix cakephp/cakephp#19032

//EDIT: I merged it from 5.x to 5.next - should already work.

@dereuromark dereuromark marked this pull request as ready for review November 3, 2025 03:12
@dereuromark
Copy link
Member Author

Additionally now seeds can be idempotent, making them untracked.
This essentially allows also restoring current default functionality of rerunning them all the time without the need to confirm or force.

Co-authored-by: Kevin Pfeifer <[email protected]>
@dereuromark dereuromark requested a review from Copilot November 4, 2025 16:49
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements seed execution tracking for CakePHP's Migrations plugin. Seeds now track their execution state in a cake_seeds database table, preventing them from running multiple times by default unless the --force flag is used or they are marked as idempotent.

Key Changes:

  • Added seed execution state tracking with a new cake_seeds database table
  • Introduced idempotent seed support via isIdempotent() method
  • Renamed command from migrations seed to seeds run and added new commands: seeds status and seeds reset

Reviewed Changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/TestCase/MigrationsTest.php Added setup to truncate cake_seeds table and updated tests to use force flag
tests/TestCase/Command/SeedCommandTest.php Updated all tests to use new seeds run command and added tests for state tracking, status, and reset features
tests/TestCase/Command/CompletionTest.php Removed seed from migrations subcommands as it moved to seeds namespace
src/SeedInterface.php Added isIdempotent() interface method
src/MigrationsPlugin.php Reorganized command registration to separate migration and seed commands
src/Migration/Manager.php Added methods for checking seed execution state and managing dependencies
src/Migration/Environment.php Added seed execution recording after seed runs
src/Migration/BuiltinBackend.php Added force parameter support
src/Db/Adapter/AdapterWrapper.php Added wrapper methods for seed schema table operations
src/Db/Adapter/AdapterInterface.php Added interface methods for seed tracking
src/Db/Adapter/AbstractAdapter.php Implemented seed logging and schema table creation
src/Command/SeedsEntryCommand.php New entry point command for seeds namespace
src/Command/SeedStatusCommand.php New command to show seed execution status
src/Command/SeedResetCommand.php New command to reset seed execution logs
src/Command/SeedCommand.php Updated to use new command name and added --force flag
src/BaseSeed.php Implemented default isIdempotent() returning false
docs/en/seeding.rst Updated documentation for new tracking behavior

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

Copilot AI commented Nov 4, 2025

@dereuromark I've opened a new pull request, #945, to work on those changes. Once the pull request is ready, I'll request review from you.

Comment on lines +237 to +240
public function isIdempotent(): bool
{
return true;
}
Copy link
Member

Choose a reason for hiding this comment

The 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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what old command? you mean migrations v4?
this is a new major, so any of this functionality is only available v5+.

PS: Thats already the case anway right now, it blindly runs everything all the time.

public static function defaultName(): string
{
return 'migrations seed';
return 'seeds run';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about the old command? How does that continue working?

Copy link
Member Author

@dereuromark dereuromark Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They dont
It is simple enough to clarify in a migration guide that the API changed.

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.
Thats why we do a major, to improve and clean up the API, that really does need some overhaul, after like 2 decades.

Copy link
Member Author

Choose a reason for hiding this comment

The 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.

* @param string $seedSchemaTableName Seed Schema Table Name
* @return $this
*/
public function setSeedSchemaTableName(string $seedSchemaTableName)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do users interact with this? There doesn't seem to be any way to call this, and if there isn't why does it exist?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isnt it via options?

    public function setOptions(array $options): AdapterInterface
    {
        $this->options = $options;

        if (isset($options['migration_table'])) {
            $this->setSchemaTableName($options['migration_table']);
        }

        if (isset($options['seed_table'])) {
            $this->setSeedSchemaTableName($options['seed_table']);
        }

        if (isset($options['connection']) && $options['connection'] instanceof Connection) {
            $this->setConnection($options['connection']);
        }

        return $this;
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants