Skip to content

Comments

Added migrate:create script for migration scaffolding#26552

Open
rob-ghost wants to merge 1 commit intomainfrom
chore/migration-create-script
Open

Added migrate:create script for migration scaffolding#26552
rob-ghost wants to merge 1 commit intomainfrom
chore/migration-create-script

Conversation

@rob-ghost
Copy link
Contributor

Migration file creation currently depends on super-slimer, an external package that doesn't understand Ghost's RC versioning convention. This moves that tooling into ghost/core as a simple yarn migrate:create <slug> script, co-located with the migrations themselves.

The script creates a timestamped migration file in the correct version folder, creates the directory if needed, and auto-bumps package.json (core and admin) to RC when the first migration lands after a stable release. It uses semver.inc('minor') to derive the folder name, which correctly handles both stable (6.18.0 → folder 6.19) and prerelease (6.19.0-rc.0 → folder 6.19) versions. Slug validation enforces kebab-case to keep filenames consistent.

Unit tests cover slug validation, version folder calculation, file creation, RC bumping, and the invariant that stable and its corresponding RC target the same migration folder.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 24, 2026

Walkthrough

A new migration creation CLI tool was added to Ghost core: bin/create-migration.js scaffolds migration files with standardized timestamped names and versioned folders, validates kebab-case slugs, and can bump core (and admin if present) package.json versions to an RC pre-release when creating the first migration after a release. The script is exposed via an npm script migrate:create. The previous Slimer/manual workflow was replaced. Comprehensive unit tests were added to cover slug validation, version calculation, file creation, and RC bump behavior.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding a migrate:create script for migration scaffolding, which is the primary objective of the PR.
Description check ✅ Passed The description is directly related to the changeset, explaining the motivation (replacing super-slimer), the new script's functionality (file creation, RC bumping, slug validation), and validation approach.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/migration-create-script

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@rob-ghost rob-ghost force-pushed the chore/migration-create-script branch from 1290068 to 62b8eff Compare February 24, 2026 08:04
@rob-ghost rob-ghost marked this pull request as ready for review February 24, 2026 09:01
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.claude/skills/create-database-migration/SKILL.md:
- Around line 10-12: Update the migration creation instructions to explicitly
call out that the CLI enforces kebab-case for the migration name and that the
migration script will bump admin/package.json to an RC version when present (in
addition to bumping the core package RC); update the text around the create
command (`yarn migrate:create <name-of-database-migration>`) and the paragraph
describing package bumping to mention kebab-case and the admin RC bump so
readers aren’t surprised during onboarding.

In `@ghost/core/bin/create-migration.js`:
- Around line 75-76: fs.writeFileSync currently overwrites an existing migration
file silently; update the write to use an exclusive create flag so existing
files are not clobbered (use the fs writeFileSync option flag 'wx' for
migrationPath when writing MIGRATION_TEMPLATE). Locate the block that calls
fs.mkdirSync(versionDir, {recursive: true}) and the subsequent
fs.writeFileSync(migrationPath, MIGRATION_TEMPLATE) and replace the write with
an exclusive-write variant, and add minimal error handling around that write to
surface a clear error message if the file already exists.

In `@ghost/core/test/unit/bin/create-migration.test.js`:
- Around line 62-67: The test is creating an admin package.json outside the
isolated temp sandbox by using path.join(tmpDir, '..', 'admin'); instead, create
a single base temp directory (e.g., baseTmp) and create both core
(core/server/data/migrations/versions) and admin directories inside that base;
update the test to use a coreDir variable pointing to path.join(baseTmp, 'core')
and pass coreDir to createMigration and readVersion (replace any direct uses of
tmpDir for createMigration/readVersion with coreDir) so all files remain under
the single sandbox and do not leak into the shared temp parent.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae006d9 and 62b8eff.

📒 Files selected for processing (4)
  • .claude/skills/create-database-migration/SKILL.md
  • ghost/core/bin/create-migration.js
  • ghost/core/package.json
  • ghost/core/test/unit/bin/create-migration.test.js

Co-locates migration creation tooling within ghost/core instead of
relying on an external package. The script creates timestamped migration
files in the correct version folder and auto-bumps package.json to RC
when the first migration lands after a stable release.
@rob-ghost rob-ghost force-pushed the chore/migration-create-script branch from 62b8eff to 132fe9e Compare February 24, 2026 14:31
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
ghost/core/test/unit/bin/create-migration.test.js (1)

59-203: Add a test for the duplicate-file (EEXIST) guard.

The createMigration implementation now uses {flag: 'wx'} and throws "Migration already exists: ..." on collision, but this path has no test coverage. Since the guard was added specifically to prevent silent overwrites, it deserves its own case.

✅ Suggested test to add inside the createMigration suite
+        it('throws when migration file already exists', function () {
+            writePackageJson(coreDir, '6.19.0-rc.0');
+            const opts = {slug: 'dup-migration', coreDir, date: new Date('2026-01-01T00:00:00Z')};
+
+            createMigration(opts);
+
+            assert.throws(
+                () => createMigration(opts),
+                /Migration already exists/
+            );
+        });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ghost/core/test/unit/bin/create-migration.test.js` around lines 59 - 203, Add
a new unit test inside the existing createMigration suite that verifies the
EEXIST duplicate-file guard: call createMigration once (using writePackageJson
to set core version and a fixed date/slug), then call createMigration a second
time with the same slug and date to produce the same migration filename and
assert it throws with the message "Migration already exists:" (or matches that
string). Use the same helpers shown in the file (writePackageJson, readVersion)
and the createMigration export to locate/trigger the collision; ensure the test
checks the thrown error text rather than silently overwriting.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@ghost/core/test/unit/bin/create-migration.test.js`:
- Around line 59-203: Add a new unit test inside the existing createMigration
suite that verifies the EEXIST duplicate-file guard: call createMigration once
(using writePackageJson to set core version and a fixed date/slug), then call
createMigration a second time with the same slug and date to produce the same
migration filename and assert it throws with the message "Migration already
exists:" (or matches that string). Use the same helpers shown in the file
(writePackageJson, readVersion) and the createMigration export to locate/trigger
the collision; ensure the test checks the thrown error text rather than silently
overwriting.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 62b8eff and 132fe9e.

📒 Files selected for processing (4)
  • .claude/skills/create-database-migration/SKILL.md
  • ghost/core/bin/create-migration.js
  • ghost/core/package.json
  • ghost/core/test/unit/bin/create-migration.test.js

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant