Skip to content

[codemod] Add migration CLI - #14690

Open
penalosa wants to merge 16 commits into
mainfrom
penalosa/codemods
Open

[codemod] Add migration CLI#14690
penalosa wants to merge 16 commits into
mainfrom
penalosa/codemods

Conversation

@penalosa

@penalosa penalosa commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Makes @cloudflare/codemods a public, executable package for running Cloudflare project migrations, and extracts the shared recast helpers into a private @cloudflare/shared-ast-primitives library.

What's included

  • A cloudflare-codemods <codemod> CLI that runs a single named codemod against a project — with --cwd, --files, and --dry-run options.
  • The initial codemods cover the Workers Vitest migrations:
    • vitest:v3-to-v4 — migrate @cloudflare/vitest-pool-workers configuration from Vitest v3 to v4
    • vitest:pool-workers-to-vitest-plugin — rename @cloudflare/vitest-pool-workers to @cloudflare/vitest-plugin v1
  • Transforms are string-in/string-out and authored on top of @cloudflare/shared-ast-primitives (a recast wrapper shared with C3 and autoconfig) — the existing Vitest v3-to-v4 transform moves out of @cloudflare/vitest-pool-workers and into this package.
  • Each codemod stages its file writes in memory and only flushes them once it completes successfully — a codemod that throws part-way leaves the project untouched.

Codemods are identified and run individually by name (e.g. npx @cloudflare/codemods vitest:v3-to-v4); there's no category grouping.


  • Tests
    • Tests included/updated
    • Automated tests not possible - manual testing has been completed as follows:
    • Additional testing not necessary because:
  • Public documentation
    • Cloudflare docs PR(s):
    • Documentation not necessary because: the package README documents the CLI and its options.

A picture of a cute animal (not mandatory, but encouraged)

@changeset-bot

changeset-bot Bot commented Jul 14, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 0effaad

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@cloudflare/codemods Minor
@cloudflare/vitest-pool-workers Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

Copy link
Copy Markdown
Contributor

✅ All changesets look good

ask-bonk[bot]

This comment was marked as resolved.

@ask-bonk

ask-bonk Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Review posted successfully to PR #14690 with a summary and two inline suggestion comments.

Summary of what I flagged:

  1. No error handling in bin.ts — expected validation errors print a full stack trace instead of a clean CLI message + non-zero exit. (suggestion posted)
  2. --files replaces default patterns entirely rather than intersecting, so scoping one codemod can misfire across the category. (suggestion posted)
  3. Preflight can't catch failures that depend on a prior codemod's output, weakening the "no partial changes" guarantee. (documented in summary; no single-line fix)

github run

@pkg-pr-new

pkg-pr-new Bot commented Jul 14, 2026

Copy link
Copy Markdown
@cloudflare/autoconfig

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/autoconfig@14690

@cloudflare/build-output-utils

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/build-output-utils@14690

@cloudflare/codemods

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/codemods@14690

@cloudflare/config

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/config@14690

create-cloudflare

npm i https://pkg.pr.new/cloudflare/workers-sdk/create-cloudflare@14690

@cloudflare/deploy-helpers

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/deploy-helpers@14690

@cloudflare/kv-asset-handler

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/kv-asset-handler@14690

miniflare

npm i https://pkg.pr.new/cloudflare/workers-sdk/miniflare@14690

@cloudflare/pages-functions

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/pages-functions@14690

@cloudflare/pages-shared

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/pages-shared@14690

@cloudflare/unenv-preset

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/unenv-preset@14690

@cloudflare/vite-plugin

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/vite-plugin@14690

@cloudflare/vitest-pool-workers

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/vitest-pool-workers@14690

@cloudflare/workers-auth

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/workers-auth@14690

@cloudflare/workers-editor-shared

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/workers-editor-shared@14690

@cloudflare/workers-utils

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/workers-utils@14690

wrangler

npm i https://pkg.pr.new/cloudflare/workers-sdk/wrangler@14690

commit: 70cfea9

@penalosa

This comment was marked as outdated.

@penalosa
penalosa force-pushed the penalosa/codemods branch from 25bcf37 to 0267d3f Compare July 21, 2026 13:26
penalosa added 7 commits July 21, 2026 15:30
Separate the two unrelated concerns that were sharing `packages/codemod`:

- `@cloudflare/codemods` (`packages/codemods`) — the public Vitest migration
  CLI, run via `npx @cloudflare/codemods vitest`. Bin renamed to
  `cloudflare-codemods`.
- `@cloudflare/shared-ast-primitives` (`packages/shared-ast-primitives`) — the
  private `recast`-based AST helpers consumed by C3 and autoconfig, restored to
  `private: true`.

