-
-
Notifications
You must be signed in to change notification settings - Fork 9.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ADD a CLI for bootstrapping #1216
Changes from 19 commits
369ac55
5726f13
27edf5e
4f4b9e4
9fafeab
86c25d6
6aad7a1
8146294
31f83aa
1327e2d
02e0950
540ec9a
c85776a
de7777e
ed0e61e
b215110
7940e62
879928d
1843196
43b8753
9f30bbf
f84623d
6dd4ae7
0723401
7fd661c
30e7c37
faec65e
55a2b9a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
#!/usr/bin/env node | ||
const inquirer = require('inquirer'); | ||
const program = require('commander'); | ||
const childProcess = require('child_process'); | ||
const chalk = require('chalk'); | ||
const log = require('npmlog'); | ||
|
||
const { lstatSync, readdirSync } = require('fs'); | ||
const { join } = require('path'); | ||
|
||
const isTgz = source => lstatSync(source).isFile() && source.match(/.tgz$/); | ||
const getDirectories = source => readdirSync(source).map(name => join(source, name)).filter(isTgz); | ||
|
||
log.heading = 'storybook'; | ||
const prefix = 'bootstrap'; | ||
|
||
const spawn = command => | ||
childProcess.spawnSync(`${command}`, { | ||
shell: true, | ||
stdio: 'inherit', | ||
}); | ||
|
||
const main = program | ||
.version('3.0.0') | ||
.option('--all', `Bootstrap everything ${chalk.gray('(all)')}`); | ||
|
||
const createTask = ({ defaultValue, option, name, check = () => true, command, pre = [] }) => ({ | ||
value: false, | ||
defaultValue: defaultValue || false, | ||
option: option || undefined, | ||
name: name || 'unnamed task', | ||
check: check || (() => true), | ||
command: () => { | ||
// run all pre tasks | ||
// eslint-disable-next-line no-use-before-define | ||
pre.map(key => tasks[key]).forEach(task => { | ||
if (!task.check()) { | ||
task.command(); | ||
} | ||
}); | ||
|
||
log.info(prefix, name); | ||
command(); | ||
}, | ||
}); | ||
|
||
const tasks = { | ||
reset: createTask({ | ||
name: `Clean and re-install root dependencies ${chalk.red('(reset)')}`, | ||
defaultValue: false, | ||
option: '--reset', | ||
command: () => { | ||
log.info(prefix, 'git clean'); | ||
spawn('git clean -fdx'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you think about just running There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It should be completely destructive to anything not managed by git. Anything added not known by or ignored by git should be removed. The desired end-result is as if you just cloned the repo. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In fact, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Hypnosphi Can you give me a list / regexp that you IDE adds that should NOT be cleaned away? |
||
log.info(prefix, 'yarn install'); | ||
spawn('yarn install --no-lockfile'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why no lockfile? i think yarn's lockfiles work pretty well cc @Hypnosphi There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We're currently ignoring them, so not generating them in the first place is better. Let's discuss enabling yarn lockfiles outside this PR? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's do it: #1703 |
||
}, | ||
}), | ||
core: createTask({ | ||
name: `Core & Examples ${chalk.gray('(core)')}`, | ||
defaultValue: true, | ||
option: '--core', | ||
command: () => { | ||
spawn('yarn bootstrap:core'); | ||
}, | ||
}), | ||
docs: createTask({ | ||
name: `Documentation ${chalk.gray('(docs)')}`, | ||
defaultValue: false, | ||
option: '--docs', | ||
command: () => { | ||
spawn('yarn bootstrap:docs'); | ||
}, | ||
}), | ||
packs: createTask({ | ||
name: `Build tarballs of packages ${chalk.gray('(build-packs)')}`, | ||
defaultValue: false, | ||
option: '--packs', | ||
command: () => { | ||
spawn('yarn build-packs'); | ||
}, | ||
check: () => getDirectories(join(__dirname, '..', 'packs')).length > 0, | ||
}), | ||
'react-native-vanilla': createTask({ | ||
name: `React-Native example ${chalk.gray('(react-native-vanilla)')}`, | ||
defaultValue: false, | ||
option: '--reactnative', | ||
pre: ['packs'], | ||
command: () => { | ||
spawn('yarn bootstrap:react-native-vanilla'); | ||
}, | ||
}), | ||
'crna-kitchen-sink': createTask({ | ||
name: `React-Native-App example ${chalk.gray('(crna-kitchen-sink)')}`, | ||
defaultValue: false, | ||
option: '--reactnativeapp', | ||
pre: ['packs'], | ||
command: () => { | ||
spawn('yarn bootstrap:crna-kitchen-sink'); | ||
}, | ||
}), | ||
}; | ||
|
||
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; | ||
}); | ||
|
||
let selection; | ||
if (!Object.keys(tasks).map(key => tasks[key].value).filter(Boolean).length) { | ||
selection = inquirer | ||
.prompt([ | ||
{ | ||
type: 'checkbox', | ||
message: 'Select which packages to bootstrap', | ||
name: 'todo', | ||
choices: Object.keys(tasks).map(key => ({ | ||
name: tasks[key].name, | ||
checked: tasks[key].defaultValue, | ||
})), | ||
}, | ||
]) | ||
.then(answers => | ||
answers.todo.map(name => tasks[Object.keys(tasks).find(i => tasks[i].name === name)]) | ||
); | ||
} 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.forEach(key => { | ||
key.command(); | ||
}); | ||
process.stdout.write('\x07'); | ||
try { | ||
spawn('say "Bootstrapping sequence complete"'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. AWESOME 💯 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lol, I'm actually concerned this will be annoying to linux and windows users, will have to ask @usulpro maybe? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. won't it just fail silently on those platforms? |
||
} catch (e) { | ||
// discard error | ||
} | ||
} | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had trouble with lint-staged trying to git add multiple things in parallel, which fails because git's lockfile would exist.
I disabled concurrency for this reason. Depending on the amount of files in your stage, this will make the process a second or 2 slower, but git add is reliable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ndelangen seems like this is a separate PR?