diff --git a/.changeset/gorgeous-parrots-bow.md b/.changeset/gorgeous-parrots-bow.md new file mode 100644 index 00000000..553f41fb --- /dev/null +++ b/.changeset/gorgeous-parrots-bow.md @@ -0,0 +1,5 @@ +--- +'@openstapps/api-cli': minor +--- + +Add "\*" option to copy command that allows for a full database clone diff --git a/packages/api-cli/README.md b/packages/api-cli/README.md index 02b689f6..483bfb37 100644 --- a/packages/api-cli/README.md +++ b/packages/api-cli/README.md @@ -20,6 +20,12 @@ npm run build node ./lib/cli.js e2e http://localhost:3000 ``` +Example to clone the full database + +```shell +node app.js copy "*" https://mobile.app.uni-frankfurt.de http://localhost:3000 100 +``` + ### Program arguments ```shell diff --git a/packages/api-cli/src/app.ts b/packages/api-cli/src/app.ts index e4f8d3bd..80b1eb60 100644 --- a/packages/api-cli/src/app.ts +++ b/packages/api-cli/src/app.ts @@ -15,12 +15,11 @@ import {SCThingType} from '@openstapps/core'; import {Logger} from '@openstapps/logger'; import {Command} from 'commander'; -import {readFileSync} from 'fs'; -import path from 'path'; -import {fileURLToPath, URL} from 'url'; +import {URL} from 'url'; import waitOn from 'wait-on'; import {HttpClient} from '@openstapps/api'; import {copy} from './copy.js'; +import {version} from '../package.json'; // eslint-disable-next-line unicorn/prevent-abbreviations import {e2eRun} from './e2e.js'; @@ -28,11 +27,6 @@ process.on('unhandledRejection', async error => { await Logger.error('unhandledRejection', error); }); -// eslint-disable-next-line unicorn/prefer-module -const packageJson = JSON.parse( - readFileSync(path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'package.json')).toString(), -); - const client = new HttpClient(); const commander = new Command(); const helpAndExit = (help: string) => { @@ -43,7 +37,7 @@ const helpAndExit = (help: string) => { commander .command('e2e ') - .version(packageJson.version) + .version(version) .description( 'Run in end to end test mode. Indexing and afterwards retrieving all test files from @openstapp/core to the backend', ) @@ -87,15 +81,14 @@ commander commander .command('copy ') - .version(packageJson.version) + .version(version) .description('Copy data from one instance to another') .option( '-s, --bulkSource ', 'The source identifier for the bulk to use with the target instance [copy]', 'copy', ) - // TODO: remove - .option('-a, --appVersion ', 'The App version to use [unset by default]') + .option('-a, --appVersion ', 'The App version to use [unset by default]', version) .allowUnknownOption(false) .action(async (type, from, to, batchSize, copyCommand) => { // validate type @@ -123,23 +116,36 @@ commander helpAndExit(copyCommand.helpInformation()); } - Logger.info(`Copying ${type} objects from ${fromURL} to ${toURL}`); + /** + * Copy a single type from one backend to another + */ + async function copySingleType(type: string) { + Logger.info(`Copying ${type} objects from ${fromURL} to ${toURL}`); - copy(client, { - batchSize: Number.parseInt(batchSize, 10), - from: fromURL, - source: copyCommand.bulkSource, - to: toURL, - type: type as SCThingType, - version: copyCommand.appVersion, - }).then( - () => { - Logger.ok('Done'); - }, - error => { - throw error; - }, - ); + await copy(client, { + batchSize: Number.parseInt(batchSize, 10), + from: fromURL, + source: copyCommand.bulkSource, + to: toURL, + type: type as SCThingType, + version: copyCommand.appVersion, + }); + Logger.ok('done'); + } + + if (type === '*') { + const types = Object.values(SCThingType); + for (const [i, type] of types.entries()) { + Logger.info(`Copying ${type} (${i + 1} / ${types.length})`); + try { + await copySingleType(type); + } catch (error) { + await Logger.error(error); + } + } + } else { + await copySingleType(type); + } }); commander.parse(process.argv);