Merge branch 'deits/architecture-rework' into deits/transfer-protocol

This commit is contained in:
Convly 2023-01-03 17:45:55 +01:00
commit e46c7617df
9 changed files with 68 additions and 65 deletions

View File

@ -8,5 +8,6 @@ export JWT_SECRET="aSecret"
opts=($DB_OPTIONS)
yarn run -s build:ts
yarn run -s test:generate-app "${opts[@]}"
yarn run -s test:api --no-generate-app

View File

@ -133,8 +133,6 @@ jobs:
path: '**/node_modules'
key: ${{ runner.os }}-${{ matrix.node }}-${{ hashFiles('**/yarn.lock') }}
- run: yarn install --frozen-lockfile
- name: Build TypeScript packages
run: yarn build:t
- uses: ./.github/actions/run-api-tests
with:
dbOptions: '--dbclient=postgres --dbhost=localhost --dbport=5432 --dbname=strapi_test --dbusername=strapi --dbpassword=strapi'
@ -173,8 +171,6 @@ jobs:
path: '**/node_modules'
key: ${{ runner.os }}-${{ matrix.node }}-${{ hashFiles('**/yarn.lock') }}
- run: yarn install --frozen-lockfile
- name: Build TypeScript packages
run: yarn build:t
- uses: ./.github/actions/run-api-tests
with:
dbOptions: '--dbclient=mysql --dbhost=localhost --dbport=3306 --dbname=strapi_test --dbusername=strapi --dbpassword=strapi'
@ -212,8 +208,6 @@ jobs:
path: '**/node_modules'
key: ${{ runner.os }}-${{ matrix.node }}-${{ hashFiles('**/yarn.lock') }}
- run: yarn install --frozen-lockfile
- name: Build TypeScript packages
run: yarn build:t
- uses: ./.github/actions/run-api-tests
with:
dbOptions: '--dbclient=mysql --dbhost=localhost --dbport=3306 --dbname=strapi_test --dbusername=strapi --dbpassword=strapi'
@ -236,8 +230,6 @@ jobs:
path: '**/node_modules'
key: ${{ runner.os }}-${{ matrix.node }}-${{ hashFiles('**/yarn.lock') }}
- run: yarn install --frozen-lockfile
- name: Build TypeScript packages
run: yarn build:t
- uses: ./.github/actions/run-api-tests
env:
SQLITE_PKG: ${{ matrix.sqlite_pkg }}
@ -284,8 +276,6 @@ jobs:
path: '**/node_modules'
key: ${{ runner.os }}-${{ matrix.node }}-${{ hashFiles('**/yarn.lock') }}
- run: yarn install --frozen-lockfile
- name: Build TypeScript packages
run: yarn build:t
- uses: ./.github/actions/run-api-tests
with:
dbOptions: '--dbclient=postgres --dbhost=localhost --dbport=5432 --dbname=strapi_test --dbusername=strapi --dbpassword=strapi'
@ -328,8 +318,6 @@ jobs:
path: '**/node_modules'
key: ${{ runner.os }}-${{ matrix.node }}-${{ hashFiles('**/yarn.lock') }}
- run: yarn install --frozen-lockfile
- name: Build TypeScript packages
run: yarn build:t
- uses: ./.github/actions/run-api-tests
with:
dbOptions: '--dbclient=mysql --dbhost=localhost --dbport=3306 --dbname=strapi_test --dbusername=strapi --dbpassword=strapi'
@ -356,8 +344,6 @@ jobs:
path: '**/node_modules'
key: ${{ runner.os }}-${{ matrix.node }}-${{ hashFiles('**/yarn.lock') }}
- run: yarn install --frozen-lockfile
- name: Build TypeScript packages
run: yarn build:t
- uses: ./.github/actions/run-api-tests
env:
SQLITE_PKG: ${{ matrix.sqlite_pkg }}

View File

@ -0,0 +1 @@
export const TRANSFER_URL = '/transfer';

View File

@ -1,2 +1,3 @@
export * as controllers from './controllers';
export * as routes from './routes';
export * as constants from './constants';

View File