Update all `@cloudflare/codemod` consumers in autoconfig and create-cloudflare to
import from `@cloudflare/shared-ast-primitives`, and the deploy-package
validation set accordingly.
Rewrite the Vitest v3→v4 transform on top of `@cloudflare/shared-ast-primitives`
(recast) instead of jscodeshift, dropping the `jscodeshift` and
`@types/jscodeshift` dev dependencies. The shared library now re-exports the
`print`/`types` recast primitives and types `parseJs`/`parseTs` return values so
transforms can be authored without a direct recast dependency.
Split the codemod context into `CodemodContext` and a `RunContext` that requires
`stagedFiles`, so `transformFiles` always stages in memory. Removes the unreachable
direct-to-disk write branch, keeping the ordered run atomic (flushed only after all
codemods succeed).
Remove the category grouping and the batch "run every codemod in a category"
behaviour. Codemods are now identified by a single `vitest:`-prefixed name
(e.g. `vitest:v3-to-v4`) and run one at a time via `runCodemod(name, context)`.
The CLI takes a single codemod name as its positional argument.
@penalosa
penalosa marked this pull request as ready for review August 7, 2026 11:03
@workers-devprod
workers-devprod requested review from a team and edmundhung and removed request for a team August 7, 2026 11:04
@workers-devprod

workers-devprod commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Codeowners approval required for this PR:

  • ✅ @cloudflare/wrangler
Show detailed file reviewers

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

- Rename stale `@cloudflare/vitest-pool-workers` references anywhere in
  package.json (scripts, `pnpm.overrides`, `resolutions`), not just the four
  dependency groups, so a migrated project has no leftover references.
- Update `vitest-pool-workers` AGENTS.md to drop the removed codemods build.
devin-ai-integration[bot]

This comment was marked as resolved.

@dario-piotrowicz
dario-piotrowicz removed the request for review from edmundhung August 7, 2026 14:05
@dario-piotrowicz
dario-piotrowicz self-requested a review August 7, 2026 14:05

@dario-piotrowicz dario-piotrowicz left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM 🙂

I just left a few small nits

Comment thread packages/shared-ast-primitives/src/index.ts Outdated
Comment thread packages/shared-ast-primitives/src/index.ts Outdated
Comment thread packages/codemods/src/runner.ts Outdated
Comment thread packages/codemods/src/bin.ts Outdated

@workers-devprod workers-devprod left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Codeowners reviews satisfied

@github-project-automation github-project-automation Bot moved this from Untriaged to Approved in workers-sdk Aug 7, 2026
@workers-devprod

Copy link
Copy Markdown
Contributor

Codeowners approval required for this PR:

  • ✅ @cloudflare/wrangler
Show detailed file reviewers

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Devin Review found 1 new potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment on lines +88 to +103
{
name: "vitest:pool-workers-to-vitest-plugin",
aliases: ["vitest pool workers to vitest plugin", "vitest v1"],
description: `Rename ${OLD_PACKAGE} to ${NEW_PACKAGE} v1`,
async run(context) {
const changedFiles = await transformFiles(
context,
SOURCE_PATTERNS,
(source, filePath) =>
filePath.endsWith("package.json")
? renamePackageDependency(source)
: source.replaceAll(OLD_PACKAGE, NEW_PACKAGE)
);
return { changedFiles };
},
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Running the two Vitest migrations in the wrong order silently leaves configuration unmigrated

The configuration migration only recognises files that still mention the old package name (transformV3ToV4 at packages/codemods/src/codemods/vitest.ts:83), so if the rename migration is run first it quietly does nothing and reports success.

Impact: Users who run the rename step first end up with a renamed but still-unmigrated test configuration and no warning that the second migration did not apply.

Why the second ordering fails: the v3→v4 transform matches on the literal old package specifier

packages/codemods/src/codemods/vitest-v3-to-v4.ts:56-61 only selects import declarations whose source is exactly "@cloudflare/vitest-pool-workers/config". The vitest:pool-workers-to-vitest-plugin codemod rewrites every textual occurrence of @cloudflare/vitest-pool-workers to @cloudflare/vitest-plugin (packages/codemods/src/codemods/vitest.ts:99), including that import specifier. After that rename, matchingImports.length === 0 and transform() returns the source unchanged (packages/codemods/src/codemods/vitest-v3-to-v4.ts:88-90), so transformFiles reports zero changed files and the CLI prints "Project is already up to date." (packages/codemods/src/bin.ts:57-61).

The repo's own test runs them in the correct order (packages/codemods/test/runner.test.ts:59-63), but nothing in the CLI or README (packages/codemods/README.md:11-16) states that order is significant, and each codemod is invoked individually by name.

Prompt for agents
The two Vitest codemods in packages/codemods/src/codemods/vitest.ts are order-dependent: `vitest:v3-to-v4` matches imports from the literal specifier "@cloudflare/vitest-pool-workers/config", while `vitest:pool-workers-to-vitest-plugin` textually rewrites that specifier to "@cloudflare/vitest-plugin". If a user runs the rename first (each codemod is run individually by name from the CLI), the v3→v4 transform becomes a silent no-op and the CLI reports the project as already up to date. Consider either making the v3→v4 transform also recognise the new package specifier (`@cloudflare/vitest-plugin/config`), or having the rename codemod detect a still-v3-shaped config and error/warn, or documenting and enforcing the required ordering in the CLI/README.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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

Labels

None yet

Projects

Status: Approved

Development

Successfully merging this pull request may close these issues.

3 participants