create-strapi-starter
Advanced tools
Comparing version 4.0.0-beta.14 to 4.0.0-beta.15
@@ -24,3 +24,3 @@ 'use strict'; | ||
.version(packageJson.version) | ||
.arguments('[directory], [starterurl]') | ||
.arguments('[directory], [starter]') | ||
.option('--use-npm', 'Force usage of npm instead of yarn to create the project') | ||
@@ -41,4 +41,4 @@ .option('--debug', 'Display database connection error') | ||
) | ||
.action((directory, starterUrl, programArgs) => { | ||
const projectArgs = { projectName: directory, starterUrl }; | ||
.action((directory, starter, programArgs) => { | ||
const projectArgs = { projectName: directory, starter }; | ||
@@ -49,5 +49,5 @@ initProject(projectArgs, programArgs); | ||
function generateApp(projectArgs, programArgs) { | ||
if (!projectArgs.projectName || !projectArgs.starterUrl) { | ||
if (!projectArgs.projectName || !projectArgs.starter) { | ||
console.error( | ||
'Please specify the <directory> and <starterurl> of your project when using --quickstart' | ||
'Please specify the <directory> and <starter> of your project when using --quickstart' | ||
); | ||
@@ -77,3 +77,4 @@ // eslint-disable-next-line no-process-exit | ||
const { projectName, starterUrl } = projectArgs; | ||
const { projectName, starter } = projectArgs; | ||
if (program.quickstart) { | ||
@@ -83,7 +84,7 @@ return generateApp(projectArgs, program); | ||
const prompt = await promptUser(projectName, starterUrl, program); | ||
const prompt = await promptUser(projectName, starter, program); | ||
const promptProjectArgs = { | ||
projectName: prompt.directory || projectName, | ||
starterUrl: prompt.starter || starterUrl, | ||
starter: prompt.starter || starter, | ||
}; | ||
@@ -90,0 +91,0 @@ |
{ | ||
"name": "create-strapi-starter", | ||
"version": "4.0.0-beta.14", | ||
"version": "4.0.0-beta.15", | ||
"description": "Generate a new Strapi application.", | ||
@@ -19,14 +19,10 @@ "license": "SEE LICENSE IN LICENSE", | ||
"dependencies": { | ||
"@strapi/generate-new": "4.0.0-beta.14", | ||
"@strapi/generate-new": "4.0.0-beta.15", | ||
"chalk": "4.1.1", | ||
"ci-info": "3.1.1", | ||
"commander": "7.1.0", | ||
"execa": "5.0.0", | ||
"execa": "^5.1.1", | ||
"fs-extra": "9.1.0", | ||
"git-url-parse": "11.4.4", | ||
"inquirer": "8.2.0", | ||
"js-yaml": "4.1.0", | ||
"node-fetch": "^2.6.1", | ||
"ora": "5.4.0", | ||
"tar": "6.1.11" | ||
"ora": "5.4.0" | ||
}, | ||
@@ -52,3 +48,3 @@ "scripts": { | ||
}, | ||
"gitHead": "0c0789354d34c685b94474911b79c1b679155dfa" | ||
"gitHead": "c69713bf7f437a7cee66ffdeed95227d6246a872" | ||
} |
@@ -6,3 +6,2 @@ 'use strict'; | ||
const fse = require('fs-extra'); | ||
const ora = require('ora'); | ||
@@ -12,7 +11,7 @@ const ciEnv = require('ci-info'); | ||
const generateNewApp = require('@strapi/generate-new'); | ||
const { generateNewApp } = require('@strapi/generate-new'); | ||
const hasYarn = require('./has-yarn'); | ||
const { runInstall, runApp, initGit } = require('./child-process'); | ||
const { getRepoInfo, downloadGitHubRepo } = require('./fetch-github'); | ||
const { getStarterPackageInfo, downloadNpmStarter } = require('./fetch-npm-starter'); | ||
const logger = require('./logger'); | ||
@@ -24,3 +23,3 @@ const stopProcess = require('./stop-process'); | ||
*/ | ||
function readStarterJson(filePath, starterUrl) { | ||
function readStarterJson(filePath, starter) { | ||
try { | ||
@@ -30,3 +29,3 @@ const data = fse.readFileSync(filePath); | ||
} catch (err) { | ||
stopProcess(`Could not find ${chalk.yellow('starter.json')} in ${chalk.yellow(starterUrl)}`); | ||
stopProcess(`Could not find ${chalk.yellow('starter.json')} in ${chalk.yellow(starter)}`); | ||
} | ||
@@ -36,7 +35,9 @@ } | ||
/** | ||
* @param {string} rootPath - Path to the project directory | ||
* @param {string} projectName - Name of the project | ||
* @param {string} rootPath - Path to the project directory | ||
* @param {string} projectName - Name of the project | ||
* @param {Object} options | ||
* @param {boolean} options.useYarn - Use yarn instead of npm | ||
*/ | ||
async function initPackageJson(rootPath, projectName) { | ||
const packageManager = hasYarn() ? 'yarn --cwd' : 'npm run --prefix'; | ||
async function initPackageJson(rootPath, projectName, { useYarn } = {}) { | ||
const packageManager = useYarn ? 'yarn --cwd' : 'npm run --prefix'; | ||
@@ -71,5 +72,7 @@ try { | ||
/** | ||
* @param {string} path - The directory path for install | ||
* @param {string} path The directory path for install | ||
* @param {Object} options | ||
* @param {boolean} options.useYarn Use yarn instead of npm | ||
*/ | ||
async function installWithLogs(path) { | ||
async function installWithLogs(path, options) { | ||
const installPrefix = chalk.yellow('Installing dependencies:'); | ||
@@ -84,3 +87,3 @@ const loader = ora(installPrefix).start(); | ||
const runner = runInstall(path); | ||
const runner = runInstall(path, options); | ||
runner.stdout.on('data', logInstall); | ||
@@ -96,25 +99,49 @@ runner.stderr.on('data', logInstall); | ||
/** | ||
* @param {Object} projectArgs - The arguments for create a project | ||
* @param {string|null} projectArgs.projectName - The name/path of project | ||
* @param {string|null} projectArgs.starterUrl - The GitHub repo of the starter | ||
* @param {Object} program - Commands for generating new application | ||
* @param {string} starter The name of the starter as provided by the user | ||
* @param {Object} options | ||
* @param {boolean} options.useYarn Use yarn instead of npm | ||
*/ | ||
module.exports = async function buildStarter(programArgs, program) { | ||
let { projectName, starterUrl } = programArgs; | ||
async function getStarterInfo(starter, { useYarn } = {}) { | ||
const isLocalStarter = ['./', '../', '/'].some(filePrefix => starter.startsWith(filePrefix)); | ||
// Fetch repo info | ||
const repoInfo = await getRepoInfo(starterUrl); | ||
const { fullName } = repoInfo; | ||
let starterPath; | ||
let starterParentPath; | ||
let starterPackageInfo = {}; | ||
// Create temporary directory for starter | ||
const tmpDir = await fse.mkdtemp(join(os.tmpdir(), 'strapi-')); | ||
if (isLocalStarter) { | ||
// Starter is a local directory | ||
console.log('Installing local starter.'); | ||
starterPath = resolve(starter); | ||
} else { | ||
// Starter should be an npm package. Fetch starter info | ||
starterPackageInfo = await getStarterPackageInfo(starter, { useYarn }); | ||
console.log(`Installing ${chalk.yellow(starterPackageInfo.name)} starter.`); | ||
// Download repo inside temporary directory | ||
await downloadGitHubRepo(repoInfo, tmpDir); | ||
// Download starter repository to a temporary directory | ||
starterParentPath = await fse.mkdtemp(join(os.tmpdir(), 'strapi-')); | ||
starterPath = await downloadNpmStarter(starterPackageInfo, starterParentPath, { useYarn }); | ||
} | ||
const starterJson = readStarterJson(join(tmpDir, 'starter.json'), starterUrl); | ||
return { isLocalStarter, starterPath, starterParentPath, starterPackageInfo }; | ||
} | ||
/** | ||
* @param {Object} projectArgs - The arguments for create a project | ||
* @param {string|null} projectArgs.projectName - The name/path of project | ||
* @param {string|null} projectArgs.starter - The npm package of the starter | ||
* @param {Object} program - Commands for generating new application | ||
*/ | ||
module.exports = async function buildStarter({ projectName, starter }, program) { | ||
const hasYarnInstalled = await hasYarn(); | ||
const { | ||
isLocalStarter, | ||
starterPath, | ||
starterParentPath, | ||
starterPackageInfo, | ||
} = await getStarterInfo(starter, { useYarn: hasYarnInstalled }); | ||
// Project directory | ||
const rootPath = resolve(projectName); | ||
const projectBasename = basename(rootPath); | ||
const starterJson = readStarterJson(join(starterPath, 'starter.json'), starter); | ||
@@ -130,6 +157,4 @@ try { | ||
const starterDir = (await fse.pathExists(join(tmpDir, 'starter'))) ? 'starter' : 'frontend'; | ||
try { | ||
await fse.copy(join(tmpDir, starterDir), frontendPath, { | ||
await fse.copy(join(starterPath, 'starter'), frontendPath, { | ||
overwrite: true, | ||
@@ -142,13 +167,18 @@ recursive: true, | ||
// Delete temporary directory | ||
await fse.remove(tmpDir); | ||
// Delete the starter directory if it was downloaded | ||
if (!isLocalStarter) { | ||
await fse.remove(starterParentPath); | ||
} | ||
const fullUrl = `https://github.com/${fullName}`; | ||
// Set command options for Strapi app | ||
const generateStrapiAppOptions = { | ||
...program, | ||
starter: fullUrl, | ||
template: starterJson.template, | ||
starter: starterPackageInfo.name, | ||
run: false, | ||
}; | ||
if (starterPackageInfo.version) { | ||
starterPackageInfo.template = `${starterJson.template.name}@${starterJson.template.version}`; | ||
} else { | ||
starterPackageInfo.template = starterJson.template.name; | ||
} | ||
@@ -159,8 +189,8 @@ // Create strapi app using the template | ||
// Install frontend dependencies | ||
console.log(`Creating Strapi starter frontend at ${chalk.green(frontendPath)}.`); | ||
console.log(`Installing ${chalk.yellow(fullName)} starter`); | ||
await installWithLogs(frontendPath); | ||
console.log(`Creating Strapi starter frontend at ${chalk.yellow(frontendPath)}.`); | ||
console.log('Installing frontend dependencies'); | ||
await installWithLogs(frontendPath, { useYarn: hasYarnInstalled }); | ||
// Setup monorepo | ||
initPackageJson(rootPath, projectBasename); | ||
initPackageJson(rootPath, projectBasename, { useYarn: hasYarnInstalled }); | ||
@@ -175,3 +205,3 @@ // Add gitignore | ||
await installWithLogs(rootPath); | ||
await installWithLogs(rootPath, { useYarn: hasYarnInstalled }); | ||
@@ -183,3 +213,3 @@ if (!ciEnv.isCI) { | ||
console.log(chalk.green('Starting the app')); | ||
await runApp(rootPath); | ||
await runApp(rootPath, { useYarn: hasYarnInstalled }); | ||
}; |
@@ -5,21 +5,23 @@ 'use strict'; | ||
const execa = require('execa'); | ||
const hasYarn = require('./has-yarn'); | ||
const logger = require('./logger'); | ||
/** | ||
* @param {string} path Path to directory (frontend, backend) | ||
* @param {string} path Path to directory (frontend, backend) | ||
* @param {Object} options | ||
* @param {boolean} options.useYarn Use yarn instead of npm | ||
*/ | ||
function runInstall(path) { | ||
if (hasYarn()) { | ||
return execa('yarn', ['install'], { | ||
cwd: path, | ||
stdin: 'ignore', | ||
}); | ||
} | ||
return execa('npm', ['install'], { cwd: path, stdin: 'ignore' }); | ||
function runInstall(path, { useYarn } = {}) { | ||
return execa(useYarn ? 'yarn' : 'npm', ['install'], { | ||
cwd: path, | ||
stdin: 'ignore', | ||
}); | ||
} | ||
function runApp(rootPath) { | ||
if (hasYarn()) { | ||
/** | ||
* @param {string} rootPath | ||
* @param {Object} options | ||
* @param {boolean} options.useYarn | ||
*/ | ||
function runApp(rootPath, { useYarn } = {}) { | ||
if (useYarn) { | ||
return execa('yarn', ['develop'], { | ||
@@ -26,0 +28,0 @@ stdio: 'inherit', |
@@ -5,8 +5,7 @@ 'use strict'; | ||
module.exports = function hasYarn() { | ||
module.exports = async function hasYarn() { | ||
try { | ||
const { exitCode } = execa.sync('yarn --version', { shell: true }); | ||
const { exitCode } = await execa.commandSync('yarn --version', { shell: true }); | ||
if (exitCode === 0) return true; | ||
return false; | ||
} catch (err) { | ||
@@ -13,0 +12,0 @@ return false; |
'use strict'; | ||
const inquirer = require('inquirer'); | ||
const fetch = require('node-fetch'); | ||
const yaml = require('js-yaml'); | ||
@@ -58,48 +56,8 @@ /** | ||
async function getStarterQuestion() { | ||
const content = await getStarterData(); | ||
// Fallback to manual input when fetch fails | ||
if (!content) { | ||
return { | ||
type: 'input', | ||
message: 'Please provide the GitHub URL for the starter you would like to use:', | ||
}; | ||
} | ||
const choices = content.map(option => { | ||
const name = option.title.replace('Starter', ''); | ||
return { | ||
name, | ||
value: `https://github.com/${option.repo}`, | ||
}; | ||
}); | ||
// Ask user to manually input his starter | ||
// TODO: find way to suggest the possible v4 starters | ||
return { | ||
type: 'list', | ||
message: | ||
'Which starter would you like to use? (Starters are fullstack Strapi applications designed for a specific use case)', | ||
pageSize: choices.length, | ||
choices, | ||
type: 'input', | ||
message: 'Please provide the npm package name of the starter you want to use:', | ||
}; | ||
} | ||
/** | ||
* | ||
* @returns JSON starter data | ||
*/ | ||
async function getStarterData() { | ||
const response = await fetch( | ||
`https://api.github.com/repos/strapi/community-content/contents/starters/starters.yml` | ||
); | ||
if (!response.ok) { | ||
return null; | ||
} | ||
const { content } = await response.json(); | ||
const buff = Buffer.from(content, 'base64'); | ||
const stringified = buff.toString('utf-8'); | ||
return yaml.load(stringified); | ||
} |
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
20189
8
1
478
2
+ Added@strapi/generate-new@4.0.0-beta.15(transitive)
+ Addedexeca@5.1.1(transitive)
- Removedgit-url-parse@11.4.4
- Removedjs-yaml@4.1.0
- Removednode-fetch@^2.6.1
- Removedtar@6.1.11
- Removed@strapi/generate-new@4.0.0-beta.14(transitive)
- Removedargparse@2.0.1(transitive)
- Removedcall-bind-apply-helpers@1.0.1(transitive)
- Removedcall-bound@1.0.3(transitive)
- Removeddecode-uri-component@0.2.2(transitive)
- Removeddunder-proto@1.0.1(transitive)
- Removedes-define-property@1.0.1(transitive)
- Removedes-errors@1.3.0(transitive)
- Removedes-object-atoms@1.1.1(transitive)
- Removedexeca@5.0.0(transitive)
- Removedfilter-obj@1.1.0(transitive)
- Removedfunction-bind@1.1.2(transitive)
- Removedget-intrinsic@1.2.7(transitive)
- Removedget-proto@1.0.1(transitive)
- Removedgit-up@4.0.5(transitive)
- Removedgit-url-parse@11.4.4(transitive)
- Removedgopd@1.2.0(transitive)
- Removedhas-symbols@1.1.0(transitive)
- Removedhasown@2.0.2(transitive)
- Removedis-ssh@1.4.0(transitive)
- Removedjs-yaml@4.1.0(transitive)
- Removedmath-intrinsics@1.1.0(transitive)
- Removednormalize-url@6.1.0(transitive)
- Removedobject-inspect@1.13.3(transitive)
- Removedparse-path@4.0.4(transitive)
- Removedparse-url@6.0.5(transitive)
- Removedprotocols@1.4.82.0.1(transitive)
- Removedqs@6.14.0(transitive)
- Removedquery-string@6.14.1(transitive)
- Removedside-channel@1.1.0(transitive)
- Removedside-channel-list@1.0.0(transitive)
- Removedside-channel-map@1.0.1(transitive)
- Removedside-channel-weakmap@1.0.2(transitive)
- Removedsplit-on-first@1.1.0(transitive)
- Removedstrict-uri-encode@2.0.0(transitive)
Updatedexeca@^5.1.1