@ -1,6 +1,7 @@
// eslint-disable-next-line node/no-extraneous-import
import type { Context } from 'koa';
import { TRANSFER_URL } from './constants';
import { createTransferHandler } from './handlers';
// Extend Strapi interface type to access the admin routes' API
@ -28,7 +29,7 @@ declare module '@strapi/strapi' {
export const registerAdminTransferRoute = (strapi: Strapi.Strapi) => {
strapi.admin.routes.push({
method: 'GET',
path: '/transfer',
path: TRANSFER_URL,
handler: createTransferHandler(),
config: { auth: false },
});

View File

@ -262,8 +262,16 @@ program
program
.command('transfer')
.description('Transfer data from one source to another')
.addOption(new Option('--from <source>', `Source of your data`).default('local'))
.addOption(new Option('--to <destination>', `Destination of your data`).default('remote'))
.addOption(new Option('--from <sourceURL>', `URL of remote Strapi instance to get data from.`))
.addOption(new Option('--to <destinationURL>', `URL of remote Strapi instance to send data to`))
.hook('preAction', async (thisCommand) => {
const opts = thisCommand.opts();
if (!opts.from && !opts.to) {
console.error('At least one source (from) or destination (to) option must be provided');
process.exit(1);
}
})
.allowExcessArguments(false)
.action(getLocalScript('transfer/transfer'));

View File

@ -32,7 +32,9 @@ const expectExit = async (code, fn) => {
const transferCommand = require('../../transfer/transfer');
const logger = jest.spyOn(console, 'error').mockImplementation(() => {});
jest.spyOn(console, 'error').mockImplementation(() => {});
jest.spyOn(console, 'warn').mockImplementation(() => {});
jest.spyOn(console, 'log').mockImplementation(() => {});
jest.mock('../../transfer/utils');
@ -45,7 +47,7 @@ describe('Transfer', () => {
it('uses destination url provided by user without authentication', async () => {
await expectExit(1, async () => {
await transferCommand({ from: 'local', to: destinationUrl });
await transferCommand({ from: undefined, to: destinationUrl });
});
expect(
@ -61,7 +63,7 @@ describe('Transfer', () => {
it('uses restore as the default strategy', async () => {
await expectExit(1, async () => {
await transferCommand({ from: 'local', to: destinationUrl });
await transferCommand({ from: undefined, to: destinationUrl });
});
expect(
@ -74,7 +76,7 @@ describe('Transfer', () => {
});
it('uses destination url provided by user without authentication', async () => {
await expectExit(1, async () => {
await transferCommand({ from: 'local', to: destinationUrl });
await transferCommand({ from: undefined, to: destinationUrl });
});
expect(
@ -88,7 +90,7 @@ describe('Transfer', () => {
it('uses restore as the default strategy', async () => {
await expectExit(1, async () => {
await transferCommand({ from: 'local', to: destinationUrl });
await transferCommand({ from: undefined, to: destinationUrl });
});
expect(
@ -102,18 +104,10 @@ describe('Transfer', () => {
it('uses local strapi instance when local specified', async () => {
await expectExit(1, async () => {
await transferCommand({ from: 'local', to: destinationUrl });
await transferCommand({ from: undefined, to: destinationUrl });
});
expect(mockDataTransfer.strapi.providers.createLocalStrapiSourceProvider).toHaveBeenCalled();
expect(utils.createStrapiInstance).toHaveBeenCalled();
});
it('Logs an error when the source provider does not exist', async () => {
await expectExit(1, async () => {
await transferCommand({ from: 'test', to: destinationUrl });
});
expect(logger).toHaveBeenCalledWith("Couldn't create providers");
});
});

View File

@ -2,7 +2,11 @@
const { createTransferEngine } = require('@strapi/data-transfer/lib/engine');
const {
providers: { createRemoteStrapiDestinationProvider, createLocalStrapiSourceProvider },
providers: {
createRemoteStrapiDestinationProvider,
createLocalStrapiSourceProvider,
createLocalStrapiDestinationProvider,
},
} = require('@strapi/data-transfer/lib/strapi');
const { isObject } = require('lodash/fp');
const chalk = require('chalk');
@ -13,17 +17,17 @@ const {
DEFAULT_IGNORED_CONTENT_TYPES,
} = require('./utils');
/**
* @typedef TransferCommandOptions Options given to the CLI import command
*
* @property {string} [from] The source strapi project
* @property {string} [to] The destination strapi project
*/
const logger = console;
/**
* Import command.
* @typedef TransferCommandOptions Options given to the CLI transfer command
*
* @property {string|undefined} [to] The url of a remote Strapi to use as remote destination
* @property {string|undefined} [from] The url of a remote Strapi to use as remote source
*/
/**
* Transfer command.
*
* It transfers data from a local file to a local strapi instance
*
@ -40,11 +44,33 @@ module.exports = async (opts) => {
let source;
let destination;
if (opts.from === 'local') {
source = createSourceProvider(strapi);
if (!opts.from && !opts.to) {
logger.error('At least one source (from) or destination (to) option must be provided');
process.exit(1);
}
if (opts.to) {
destination = createDestinationProvider({
// if no URL provided, use local Strapi
if (!opts.from) {
source = createLocalStrapiSourceProvider({
getStrapi: () => strapi,
});
}
// if URL provided, set up a remote source provider
else {
logger.error(`Remote Strapi source provider not yet implemented`);
process.exit(1);
}
// if no URL provided, use local Strapi
if (!opts.to) {
destination = createLocalStrapiDestinationProvider({
getStrapi: () => strapi,
});
}
// if URL provided, set up a remote destination provider
else {
destination = createRemoteStrapiDestinationProvider({
url: opts.to,
auth: false,
strategy: 'restore',
@ -53,8 +79,9 @@ module.exports = async (opts) => {
},
});
}
if (!source || !destination) {
logger.error("Couldn't create providers");
logger.error('Could not create providers');
process.exit(1);
}
@ -83,7 +110,7 @@ module.exports = async (opts) => {
});
try {
logger.log(`Starting export...`);
logger.log(`Starting transfer...`);
const results = await engine.transfer();
@ -93,25 +120,8 @@ module.exports = async (opts) => {
logger.log(`${chalk.bold('Transfer process has been completed successfully!')}`);
process.exit(0);
} catch (e) {
logger.error('Transfer process failed unexpectedly:', e);
logger.error('Transfer process failed unexpectedly');
logger.error(e);
process.exit(1);
}
};
/**
* It creates a local strapi destination provider
*/
const createSourceProvider = (strapi) => {
return createLocalStrapiSourceProvider({
async getStrapi() {
return strapi;
},
});
};
/**
* It creates a remote strapi destination provider based on the given options
*/
const createDestinationProvider = (opts) => {
return createRemoteStrapiDestinationProvider(opts);
};

View File

@ -81,6 +81,7 @@
"@koa/cors": "3.4.3",
"@koa/router": "10.1.1",
"@strapi/admin": "4.5.5",
"@strapi/data-transfer": "4.5.5",
"@strapi/database": "4.5.5",
"@strapi/data-transfer": "4.5.5",
"@strapi/generate-new": "4.5.5",