diff --git a/apps/cli/commands/site/create.ts b/apps/cli/commands/site/create.ts index 3881ff7a09..628356a115 100644 --- a/apps/cli/commands/site/create.ts +++ b/apps/cli/commands/site/create.ts @@ -659,7 +659,7 @@ export async function runCommand( try { if ( isOnlineStatus ) { - const updated = await updateServerFiles(); + const updated = await updateServerFiles( options.wpVersion === DEFAULT_WORDPRESS_VERSION ); if ( updated ) { logger.reportSuccess( __( 'Dependencies updated' ) ); } diff --git a/apps/cli/lib/dependency-management/setup.ts b/apps/cli/lib/dependency-management/setup.ts index 73ebb7a8b3..384fd95b8a 100644 --- a/apps/cli/lib/dependency-management/setup.ts +++ b/apps/cli/lib/dependency-management/setup.ts @@ -79,9 +79,13 @@ async function markDependencyCheckTime(): Promise< void > { /** * Checks for and applies dependency updates (e.g. WordPress versions), throttled * to at most once per 24 hours. Returns true if the check ran, false if skipped. + * + * @param force Bypass the throttle. Site creation passes this for "latest", + * which installs by copying the cached directory instead of + * downloading a numbered release, so the cache has to be current. */ -export async function updateServerFiles(): Promise< boolean > { - if ( ! ( await shouldCheckDependencyUpdates() ) ) { +export async function updateServerFiles( force = false ): Promise< boolean > { + if ( ! force && ! ( await shouldCheckDependencyUpdates() ) ) { return false; } diff --git a/apps/cli/lib/dependency-management/tests/setup.test.ts b/apps/cli/lib/dependency-management/tests/setup.test.ts index 2c74c7ddbc..e8ea14813e 100644 --- a/apps/cli/lib/dependency-management/tests/setup.test.ts +++ b/apps/cli/lib/dependency-management/tests/setup.test.ts @@ -65,6 +65,22 @@ describe( 'updateServerFiles', () => { expect( updateLatestWordPressVersion ).not.toHaveBeenCalled(); } ); + it( 'runs the update inside the interval when forced', async () => { + // Creating a site on "latest" installs by copying the cached directory, + // so it has to verify the cache is current no matter when we last looked. + vi.mocked( readCliConfig ).mockResolvedValue( { + version: 1, + sites: [], + snapshots: [], + lastDependencyCheckTime: NOW - 60 * 1000, + } ); + + const result = await updateServerFiles( true ); + + expect( result ).toBe( true ); + expect( updateLatestWordPressVersion ).toHaveBeenCalledTimes( 1 ); + } ); + it( 'runs the update when the timestamp is in the future (clock skew)', async () => { vi.mocked( readCliConfig ).mockResolvedValue( { version: 1, diff --git a/packages/common/lib/mu-plugins.ts b/packages/common/lib/mu-plugins.ts index 7f2837ba83..4f2d086ba2 100644 --- a/packages/common/lib/mu-plugins.ts +++ b/packages/common/lib/mu-plugins.ts @@ -362,8 +362,11 @@ function getStandardMuPlugins( options: MuPluginOptions ): MuPlugin[] { `, } ); - // Configure auto-updates based on Studio settings - if ( ! options.isWpAutoUpdating ) { + // Only an explicit `false` disables auto-updates. Sites created before this + // option existed have no flag, and every other reader treats that as + // auto-updating — reading it as falsy here left them pinned for good while + // Settings showed "latest" (STU-2348). + if ( options.isWpAutoUpdating === false ) { muPlugins.push( { filename: '0-disable-auto-updates.php', content: ` { expect( generatedPlugins ).not.toContain( '0-disable-auto-updates.php' ); } ); + it.each( [ + [ 'enables them when the flag is true', true, '0-enable-auto-updates.php' ], + [ 'disables them only on an explicit false', false, '0-disable-auto-updates.php' ], + // Sites created before the flag existed have no value. The settings UI reads + // that as auto-updating, so the mu-plugins must agree (STU-2348). + [ 'enables them when the flag is unset', undefined, '0-enable-auto-updates.php' ], + ] )( 'auto-updates: %s', async ( _label, flag, expected ) => { + const muPluginsDir = await writeStudioMuPluginsForNativePhpRuntime( sitePath, flag ); + const generatedPlugins = await readdir( muPluginsDir ); + + const other = + expected === '0-enable-auto-updates.php' + ? '0-disable-auto-updates.php' + : '0-enable-auto-updates.php'; + expect( generatedPlugins ).toContain( expected ); + expect( generatedPlugins ).not.toContain( other ); + } ); + it( 'should reuse the existing mu-plugins directory when contents are up to date', async () => { const firstDir = await writeStudioMuPluginsForNativePhpRuntime( sitePath, false ); const secondDir = await writeStudioMuPluginsForNativePhpRuntime( sitePath, false );