strapi/packages/generators/app/lib/create-customized-project.js
2022-09-05 15:19:02 +02:00

185 lines
4.6 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* eslint-disable no-unreachable */
'use strict';
const { join } = require('path');
const fse = require('fs-extra');
const inquirer = require('inquirer');
const execa = require('execa');
const { merge } = require('lodash');
const stopProcess = require('./utils/stop-process');
const { trackUsage } = require('./utils/usage');
const defaultConfigs = require('./utils/db-configs');
const clientDependencies = require('./utils/db-client-dependencies');
const dbQuestions = require('./utils/db-questions');
const createProject = require('./create-project');
const LANGUAGES = {
javascript: 'JavaScript',
typescript: 'TypeScript',
};
module.exports = async (scope) => {
if (!scope.useTypescript) {
const language = await askAboutLanguages(scope);
scope.useTypescript = language === LANGUAGES.typescript;
}
await trackUsage({ event: 'didChooseCustomDatabase', scope });
const configuration = await askDbInfosAndTest(scope).catch((error) => {
return trackUsage({ event: 'didNotConnectDatabase', scope, error }).then(() => {
throw error;
});
});
console.log();
console.log('Creating a project with custom database options.');
await trackUsage({ event: 'didConnectDatabase', scope });
return createProject(scope, configuration);
};
const MAX_RETRIES = 5;
async function askDbInfosAndTest(scope) {
let retries = 0;
async function loop() {
// else ask for the client name
const { client, connection } = await askDatabaseInfos(scope);
const configuration = {
client,
connection,
dependencies: clientDependencies({ scope, client }),
};
return testDatabaseConnection({
scope,
configuration,
})
.then((result) => {
if (result && result.shouldRetry === true && retries < MAX_RETRIES - 1) {
console.log('Retrying...');
retries += 1;
return loop();
}
})
.then(
() => fse.remove(scope.tmpPath),
(err) => {
return fse.remove(scope.tmpPath).then(() => {
throw err;
});
}
)
.then(() => configuration)
.catch((err) => {
if (retries < MAX_RETRIES - 1) {
console.log();
console.log(` Connection test failed: ${err.message}`);
console.log();
if (scope.debug) {
console.log('Full error log:');
console.log(err);
}
console.log('Retrying...');
retries += 1;
return loop();
}
console.log(err);
stopProcess(
` Could not connect to your database after ${MAX_RETRIES} tries. Try to check your database configuration an retry.`
);
});
}
return loop();
}
async function testDatabaseConnection({ scope, configuration }) {
const { client } = configuration;
if (client === 'sqlite') return;
return;
// TODO: test DB connection somehow
await installDatabaseTestingDep({
scope,
configuration,
});
const connectivityFile = join(
scope.tmpPath,
'node_modules',
`@strapi/connector-${configuration.connection.connector}`,
'lib',
'utils',
'connectivity.js'
);
const tester = require(connectivityFile);
return tester({ scope, connection: configuration.connection });
}
async function askDatabaseInfos(scope) {
const { client } = await inquirer.prompt([
{
type: 'list',
name: 'client',
message: 'Choose your default database client',
choices: ['sqlite', 'postgres', 'mysql'],
default: 'sqlite',
},
]);
const responses = await inquirer.prompt(dbQuestions[client].map((q) => q({ scope, client })));
const connection = merge({}, defaultConfigs[client] || {}, {
client,
connection: responses,
});
return {
client,
connection,
};
}
async function installDatabaseTestingDep({ scope, configuration }) {
const packageManager = scope.useYarn ? 'yarnpkg' : 'npm';
const cmd = scope.useYarn
? ['--cwd', scope.tmpPath, 'add']
: ['install', '--prefix', scope.tmpPath];
// Manually create the temp directory for yarn
if (scope.useYarn) {
await fse.ensureDir(scope.tmpPath);
}
const deps = Object.keys(configuration.dependencies).map((dep) => {
return `${dep}@${configuration.dependencies[dep]}`;
});
await execa(packageManager, cmd.concat(deps));
}
async function askAboutLanguages() {
const { language } = await inquirer.prompt([
{
type: 'list',
name: 'language',
message: 'Choose your preferred language',
choices: Object.values(LANGUAGES),
default: LANGUAGES.javascript,
},
]);
return language;
}