Skip to content

Commit

Permalink
Skip plugins and themes in internal Studio wp-cli commands like impor…
Browse files Browse the repository at this point in the history
…t export (#748)

- Let's skip plugins and themes executing wp-cli for Studio internal commands.
- Keep the regular wp-cli behaviour for commands executed by the assistant
  • Loading branch information
sejas authored Dec 18, 2024
1 parent 4533c37 commit 4b9f1ee
Show file tree
Hide file tree
Showing 11 changed files with 74 additions and 13 deletions.
10 changes: 10 additions & 0 deletions src/hooks/tests/use-chat-context.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,12 @@ describe( 'useChatContext hook', () => {
expect( getIpcApi().executeWPCLiInline ).toHaveBeenNthCalledWith( 1, {
siteId: SELECTED_SITE.id,
args: 'plugin list --format=json --status=active',
skipPluginsAndThemes: true,
} );
expect( getIpcApi().executeWPCLiInline ).toHaveBeenNthCalledWith( 2, {
siteId: SELECTED_SITE.id,
args: 'theme list --format=json',
skipPluginsAndThemes: true,
} );
expect( getIpcApi().executeWPCLiInline ).toHaveBeenCalledTimes( 2 );
} );
Expand Down Expand Up @@ -234,10 +236,12 @@ describe( 'useChatContext hook', () => {
expect( getIpcApi().executeWPCLiInline ).toHaveBeenNthCalledWith( 1, {
siteId: ANOTHER_SITE.id,
args: 'plugin list --format=json --status=active',
skipPluginsAndThemes: true,
} );
expect( getIpcApi().executeWPCLiInline ).toHaveBeenNthCalledWith( 2, {
siteId: ANOTHER_SITE.id,
args: 'theme list --format=json',
skipPluginsAndThemes: true,
} );
expect( getIpcApi().executeWPCLiInline ).toHaveBeenCalledTimes( 2 );
} );
Expand Down Expand Up @@ -288,10 +292,12 @@ describe( 'useChatContext hook', () => {
expect( getIpcApi().executeWPCLiInline ).toHaveBeenNthCalledWith( 1, {
siteId: SELECTED_SITE.id,
args: 'plugin list --format=json --status=active',
skipPluginsAndThemes: true,
} );
expect( getIpcApi().executeWPCLiInline ).toHaveBeenNthCalledWith( 2, {
siteId: SELECTED_SITE.id,
args: 'theme list --format=json',
skipPluginsAndThemes: true,
} );
expect( getIpcApi().executeWPCLiInline ).toHaveBeenCalledTimes( 2 );
} );
Expand Down Expand Up @@ -391,10 +397,12 @@ describe( 'useChatContext hook', () => {
expect( getIpcApi().executeWPCLiInline ).toHaveBeenNthCalledWith( 1, {
siteId: NEW_SITE.id,
args: 'plugin list --format=json --status=active',
skipPluginsAndThemes: true,
} );
expect( getIpcApi().executeWPCLiInline ).toHaveBeenNthCalledWith( 2, {
siteId: NEW_SITE.id,
args: 'theme list --format=json',
skipPluginsAndThemes: true,
} );
expect( getIpcApi().executeWPCLiInline ).toHaveBeenCalledTimes( 2 );
} );
Expand Down Expand Up @@ -436,10 +444,12 @@ describe( 'useChatContext hook', () => {
expect( getIpcApi().executeWPCLiInline ).toHaveBeenNthCalledWith( 1, {
siteId: SELECTED_SITE.id,
args: 'plugin list --format=json --status=active',
skipPluginsAndThemes: true,
} );
expect( getIpcApi().executeWPCLiInline ).toHaveBeenNthCalledWith( 2, {
siteId: SELECTED_SITE.id,
args: 'theme list --format=json',
skipPluginsAndThemes: true,
} );
expect( getIpcApi().executeWPCLiInline ).toHaveBeenCalledTimes( 2 );
} );
Expand Down
2 changes: 2 additions & 0 deletions src/hooks/use-chat-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export const ChatProvider: React.FC< ChatProviderProps > = ( { children } ) => {
const { stdout, stderr } = await getIpcApi().executeWPCLiInline( {
siteId,
args: 'plugin list --format=json --status=active',
skipPluginsAndThemes: true,
} );
if ( stderr ) {
return [];
Expand All @@ -91,6 +92,7 @@ export const ChatProvider: React.FC< ChatProviderProps > = ( { children } ) => {
const { stdout, stderr } = await getIpcApi().executeWPCLiInline( {
siteId,
args: 'theme list --format=json',
skipPluginsAndThemes: true,
} );
if ( stderr ) {
return [];
Expand Down
1 change: 1 addition & 0 deletions src/hooks/use-execute-cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export function useExecuteWPCLI(
const result = await getIpcApi().executeWPCLiInline( {
siteId: siteId || '',
args: args.join( ' ' ),
skipPluginsAndThemes: false,
} );

const msTime = Date.now() - startTime;
Expand Down
14 changes: 12 additions & 2 deletions src/ipc-handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -815,7 +815,15 @@ export async function saveOnboarding(

export async function executeWPCLiInline(
_event: IpcMainInvokeEvent,
{ siteId, args }: { siteId: string; args: string }
{
siteId,
args,
skipPluginsAndThemes = false,
}: {
siteId: string;
args: string;
skipPluginsAndThemes?: boolean;
}
): Promise< WpCliResult > {
if ( SiteServer.isDeleted( siteId ) ) {
return {
Expand All @@ -828,7 +836,9 @@ export async function executeWPCLiInline(
if ( ! server ) {
throw new Error( 'Site not found.' );
}
return server.executeWpCliCommand( args );
return server.executeWpCliCommand( args, {
skipPluginsAndThemes,
} );
}

export async function getThumbnailData( _event: IpcMainInvokeEvent, id: string ) {
Expand Down
15 changes: 12 additions & 3 deletions src/lib/import-export/export/export-database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ export async function exportDatabaseToFile(

// Execute the command to export directly to the temp file
const { stderr, exitCode } = await server.executeWpCliCommand(
`sqlite export ${ tempFileName } --require=/tmp/sqlite-command/command.php`
`sqlite export ${ tempFileName } --require=/tmp/sqlite-command/command.php`,
{
skipPluginsAndThemes: true,
}
);

if ( stderr ) {
Expand Down Expand Up @@ -47,7 +50,10 @@ export async function exportDatabaseToMultipleFiles(
}

const tablesResult = await server.executeWpCliCommand(
`sqlite tables --format=json --require=/tmp/sqlite-command/command.php`
`sqlite tables --format=json --require=/tmp/sqlite-command/command.php`,
{
skipPluginsAndThemes: true,
}
);
if ( tablesResult.stderr ) {
throw new Error( `Database export failed: ${ tablesResult.stderr }` );
Expand Down Expand Up @@ -79,7 +85,10 @@ export async function exportDatabaseToMultipleFiles(

// Execute the command to export directly to a temporary file in the project directory
const { stderr, exitCode } = await server.executeWpCliCommand(
`sqlite export ${ fileName } --tables=${ table } --require=/tmp/sqlite-command/command.php`
`sqlite export ${ fileName } --tables=${ table } --require=/tmp/sqlite-command/command.php`,
{
skipPluginsAndThemes: true,
}
);

if ( stderr ) {
Expand Down
10 changes: 8 additions & 2 deletions src/lib/import-export/export/exporters/default-exporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,10 @@ export class DefaultExporter extends EventEmitter implements Exporter {
}

const { stderr, stdout } = await server.executeWpCliCommand(
'plugin list --status=active,inactive --fields=name,status,version --format=json'
'plugin list --status=active,inactive --fields=name,status,version --format=json',
{
skipPluginsAndThemes: true,
}
);

if ( stderr ) {
Expand Down Expand Up @@ -296,7 +299,10 @@ export class DefaultExporter extends EventEmitter implements Exporter {
}

const { stderr, stdout } = await server.executeWpCliCommand(
'theme list --fields=name,status,version --format=json'
'theme list --fields=name,status,version --format=json',
{
skipPluginsAndThemes: true,
}
);

if ( stderr ) {
Expand Down
11 changes: 8 additions & 3 deletions src/lib/import-export/import/importers/importer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ abstract class BaseImporter extends EventEmitter implements Importer {
const { stderr, exitCode } = await server.executeWpCliCommand(
`sqlite import ${ sqlTempFile } --require=/tmp/sqlite-command/command.php`,
// SQLite plugin requires PHP 8+
{ targetPhpVersion: DEFAULT_PHP_VERSION }
{ targetPhpVersion: DEFAULT_PHP_VERSION, skipPluginsAndThemes: true }
);

if ( stderr ) {
Expand Down Expand Up @@ -86,7 +86,9 @@ abstract class BaseImporter extends EventEmitter implements Importer {
throw new Error( 'Site not found.' );
}

const { stdout: currentSiteUrl } = await server.executeWpCliCommand( `option get siteurl` );
const { stdout: currentSiteUrl } = await server.executeWpCliCommand( `option get siteurl`, {
skipPluginsAndThemes: true,
} );

if ( ! currentSiteUrl ) {
console.error( 'Failed to fetch site URL after import' );
Expand All @@ -96,7 +98,10 @@ abstract class BaseImporter extends EventEmitter implements Importer {
const studioUrl = `http://localhost:${ server.details.port }`;

const { stderr, exitCode } = await server.executeWpCliCommand(
`search-replace '${ currentSiteUrl.trim() }' '${ studioUrl.trim() }'`
`search-replace '${ currentSiteUrl.trim() }' '${ studioUrl.trim() }'`,
{
skipPluginsAndThemes: true,
}
);

if ( stderr ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ describe( 'SqlExporter', () => {

const siteServer = SiteServer.get( '123' );
expect( siteServer?.executeWpCliCommand ).toHaveBeenCalledWith(
'sqlite export studio-backup-db-export-2024-08-01-12-00-00.sql --require=/tmp/sqlite-command/command.php'
'sqlite export studio-backup-db-export-2024-08-01-12-00-00.sql --require=/tmp/sqlite-command/command.php',
{
skipPluginsAndThemes: true,
}
);
} );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,11 @@ describe( 'JetpackImporter', () => {
'sqlite import studio-backup-sql-2024-08-01-12-00-00.sql --require=/tmp/sqlite-command/command.php';
expect( siteServer?.executeWpCliCommand ).toHaveBeenNthCalledWith( 1, expectedCommand, {
targetPhpVersion: '8.1',
skipPluginsAndThemes: true,
} );
expect( siteServer?.executeWpCliCommand ).toHaveBeenNthCalledWith( 2, expectedCommand, {
targetPhpVersion: '8.1',
skipPluginsAndThemes: true,
} );

const expectedUnlinkPath = '/path/to/studio/site/studio-backup-sql-2024-08-01-12-00-00.sql';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ describe( 'localImporter', () => {
const siteServer = SiteServer.get( mockStudioSiteId );

const expectedCommand = 'option get siteurl';
expect( siteServer?.executeWpCliCommand ).toHaveBeenNthCalledWith( 1, expectedCommand );
expect( siteServer?.executeWpCliCommand ).toHaveBeenNthCalledWith( 1, expectedCommand, {
skipPluginsAndThemes: true,
} );

expect( move ).toHaveBeenNthCalledWith(
1,
Expand Down
13 changes: 12 additions & 1 deletion src/site-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,13 @@ export class SiteServer {

async executeWpCliCommand(
args: string,
{ targetPhpVersion }: { targetPhpVersion?: string } = {}
{
targetPhpVersion,
skipPluginsAndThemes = false,
}: {
targetPhpVersion?: string;
skipPluginsAndThemes?: boolean;
} = {}
): Promise< WpCliResult > {
const projectPath = this.details.path;
const phpVersion = targetPhpVersion ?? this.details.phpVersion;
Expand All @@ -180,6 +186,11 @@ export class SiteServer {

const wpCliArgs = parse( args );

if ( skipPluginsAndThemes ) {
wpCliArgs.push( '--skip-plugins' );
wpCliArgs.push( '--skip-themes' );
}

// The parsing of arguments can include shell operators like `>` or `||` that the app don't support.
const isValidCommand = wpCliArgs.every(
( arg: unknown ) => typeof arg === 'string' || arg instanceof String
Expand Down

0 comments on commit 4b9f1ee

Please sign in to comment.