Skip to content

Commit 1a0e1a4

Browse files
authored
Add migration guidance for dependencies instrumentation opt outs (#16240)
1 parent 6895ddc commit 1a0e1a4

5 files changed

Lines changed: 231 additions & 2 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@cloudflare/codemods": patch
3+
---
4+
5+
Explain how to preserve dependency metadata opt-outs when migrating to cf
6+
7+
Wrangler configurations with `dependencies_instrumentation.enabled` set to `false` now receive a migration follow-up directing them to `CLOUDFLARE_DEPENDENCIES_INSTRUMENTATION=false`. Package exclusion lists remain required follow-up work because the environment variable controls dependency metadata as a whole.

‎packages/codemods/src/codemods/wrangler-to-cf/worker-config.ts‎

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,66 @@ import type {
2828
OutputValue,
2929
} from "./types";
3030

31+
const DEPENDENCIES_INSTRUMENTATION_ENV_VAR =
32+
"CLOUDFLARE_DEPENDENCIES_INSTRUMENTATION";
33+
34+
function isDependenciesInstrumentationConfig(
35+
value: unknown
36+
): value is { enabled?: boolean; exclude_packages?: string[] } {
37+
if (!isRecord(value)) {
38+
return false;
39+
}
40+
41+
return (
42+
(value.enabled === undefined || typeof value.enabled === "boolean") &&
43+
(value.exclude_packages === undefined ||
44+
(Array.isArray(value.exclude_packages) &&
45+
value.exclude_packages.every(
46+
(packageName) => typeof packageName === "string"
47+
)))
48+
);
49+
}
50+
51+
function createDependenciesInstrumentationFollowUp(
52+
source: UnknownRecord,
53+
sourcePrefix: string
54+
): MigrationFollowUp | undefined {
55+
if (!hasOwn(source, "dependencies_instrumentation")) {
56+
return;
57+
}
58+
59+
const sourcePath = `${sourcePrefix ? `${sourcePrefix}.` : ""}dependencies_instrumentation`;
60+
const instrumentation = source.dependencies_instrumentation;
61+
if (!isDependenciesInstrumentationConfig(instrumentation)) {
62+
return createFollowUp(
63+
"unsupported-field",
64+
"The dependency instrumentation configuration is invalid and was not migrated.",
65+
{ sourcePath }
66+
);
67+
}
68+
69+
const hasExcludedPackages =
70+
(instrumentation.exclude_packages?.length ?? 0) > 0;
71+
72+
if (instrumentation.enabled === false) {
73+
return createFollowUp(
74+
"dependencies-instrumentation-opt-out",
75+
`Set ${DEPENDENCIES_INSTRUMENTATION_ENV_VAR}=false before deploying to keep package dependency metadata disabled.${hasExcludedPackages ? " The package exclusion list was not migrated; if dependency metadata is later enabled, those packages will be included." : ""}`,
76+
{ sourcePath }
77+
);
78+
}
79+
80+
if (hasExcludedPackages) {
81+
return createFollowUp(
82+
"dependencies-instrumentation-exclusions",
83+
`Package dependency exclusions cannot be migrated. ${DEPENDENCIES_INSTRUMENTATION_ENV_VAR} only enables or disables dependency metadata as a whole.`,
84+
{ sourcePath }
85+
);
86+
}
87+
88+
return;
89+
}
90+
3191
export function convertWorkerConfig(
3292
source: UnknownRecord,
3393
sourcePrefix: string,
@@ -268,10 +328,14 @@ export function convertWorkerConfig(
268328
)
269329
);
270330
}
331+
const dependenciesInstrumentationFollowUp =
332+
createDependenciesInstrumentationFollowUp(source, sourcePrefix);
333+
if (dependenciesInstrumentationFollowUp) {
334+
report(dependenciesInstrumentationFollowUp);
335+
}
271336

272337
const unsupportedFields: Array<[string, string]> = [
273338
["cloudchamber", "Cloudchamber configuration"],
274-
["dependencies_instrumentation", "dependency instrumentation"],
275339
["keep_vars", "keep_vars"],
276340
["pages_build_output_dir", "Pages configuration"],
277341
["site", "Workers Sites configuration"],

‎packages/codemods/test/config-converter.test.ts‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,24 @@ describe("Wrangler environment and tooling conversion", () => {
177177
);
178178
});
179179

