-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(roc-plugin-repo): Made it possible to define custom scripts
This can be done using npm scripts in the package.json for a project. Additionally it's possible to add actions that interact with how projects are built.
- Loading branch information
Showing
16 changed files
with
486 additions
and
233 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import babel from '../commands/utils/babel'; | ||
import { invokeHook } from '../util'; | ||
|
||
function buildWithBabel(config, watch, createLogger) { | ||
const settings = config.settings.repo; | ||
|
||
return (projects, mode, multipleTargets) => | ||
Promise.all( | ||
projects.map(project => { | ||
const logger = createLogger(project.name).logger; | ||
const babelConfig = invokeHook('babel-config', mode, project); | ||
try { | ||
logger(`Building for ${mode} with Babel`); | ||
return babel( | ||
{ | ||
mode, | ||
path: project.path, | ||
src: `${project.path}/${settings.input}`, | ||
out: multipleTargets | ||
? `${project.path}/${settings.output}/${mode}` | ||
: `${project.path}/${settings.output}`, | ||
// We want to ignore potential __snapshots__ and __mocks__ directories | ||
ignore: settings.test.concat([ | ||
'**/__snapshots__/**', | ||
'**/__mocks__/**', | ||
]), | ||
copyFiles: true, | ||
sourceMaps: true, | ||
babelrc: false, | ||
watch, | ||
log: logger, | ||
}, | ||
babelConfig, | ||
); | ||
} catch (err) { | ||
err.projectName = project.name; | ||
if (err._babel && err instanceof SyntaxError) { | ||
// Display codeFrame if it is an Babel Error | ||
err.message = `${err.message}\n${err.codeFrame}`; | ||
} | ||
throw err; | ||
} | ||
}), | ||
); | ||
} | ||
|
||
export default (context, projects, { options: { watch }, createLogger }) => { | ||
const esmJavaScriptBuild = projects.filter( | ||
({ packageJSON }) => | ||
packageJSON.module && packageJSON.module.endsWith('.js'), | ||
); | ||
const cjsJavaScriptBuild = projects.filter( | ||
({ packageJSON }) => packageJSON.main && packageJSON.main.endsWith('.js'), | ||
); | ||
|
||
return async () => { | ||
if (cjsJavaScriptBuild.length > 0) { | ||
await buildWithBabel(context.config, watch, createLogger)( | ||
cjsJavaScriptBuild, | ||
'cjs', | ||
esmJavaScriptBuild.length > 0, | ||
); | ||
} | ||
|
||
if (esmJavaScriptBuild.length > 0) { | ||
await buildWithBabel(context.config, watch, createLogger)( | ||
esmJavaScriptBuild, | ||
'esm', | ||
cjsJavaScriptBuild.length > 0, | ||
); | ||
} | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import execa from 'execa'; | ||
import Listr from 'listr'; | ||
import isCI from 'is-ci'; | ||
|
||
const rimraf = require.resolve('rimraf/bin'); | ||
|
||
const clean = (project, output) => `${rimraf} ${project.path}/${output}`; | ||
|
||
export default (context, projects) => () => | ||
new Listr( | ||
projects.map(project => ({ | ||
title: `Cleaning ${project.name}`, | ||
task: () => | ||
execa.shell(clean(project, context.config.settings.repo.output)), | ||
})), | ||
{ concurrent: true, renderer: isCI ? 'verbose' : 'default' }, | ||
).run(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import path from 'path'; | ||
|
||
import execa from 'execa'; | ||
import { fileExists } from 'roc'; | ||
import log from 'roc/log/default/small'; | ||
|
||
const eslint = require.resolve('eslint/bin/eslint'); | ||
|
||
const eslintCommand = (project, fix, config, ignorePattern, ignoreFile) => | ||
`${eslint} ${config}${project.path} --ignore-path '${ignoreFile}' --ignore-pattern '${ignorePattern}' ${fix | ||
? '--fix' | ||
: ''}`; | ||
|
||
export default (context, projects, { options: { fix, forceDefault } }) => { | ||
let config; | ||
if (fileExists('.eslintrc', context.directory) && !forceDefault) { | ||
log.info( | ||
'A local ESLint configuration was detected and will be used over the default.\n', | ||
); | ||
config = ''; | ||
} else { | ||
config = `--config ${require.resolve('../configuration/eslintrc.js')} `; | ||
} | ||
|
||
let ignoreFile; | ||
if (fileExists('.eslintignore', context.directory) && !forceDefault) { | ||
log.info( | ||
'A local ESLint ignore file was detected and will be used over the default.\n', | ||
); | ||
ignoreFile = path.join(context.directory, '.eslintignore'); | ||
} else { | ||
ignoreFile = require.resolve('../configuration/eslintignore'); | ||
} | ||
|
||
return () => | ||
Promise.all( | ||
projects | ||
.map(project => { | ||
const ignorePattern = path.join( | ||
path.relative( | ||
context.directory, | ||
path.resolve(project.path, context.config.settings.repo.output), | ||
), | ||
'*', | ||
); | ||
|
||
return execa.shell( | ||
eslintCommand(project, fix, config, ignorePattern, ignoreFile), | ||
{ stdio: 'inherit' }, | ||
); | ||
}) | ||
.map(promise => promise.then(() => 0, () => 1)), | ||
).then(results => { | ||
const status = results.reduce((previous, current) => | ||
Math.max(previous, current), | ||
); | ||
if (status === 1) { | ||
process.exitCode = 1; | ||
} | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import execa from 'execa'; | ||
|
||
/** | ||
* By default all projects will be published using npm something that we might want to go away from. | ||
* The question is if there is anything that can be used to detect if a project should be published | ||
* using npm. | ||
* | ||
* One alternative would have been to use "private: true" but that is already used for other | ||
* purposes, mainly making sure we don't do anything in terms of releasing for them. | ||
*/ | ||
export default (context, projects, { options: { distTag } }) => () => | ||
Promise.all( | ||
projects.map(project => { | ||
let registry = ''; | ||
const publishConfig = project.packageJSON.publishConfig; | ||
if (publishConfig && publishConfig.registry) { | ||
registry = `--registry='${publishConfig.registry}'`; | ||
} | ||
|
||
return execa.shell(`npm publish ${registry} --tag ${distTag}`, { | ||
cwd: project.path, | ||
}); | ||
}), | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { lazyFunctionRequire } from 'roc'; | ||
|
||
const lazyRequire = lazyFunctionRequire(require); | ||
|
||
export default ({ context }) => (script, projects, extra) => () => { | ||
if (script === 'build') { | ||
return lazyRequire('./build')(context, projects, extra); | ||
} else if (script === 'clean') { | ||
return lazyRequire('./clean')(context, projects, extra); | ||
} else if (script === 'lint') { | ||
return lazyRequire('./lint')(context, projects, extra); | ||
} else if (script === 'publish') { | ||
return lazyRequire('./publish')(context, projects, extra); | ||
} else if (script === 'test') { | ||
return lazyRequire('./test')(context, projects, extra); | ||
} | ||
|
||
return []; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import jest from 'jest'; // eslint-disable-line import/no-extraneous-dependencies | ||
|
||
export default (context, projects, { options, extraArguments }) => { | ||
// Enforce test | ||
process.env.NODE_ENV = 'test'; | ||
|
||
process.env.ROC_INITAL_ARGV = JSON.stringify(process.argv); | ||
|
||
let argv = [...extraArguments]; | ||
|
||
const jestConfig = { | ||
resolver: require.resolve('../commands/utils/jest/roc-resolver.js'), | ||
testPathIgnorePatterns: projects.map( | ||
({ path }) => | ||
`${path}/(${context.config.settings.repo.output}|node_modules)/`, | ||
), | ||
transform: { | ||
'^.+\\.js$': require.resolve( | ||
'../commands/utils/jest/babel-jest-transformer.js', | ||
), | ||
}, | ||
testMatch: [].concat( | ||
...projects.map(({ path }) => | ||
context.config.settings.repo.test.map(pattern => `${path}/${pattern}`), | ||
), | ||
), | ||
}; | ||
|
||
argv.push('--config', JSON.stringify(jestConfig)); | ||
argv = argv | ||
.concat( | ||
Object.keys(options).map( | ||
key => options[key] !== undefined && `--${key}=${options[key]}`, | ||
), | ||
) | ||
.filter(Boolean); | ||
|
||
return () => jest.run(argv); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,80 +1,14 @@ | ||
import log from 'roc/log/default'; | ||
|
||
import { invokeHook } from '../util'; | ||
import babel from './utils/babel'; | ||
import scriptRunner from './utils/scriptRunner'; | ||
|
||
export default projects => ({ | ||
arguments: { managed: { projects: selectedProjects } }, | ||
options: { managed: { watch } }, | ||
options: { managed: { watch, concurrent } }, | ||
context, | ||
}) => { | ||
const settings = context.config.settings.repo; | ||
const selected = projects.filter( | ||
({ name }) => !selectedProjects || selectedProjects.includes(name), | ||
); | ||
|
||
if (selected.length === 0) { | ||
return log.small.warn('No projects were found'); | ||
} | ||
|
||
return Promise.all( | ||
settings.targets.map(mode => | ||
Promise.all( | ||
selected | ||
.map( | ||
project => | ||
new Promise((resolve, reject) => { | ||
const config = invokeHook('babel-config', mode, project); | ||
try { | ||
babel( | ||
{ | ||
identifier: project.name, | ||
mode, | ||
path: project.path, | ||
src: `${project.path}/${settings.input}`, | ||
out: | ||
settings.targets.length === 1 | ||
? `${project.path}/${settings.output}` | ||
: `${project.path}/${settings.output}/${mode}`, | ||
// We want to ignore potential __snapshots__ and __mocks__ directories | ||
ignore: settings.test.concat([ | ||
'**/__snapshots__/**', | ||
'**/__mocks__/**', | ||
]), | ||
copyFiles: true, | ||
sourceMaps: true, | ||
babelrc: false, | ||
watch, | ||
}, | ||
config, | ||
); | ||
} catch (err) { | ||
if (err._babel && err instanceof SyntaxError) { | ||
// Display codeFrame if it is an Babel Error | ||
err.message = `${err.message}\n${err.codeFrame}`; | ||
log.large.warn(project.name, 'Build Error', err); | ||
} | ||
reject(err); | ||
} | ||
resolve(); | ||
}), | ||
) | ||
.map(promise => promise.then(() => 0, () => 1)), | ||
).then(results => | ||
results.reduce((previous, current) => Math.max(previous, current)), | ||
), | ||
), | ||
).then(results => { | ||
const status = results.reduce((previous, current) => | ||
Math.max(previous, current), | ||
); | ||
if (status === 1) { | ||
process.exitCode = 1; | ||
log.small.log(); // Create a new line for padding purposes | ||
log.small.error('Build failed.'); | ||
} else if (!watch) { | ||
log.small.log(); // Create a new line for padding purposes | ||
log.small.success('Build succeeded.'); | ||
} | ||
}); | ||
return scriptRunner('build')(selected, settings, concurrent, { watch }); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,14 @@ | ||
import { execute } from 'roc'; | ||
import log from 'roc/log/default/small'; | ||
import Listr from 'listr'; | ||
import isCI from 'is-ci'; | ||
|
||
const rimraf = require.resolve('rimraf/bin'); | ||
|
||
const clean = (project, output) => `${rimraf} ${project.path}/${output}`; | ||
import scriptRunner from './utils/scriptRunner'; | ||
|
||
export default projects => ({ | ||
arguments: { managed: { projects: selectedProjects } }, | ||
options: { managed: { concurrent } }, | ||
context, | ||
}) => { | ||
const settings = context.config.settings.repo; | ||
const selected = projects.filter( | ||
({ name }) => !selectedProjects || selectedProjects.includes(name), | ||
); | ||
|
||
if (selected.length === 0) { | ||
return log.warn('No projects were found'); | ||
} | ||
|
||
return new Listr( | ||
selected.map(project => ({ | ||
title: `Cleaning ${project.name}`, | ||
task: () => execute(clean(project, context.config.settings.repo.output)), | ||
})), | ||
{ concurrent: true, renderer: isCI ? 'verbose' : 'default' }, | ||
).run(); | ||
return scriptRunner('clean')(selected, settings, concurrent); | ||
}; |
Oops, something went wrong.