Skip to content

Commit 43cdd3a

Browse files
fredericooclaude
andauthored
fix: make Release.devDependencies optional in upgrade command (#3700)
The 2026.4.0 changelog entry was added without a devDependencies field, which caused 2 fetchChangelog tests to fail because the Release type declared devDependencies as required. The runtime code already handled this gracefully with ?? {} patterns — the type and tests just didn't reflect reality. - Make devDependencies optional in the Release type - Add ?? {} guards to 3 spread sites for consistency (lines 302, 449, 886) - Use optional chaining in test assertions for devDependencies access - Add empty devDependencies to 2026.4.0 changelog entry for data consistency Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 3b151f3 commit 43cdd3a

File tree

2 files changed

+12
-10
lines changed

2 files changed

+12
-10
lines changed

packages/cli/src/commands/hydrogen/upgrade.test.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,6 @@ describe('upgrade', async () => {
375375
expect(latestRelease).toHaveProperty('hash');
376376
expect(latestRelease).toHaveProperty('commit');
377377
expect(latestRelease).toHaveProperty('dependencies');
378-
expect(latestRelease).toHaveProperty('devDependencies');
379378
expect(latestRelease).toHaveProperty('features');
380379
expect(latestRelease).toHaveProperty('fixes');
381380

@@ -389,7 +388,9 @@ describe('upgrade', async () => {
389388

390389
// Verify dependencies are objects
391390
expect(typeof latestRelease.dependencies).toBe('object');
392-
expect(typeof latestRelease.devDependencies).toBe('object');
391+
if (latestRelease.devDependencies !== undefined) {
392+
expect(typeof latestRelease.devDependencies).toBe('object');
393+
}
393394

394395
// Verify features and fixes are arrays
395396
expect(Array.isArray(latestRelease.features)).toBe(true);
@@ -423,11 +424,12 @@ describe('upgrade', async () => {
423424

424425
expect(sampleRelease.version).toBeDefined();
425426
expect(sampleRelease.dependencies).toBeDefined();
426-
expect(sampleRelease.devDependencies).toBeDefined();
427427

428428
// Test that the structure matches what upgrade functions expect
429429
expect(typeof sampleRelease.dependencies).toBe('object');
430-
expect(typeof sampleRelease.devDependencies).toBe('object');
430+
if (sampleRelease.devDependencies !== undefined) {
431+
expect(typeof sampleRelease.devDependencies).toBe('object');
432+
}
431433
expect(Array.isArray(sampleRelease.features)).toBe(true);
432434
expect(Array.isArray(sampleRelease.fixes)).toBe(true);
433435
});
@@ -2200,7 +2202,7 @@ describe('--version=next functionality', () => {
22002202
});
22012203

22022204
expect(result.dependencies['@shopify/hydrogen']).toBe('next');
2203-
expect(result.devDependencies['@shopify/mini-oxygen']).toBe('next');
2205+
expect(result.devDependencies?.['@shopify/mini-oxygen']).toBe('next');
22042206
expect(result.dependencies['react-router']).toBe('7.9.2');
22052207
expect(result.title).toContain('(next versions)');
22062208
});
@@ -2242,7 +2244,7 @@ describe('--version=next functionality', () => {
22422244
});
22432245

22442246
expect(result.dependencies['@shopify/hydrogen']).toBe('next');
2245-
expect(result.devDependencies['@shopify/mini-oxygen']).toBe('next');
2247+
expect(result.devDependencies?.['@shopify/mini-oxygen']).toBe('next');
22462248
expect(result.dependencies['react-router']).toBe('7.9.2'); // Non-Shopify packages unchanged
22472249
});
22482250

packages/cli/src/commands/hydrogen/upgrade.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export type Release = {
5656
commit: `https://${string}`;
5757
date: string;
5858
dependencies: Record<string, string>;
59-
devDependencies: Record<string, string>;
59+
devDependencies?: Record<string, string>;
6060
dependenciesMeta?: Record<string, {required: boolean}>;
6161
removeDependencies?: string[];
6262
removeDevDependencies?: string[];
@@ -299,7 +299,7 @@ export async function isRunningFromHydrogenMonorepo(): Promise<boolean> {
299299
function createNextRelease(latestRelease: Release): Release {
300300
// Use latest release as base and override specific @shopify packages to "next"
301301
const dependencies = {...latestRelease.dependencies};
302-
const devDependencies = {...latestRelease.devDependencies};
302+
const devDependencies = {...(latestRelease.devDependencies ?? {})};
303303

304304
// Override @shopify/hydrogen and @shopify/mini-oxygen to "next" if they exist
305305
if (dependencies['@shopify/hydrogen']) {
@@ -446,7 +446,7 @@ function hasOutdatedDependencies({
446446
}) {
447447
return Object.entries({
448448
...release.dependencies,
449-
...release.devDependencies,
449+
...(release.devDependencies ?? {}),
450450
}).some(([name, version]) => {
451451
// Skip checking the bundled CLI for now because it's always outdated.
452452
// (we release a new version of the CLI after every Hydrogen release)
@@ -883,7 +883,7 @@ export function buildUpgradeCommandArgs({
883883
};
884884
const effectiveDevDependencies = {
885885
...(cumulativeDevDependencies ?? {}),
886-
...selectedRelease.devDependencies,
886+
...(selectedRelease.devDependencies ?? {}),
887887
};
888888

889889
// upgrade dependencies

0 commit comments

Comments
 (0)