180+
it("reports dependency instrumentation opt-outs", ({ expect }) => {
181+
const converted = convertWranglerConfig(
182+
{
183+
compatibility_date: "2026-09-23",
184+
dependencies_instrumentation: { enabled: false },
185+
name: "example-worker",
186+
},
187+
"vite",
188+
[]
189+
);
190+
191+
expect(
192+
converted.followUps
193+
.filter(({ code }) => code === "dependencies-instrumentation-opt-out")
194+
.map(({ sourcePath }) => sourcePath)
195+
).toEqual(["dependencies_instrumentation"]);
196+
});
197+
180198
it("reports a Vite assets directory once", ({ expect }) => {
181199
const result = convert({
182200
assets: { directory: "public" },

‎packages/codemods/test/worker-config.test.ts‎

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,146 @@ describe("Wrangler Worker configuration conversion", () => {
108108
expect(result).toMatchSnapshot();
109109
});
110110

111+
it("reports invalid dependency instrumentation configuration", ({
112+
expect,
113+
}) => {
114+
for (const dependenciesInstrumentation of [
115+
{ enabled: "false" },
116+
{ enabled: true, exclude_packages: "@internal/*" },
117+
{ enabled: true, exclude_packages: [123] },
118+
]) {
119+
const result = convert({
120+
compatibility_date: "2026-09-23",
121+
dependencies_instrumentation: dependenciesInstrumentation,
122+
name: "example-worker",
123+
});
124+
125+
expect(result.followUps).toEqual([
126+
expect.objectContaining({
127+
blocking: true,
128+
code: "unsupported-field",
129+
message:
130+
"The dependency instrumentation configuration is invalid and was not migrated.",
131+
sourcePath: "dependencies_instrumentation",
132+
}),
133+
]);
134+
}
135+
});
136+
137+
it("preserves recognized guidance when unknown fields are present", ({
138+
expect,
139+
}) => {
140+
const result = convert({
141+
compatibility_date: "2026-09-23",
142+
dependencies_instrumentation: {
143+
enabled: false,
144+
unknown_field: true,
145+
},
146+
name: "example-worker",
147+
});
148+
149+
expect(result.followUps).toEqual([
150+
expect.objectContaining({
151+
code: "dependencies-instrumentation-opt-out",
152+
sourcePath: "dependencies_instrumentation",
153+
}),
154+
]);
155+
expect(result.output).toContain(
156+
"CLOUDFLARE_DEPENDENCIES_INSTRUMENTATION=false"
157+
);
158+
});
159+
160+
it("reports how to preserve disabled dependency instrumentation", ({
161+
expect,
162+
}) => {
163+
const result = convert({
164+
compatibility_date: "2026-09-23",
165+
dependencies_instrumentation: { enabled: false },
166+
name: "example-worker",
167+
});
168+
169+
expect(result.followUps).toEqual([
170+
expect.objectContaining({
171+
blocking: true,
172+
code: "dependencies-instrumentation-opt-out",
173+
message:
174+
"Set CLOUDFLARE_DEPENDENCIES_INSTRUMENTATION=false before deploying to keep package dependency metadata disabled.",
175+
sourcePath: "dependencies_instrumentation",
176+
}),
177+
]);
178+
expect(result.output).toContain(
179+
"CLOUDFLARE_DEPENDENCIES_INSTRUMENTATION=false"
180+
);
181+
expect(result.output).toContain("Migration incomplete");
182+
});
183+
184+
it("reports exclusions when dependency instrumentation is disabled", ({
185+
expect,
186+
}) => {
187+
const result = convert({
188+
compatibility_date: "2026-09-23",
189+
dependencies_instrumentation: {
190+
enabled: false,
191+
exclude_packages: ["@internal/*"],
192+
},
193+
name: "example-worker",
194+
});
195+
196+
expect(result.followUps).toEqual([
197+
expect.objectContaining({
198+
blocking: true,
199+
code: "dependencies-instrumentation-opt-out",
200+
message: expect.stringContaining(
201+
"The package exclusion list was not migrated"
202+
),
203+
sourcePath: "dependencies_instrumentation",
204+
}),
205+
]);
206+
expect(result.output).toContain(
207+
"if dependency metadata is later enabled, those packages will be included"
208+
);
209+
});
210+
211+
it("drops enabled dependency instrumentation without follow-up work", ({
212+
expect,
213+
}) => {
214+
const result = convert({
215+
compatibility_date: "2026-09-23",
216+
dependencies_instrumentation: { enabled: true },
217+
name: "example-worker",
218+
});
219+
220+
expect(result.followUps).toEqual([]);
221+
expect(result.output).not.toContain(
222+
"CLOUDFLARE_DEPENDENCIES_INSTRUMENTATION"
223+
);
224+
expect(result.output).not.toContain("Migration incomplete");
225+
});
226+
227+
it("reports dependency package exclusions that cannot be preserved", ({
228+
expect,
229+
}) => {
230+
const result = convert({
231+
compatibility_date: "2026-09-23",
232+
dependencies_instrumentation: {
233+
enabled: true,
234+
exclude_packages: ["@internal/*"],
235+
},
236+
name: "example-worker",
237+
});
238+
239+
expect(result.followUps).toEqual([
240+
expect.objectContaining({
241+
blocking: true,
242+
code: "dependencies-instrumentation-exclusions",
243+
message: expect.stringContaining(
244+
"only enables or disables dependency metadata as a whole"
245+
),
246+
sourcePath: "dependencies_instrumentation",
247+
}),
248+
]);
249+
});
250+
111251
it("converts Workflow bindings and exports the Workflows the Worker defines", ({
112252
expect,
113253
}) => {

‎packages/codemods/test/wrangler-to-cf/schema-coverage.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ const FIELD_CASES = {
5353
],
5454
data_blobs: { DATA: "data.bin" },
5555
define: { FEATURE: "true" },
56-
dependencies_instrumentation: { enabled: true },
56+
dependencies_instrumentation: { enabled: false },
5757
dev: { port: 8788 },
5858
dispatch_namespaces: [{ binding: "DISPATCH", namespace: "namespace" }],
5959
durable_objects: {

0 commit comments

Comments
 (0)