Skip to content

Commit

Permalink
Improve logic for checking valid exporters (#414)
Browse files Browse the repository at this point in the history
* Fix `wp-load.php` path in export unit tests

* Make required paths match more robust in default export process

* Throw error when no exporter can be found

* Fix not found valid exporter case
  • Loading branch information
fluiddot authored Aug 2, 2024
1 parent 46e7e35 commit bcf3c4f
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 4 deletions.
8 changes: 7 additions & 1 deletion src/lib/import-export/export/export-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ export async function exportBackup(
onEvent: ( data: ImportExportEventData ) => void,
exporters: NewExporter[] = defaultExporterOptions
): Promise< void > {
let foundValidExporter;
for ( const Exporter of exporters ) {
const exporterInstance = new Exporter( exportOptions );
const removeExportListeners = handleEvents( exporterInstance, onEvent, ExportEvents );
if ( await exporterInstance.canHandle() ) {
foundValidExporter = await exporterInstance.canHandle();
if ( foundValidExporter ) {
try {
await exporterInstance.export();
} finally {
Expand All @@ -20,6 +22,10 @@ export async function exportBackup(
break;
}
}
if ( ! foundValidExporter ) {
onEvent( { event: ExportEvents.EXPORT_ERROR, data: null } );
throw new Error( 'No suitable exporter found for the site' );
}
}

export const defaultExporterOptions: NewExporter[] = [ DefaultExporter, SqlExporter ];
14 changes: 12 additions & 2 deletions src/lib/import-export/export/exporters/default-exporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,22 @@ export class DefaultExporter extends EventEmitter implements Exporter {
return false;
}

const requiredPaths = [ 'wp-content', 'wp-includes', 'wp-load.php', 'wp-config.php' ];
const requiredPaths = [
{ path: 'wp-content', isDir: true },
{ path: 'wp-includes', isDir: true },
{ path: 'wp-load.php', isDir: false },
{ path: 'wp-config.php', isDir: false },
];

this.siteFiles = await this.getSiteFiles();

return requiredPaths.every( ( requiredPath ) =>
this.siteFiles.some( ( file ) => file.includes( requiredPath ) )
this.siteFiles.some( ( file ) => {
const relativePath = path.relative( this.options.site.path, file );
return requiredPath.isDir
? relativePath.startsWith( requiredPath.path )
: relativePath === requiredPath.path;
} )
);
}

Expand Down
28 changes: 28 additions & 0 deletions src/lib/import-export/tests/export/export-manager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,32 @@ describe( 'exportBackup', () => {
expect( MockExporter2 ).toHaveBeenCalledWith( mockExportOptions );
expect( ExportMethod2 ).toHaveBeenCalled();
} );

it( 'fails if no exporter is found', async () => {
const ExportMethod1 = jest.fn();
const MockExporter1 = jest.fn( () => ( {
canHandle: jest.fn().mockResolvedValue( false ),
export: ExportMethod1,
on: jest.fn(),
emit: jest.fn(),
} ) );

const ExportMethod2 = jest.fn();
const MockExporter2 = jest.fn( () => ( {
canHandle: jest.fn().mockResolvedValue( false ),
export: ExportMethod2,
on: jest.fn(),
emit: jest.fn(),
} ) );

const exporters: NewExporter[] = [ MockExporter1, MockExporter2 ];
await expect( exportBackup( mockExportOptions, jest.fn(), exporters ) ).rejects.toThrow(
'No suitable exporter found for the site'
);

expect( MockExporter1 ).toHaveBeenCalledWith( mockExportOptions );
expect( ExportMethod1 ).not.toHaveBeenCalled();
expect( MockExporter2 ).toHaveBeenCalledWith( mockExportOptions );
expect( ExportMethod2 ).not.toHaveBeenCalled();
} );
} );
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ describe( 'DefaultExporter', () => {
{ path: '/path/to/site/wp-content/plugins/plugin1', name: 'plugin1.php', isFile: () => true },
{ path: '/path/to/site/wp-content/themes/theme1', name: 'index.php', isFile: () => true },
{ path: '/path/to/site/wp-includes/index.php', name: 'index.php', isFile: () => true },
{ path: '/path/to/site/wp-load.php', name: 'wp-load.php', isFile: () => true },
{ path: '/path/to/site', name: 'wp-load.php', isFile: () => true },
];

( fsPromises.readdir as jest.Mock ).mockResolvedValue( mockFiles );
Expand Down

0 comments on commit bcf3c4f

Please sign in to comment.