storybook/scripts/bootstrap.js
Norbert de Langen 504d40faab
fix reset script
2022-07-26 09:32:13 +02:00

259 lines
6.6 KiB
JavaScript
Executable File

#!/usr/bin/env node
/* eslint-disable global-require */
const { spawnSync } = require('child_process');
const { join } = require('path');
const { maxConcurrentTasks } = require('./utils/concurrency');
const spawn = (command, options = {}) => {
return spawnSync(`${command}`, {
shell: true,
stdio: 'inherit',
...options,
});
};
function run() {
const prompts = require('prompts');
const program = require('commander');
const chalk = require('chalk');
const log = require('npmlog');
log.heading = 'storybook';
const prefix = 'bootstrap';
log.addLevel('aborted', 3001, { fg: 'red', bold: true });
const main = program
.version('5.0.0')
.option('--all', `Bootstrap everything ${chalk.gray('(all)')}`);
const createTask = ({
defaultValue,
option,
name,
check = () => true,
command,
pre = [],
order,
}) => ({
value: false,
defaultValue: defaultValue || false,
option: option || undefined,
name: name || 'unnamed task',
check: check || (() => true),
order,
command: () => {
// run all pre tasks
pre
.map((key) => tasks[key])
.forEach((task) => {
if (task.check()) {
task.command();
}
});
log.info(prefix, name);
command();
},
});
const tasks = {
core: createTask({
name: `Core & Examples ${chalk.gray('(core)')}`,
defaultValue: false,
option: '--core',
command: () => {
log.info(prefix, 'yarn workspace');
},
pre: ['install', 'build'],
order: 1,
}),
prep: createTask({
name: `Prep for development ${chalk.gray('(prep)')}`,
defaultValue: true,
option: '--prep',
command: () => {
log.info(prefix, 'prepare');
spawn(
`nx run-many --target="prepare" --all --parallel --exclude=@storybook/addon-storyshots,@storybook/addon-storyshots-puppeteer -- --reset`
);
},
order: 2,
}),
retry: createTask({
name: `Core & Examples but only build previously failed ${chalk.gray('(core)')}`,
defaultValue: true,
option: '--retry',
command: () => {
log.info(prefix, 'prepare');
spawn(
`nx run-many --target=prepare --all --parallel --only-failed ${
process.env.CI ? `--max-parallel=${maxConcurrentTasks}` : ''
}`
);
},
order: 1,
}),
cleanup: createTask({
name: `Remove compiled dist directories ${chalk.gray('(cleanup)')}`,
defaultValue: false,
option: '--cleanup',
command: () => {
spawn('npm run clean:dist');
},
order: 0,
}),
reset: createTask({
name: `Clean repository ${chalk.red('(reset)')}`,
defaultValue: false,
option: '--reset',
command: () => {
log.info(prefix, 'git clean');
spawn(`node -r esm ${join(__dirname, 'reset.js')}`);
},
order: 0,
}),
install: createTask({
name: `Install dependencies ${chalk.gray('(install)')}`,
defaultValue: false,
option: '--install',
command: () => {
const command = process.env.CI ? `yarn install --immutable` : `yarn install`;
spawn(command);
},
order: 1,
}),
build: createTask({
name: `Build packages ${chalk.gray('(build)')}`,
defaultValue: false,
option: '--build',
command: () => {
log.info(prefix, 'build');
spawn(
`nx run-many --target="prepare" --all --parallel=8 ${
process.env.CI ? `--max-parallel=${maxConcurrentTasks}` : ''
} -- --reset --optimized`
);
},
order: 2,
}),
registry: createTask({
name: `Run local registry ${chalk.gray('(reg)')}`,
defaultValue: false,
option: '--reg',
command: () => {
spawn('yarn local-registry --publish --open --port 6000');
},
order: 11,
}),
dev: createTask({
name: `Run build in watch mode ${chalk.gray('(dev)')}`,
defaultValue: false,
option: '--dev',
command: () => {
spawn('yarn build');
},
order: 9,
}),
};
const groups = {
main: ['prep', 'core'],
buildtasks: ['install', 'build'],
devtasks: ['dev', 'registry', 'cleanup', 'reset'],
};
Object.keys(tasks)
.reduce((acc, key) => acc.option(tasks[key].option, tasks[key].name), main)
.parse(process.argv);
Object.keys(tasks).forEach((key) => {
tasks[key].value = program[tasks[key].option.replace('--', '')] || program.all;
});
const createSeparator = (input) => ({
title: `- ${input}${' ---------'.substr(0, 12)}`,
disabled: true,
});
const choices = Object.values(groups)
.map((l) =>
l.map((key) => ({
value: tasks[key].name,
title: tasks[key].name,
selected: tasks[key].defaultValue,
}))
)
.reduce((acc, i, k) => acc.concat(createSeparator(Object.keys(groups)[k])).concat(i), []);
let selection;
if (
!Object.keys(tasks)
.map((key) => tasks[key].value)
.filter(Boolean).length
) {
selection = prompts([
{
type: 'multiselect',
message: 'Select the bootstrap activities',
name: 'todo',
warn: ' ',
pageSize: Object.keys(tasks).length + Object.keys(groups).length,
choices,
},
])
.then(({ todo }) =>
todo.map((name) => tasks[Object.keys(tasks).find((i) => tasks[i].name === name)])
)
.then((list) => {
if (list.find((i) => i === tasks.reset)) {
return prompts([
{
type: 'confirm',
message: `${chalk.red(
'DESTRUCTIVE'
)} deletes node_modules, files not present in git ${chalk.underline(
'will get trashed'
)}, except for .idea and .vscode, ${chalk.cyan('Continue?')}`,
name: 'sure',
},
]).then(({ sure }) => {
if (sure) {
return list;
}
throw new Error('Cleanup canceled');
});
}
return list;
});
} else {
selection = Promise.resolve(
Object.keys(tasks)
.map((key) => tasks[key])
.filter((item) => item.value === true)
);
}
selection
.then((list) => {
if (list.length === 0) {
log.warn(prefix, 'Nothing to bootstrap');
} else {
list
.sort((a, b) => a.order - b.order)
.forEach((key) => {
key.command();
});
process.stdout.write('\x07');
}
})
.catch((e) => {
log.aborted(prefix, chalk.red(e.message));
log.silly(prefix, e);
process.exit(1);
});
}
run();