From b9776ea4736b797cee09bc7ab3b6b6ec71c72e5f Mon Sep 17 00:00:00 2001 From: Brian Frichette Date: Sat, 15 Jul 2017 17:01:41 -0700 Subject: [PATCH] build(platform): Improve consistency (yarn), and async (#84) - Add CircleCI override to use latest yarn for deterministic builds - Refactor some overly obtuse functions - Use async throughout - Add commitizen-friendly badge --- README.md | 3 +- build/tasks.ts | 72 +++++++++++++++++++++--------------------- build/util.ts | 85 +++++++++++++++++++++++++------------------------- circle.yml | 15 +++++++-- 4 files changed, 94 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index ba3429b05b..88fb71c5e9 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,8 @@ Reactive libraries for Angular ## Support -[![Join the chat at https://gitter.im/ngrx/store](https://badges.gitter.im/ngrx/store.svg)](https://gitter.im/ngrx/store?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Join the chat at https://gitter.im/ngrx/store](https://badges.gitter.im/ngrx/store.svg)](https://gitter.im/ngrx/store?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/) + ## Packages diff --git a/build/tasks.ts b/build/tasks.ts index 98050171ce..870906e685 100644 --- a/build/tasks.ts +++ b/build/tasks.ts @@ -5,10 +5,8 @@ import * as util from './util'; * Cleans the top level dist folder. All npm-ready packages are created * in the dist folder. */ -export async function removeDistFolder(config: Config) { - const args = ['./dist']; - - return await util.exec('rimraf', args); +export function removeDistFolder(config: Config) { + return util.exec('rimraf', ['./dist']); } /** @@ -22,8 +20,8 @@ export async function compilePackagesWithNgc(config: Config) { const testPkgs = util.getTestingPackages(config); await _compilePackagesWithNgc(storePkg); - await mapPackages(restPkgs, _compilePackagesWithNgc); - await mapPackages(testPkgs, _compilePackagesWithNgc); + await mapAsync(restPkgs, _compilePackagesWithNgc); + await mapAsync(testPkgs, _compilePackagesWithNgc); } async function _compilePackagesWithNgc(pkg: string) { @@ -32,8 +30,10 @@ async function _compilePackagesWithNgc(pkg: string) { const entryTypeDefinition = `export * from './${pkg}/index';`; const entryMetadata = `{"__symbolic":"module","version":3,"metadata":{},"exports":[{"from":"./${pkg}/index"}]}`; - util.writeFile(`./dist/packages/${pkg}.d.ts`, entryTypeDefinition); - util.writeFile(`./dist/packages/${pkg}.metadata.json`, entryMetadata); + await Promise.all([ + util.writeFile(`./dist/packages/${pkg}.d.ts`, entryTypeDefinition), + util.writeFile(`./dist/packages/${pkg}.metadata.json`, entryMetadata), + ]); } /** @@ -43,7 +43,7 @@ async function _compilePackagesWithNgc(pkg: string) { export async function bundleFesms(config: Config) { const pkgs = util.getAllPackages(config); - await mapPackages(pkgs, async pkg => { + await mapAsync(pkgs, async pkg => { const topLevelName = util.getTopLevelName(pkg); await util.exec('rollup', [ @@ -64,14 +64,13 @@ export async function downLevelFesmsToES5(config: Config) { const packages = util.getAllPackages(config); const tscArgs = ['--target es5', '--module es2015', '--noLib', '--sourceMap']; - await mapPackages(packages, async pkg => { + await mapAsync(packages, async pkg => { const topLevelName = util.getTopLevelName(pkg); const file = `./dist/${topLevelName}/${config.scope}/${pkg}.js`; const target = `./dist/${topLevelName}/${config.scope}/${pkg}.es5.ts`; - util.copy(file, target); - + await util.copy(file, target); await util.ignoreErrors(util.exec('tsc', [target, ...tscArgs])); await util.mapSources(target.replace('.ts', '.js')); await util.remove(target); @@ -84,7 +83,7 @@ export async function downLevelFesmsToES5(config: Config) { * Re-runs Rollup on the downleveled ES5 to produce a UMD bundle */ export async function createUmdBundles(config: Config) { - await mapPackages(util.getAllPackages(config), async pkg => { + await mapAsync(util.getAllPackages(config), async pkg => { const topLevelName = util.getTopLevelName(pkg); const destinationName = util.getDestinationName(pkg); @@ -106,9 +105,7 @@ export async function cleanTypeScriptFiles(config: Config) { const dtsFilesFlob = './dist/packages/**/*.d.ts'; const filesToRemove = await util.getListOfFiles(tsFilesGlob, dtsFilesFlob); - for (let file of filesToRemove) { - util.remove(file); - } + await mapAsync(filesToRemove, util.remove); } /** @@ -116,16 +113,17 @@ export async function cleanTypeScriptFiles(config: Config) { * of the package. */ export async function renamePackageEntryFiles(config: Config) { - await mapPackages(util.getAllPackages(config), async pkg => { + await mapAsync(util.getAllPackages(config), async pkg => { const bottomLevelName = util.getBottomLevelName(pkg); const files = await util.getListOfFiles(`./dist/packages/${pkg}/index.**`); - for (let file of files) { + await mapAsync(files, async file => { const target = file.replace('index', bottomLevelName); - util.copy(file, target); - util.remove(file); - } + + await util.copy(file, target); + await util.remove(file); + }); }); } @@ -150,10 +148,10 @@ export async function copyTypeDefinitionFiles(config: Config) { `./dist/packages/?(${packages.join('|')})/**/*` ); - for (let file of files) { + await mapAsync(files, async file => { const target = file.replace('packages/', ''); - util.copy(file, target); - } + await util.copy(file, target); + }); await util.removeRecursively(`./dist/packages/?(${packages.join('|')})`); } @@ -164,7 +162,7 @@ export async function copyTypeDefinitionFiles(config: Config) { export async function minifyUmdBundles(config: Config) { const uglifyArgs = ['-c', '-m', '--screw-ie8', '--comments']; - await mapPackages(util.getAllPackages(config), async pkg => { + await mapAsync(util.getAllPackages(config), async pkg => { const topLevelName = util.getTopLevelName(pkg); const destinationName = util.getDestinationName(pkg); const file = `./dist/${topLevelName}/bundles/${destinationName}.umd.js`; @@ -187,24 +185,26 @@ export async function minifyUmdBundles(config: Config) { export async function copyDocs(config: Config) { const packages = util.getTopLevelPackages(config); - for (let pkg of packages) { + await mapAsync(packages, async pkg => { const source = `./modules/${pkg}`; const target = `./dist/${pkg}`; - util.copy(`${source}/README.md`, `${target}/README.md`); - util.copy('./LICENSE', `${target}/LICENSE`); - } + await Promise.all([ + util.copy(`${source}/README.md`, `${target}/README.md`), + util.copy('./LICENSE', `${target}/LICENSE`), + ]); + }); } export async function copyPackageJsonFiles(config: Config) { const packages = util.getAllPackages(config); - for (let pkg of packages) { + await mapAsync(packages, async pkg => { const source = `./modules/${pkg}`; const target = `./dist/${pkg}`; - util.copy(`${source}/package.json`, `${target}/package.json`); - } + await util.copy(`${source}/package.json`, `${target}/package.json`); + }); } /** @@ -254,9 +254,9 @@ export async function publishToRepo(config: Config) { } } -export function mapPackages( - packages: string[], - mapFn: (pkg: string, i: number) => Promise +export function mapAsync( + list: T[], + mapFn: (v: T, i: number) => Promise ) { - return Promise.all(packages.map(mapFn)); + return Promise.all(list.map(mapFn)); } diff --git a/build/util.ts b/build/util.ts index 8efed0f41d..b26526c4ef 100644 --- a/build/util.ts +++ b/build/util.ts @@ -6,24 +6,35 @@ import * as path from 'path'; import * as rimraf from 'rimraf'; import { Config } from './config'; -export function copy(target: string, destination: string) { - fsExtra.copySync(target, destination); -} - -export function remove(target: string) { - fsExtra.removeSync(target); -} +export type RunnerFn = (config: Config) => Promise; +export type TaskDef = [string, RunnerFn]; +export type BaseFn = (command: string) => string; -export function writeFile(target: string, contents: string) { - fs.writeFileSync(target, contents); +export function copy(target: string, destination: string): Promise { + return new Promise((resolve, reject) => { + fsExtra.copy(target, destination, err => { + if (err) return reject(err); + resolve(); + }); + }); } -export function mkdir(target: string) { - fs.mkdirSync(target); +export function remove(target: string): Promise { + return new Promise((resolve, reject) => { + fsExtra.remove(target, err => { + if (err) return reject(err); + resolve(); + }); + }); } -export function rmdir(target: string) { - fs.rmdirSync(target); +export function writeFile(target: string, contents: string) { + return new Promise((resolve, reject) => { + fs.writeFile(target, contents, err => { + if (err) return reject(err); + resolve(); + }); + }); } export function getListOfFiles( @@ -58,10 +69,10 @@ export function removeRecursively(glob: string) { export function exec( command: string, args: string[], - base: (command: string) => string = fromNpm + base: BaseFn = fromNpm ): Promise { return new Promise((resolve, reject) => { - cp.exec(base(command) + ' ' + args.join(' '), (err, stdout, stderr) => { + cp.exec(base(command) + ' ' + args.join(' '), (err, stdout) => { if (err) { return reject(err); } @@ -76,37 +87,25 @@ export function cmd(command: string, args: string[]): Promise { } export function git(args: string[]): Promise { - return exec('git', args, (command: string) => command); + return cmd('git', args); } -export async function ignoreErrors(promise: Promise): Promise { - try { - const result = await promise; - return result; - } catch (err) { - return null; - } +export function ignoreErrors(promise: Promise): Promise { + return promise.catch(() => null); } export function fromNpm(command: string) { - return path.normalize(`./node_modules/.bin/${command}`); + return baseDir(`./node_modules/.bin/${command}`); } export function getPackageFilePath(pkg: string, filename: string) { - return path.resolve(process.cwd(), `./modules/${pkg}/${filename}`); + return baseDir(`./modules/${pkg}/${filename}`); } const sorcery = require('sorcery'); -export function mapSources(file: string) { - return new Promise((resolve, reject) => { - sorcery - .load(file) - .then((chain: any) => { - chain.write(); - resolve(); - }) - .catch(reject); - }); +export async function mapSources(file: string) { + const chain = await sorcery.load(file); + chain.write(); } const ora = require('ora'); @@ -126,9 +125,7 @@ async function runTask(name: string, taskFn: () => Promise) { } } -export function createBuilder( - tasks: [string, (config: Config) => Promise][] -) { +export function createBuilder(tasks: TaskDef[]) { return async function(config: Config) { for (let [name, runner] of tasks) { await runTask(name, () => runner(config)); @@ -157,12 +154,12 @@ export function getTestingPackages(config: Config) { } export function getAllPackages(config: Config) { - return flatMap(config.packages, packageDescription => { - if (packageDescription.hasTestingModule) { - return [packageDescription.name, `${packageDescription.name}/testing`]; + return flatMap(config.packages, ({ name, hasTestingModule }) => { + if (hasTestingModule) { + return [name, `${name}/testing`]; } - return [packageDescription.name]; + return [name]; }); } @@ -177,3 +174,7 @@ export function getTopLevelName(packageName: string) { export function getBottomLevelName(packageName: string) { return packageName.includes('/testing') ? 'testing' : packageName; } + +export function baseDir(...dirs: string[]): string { + return path.resolve(__dirname, '../', ...dirs); +} diff --git a/circle.yml b/circle.yml index 04e46274fe..f6cf91ac6d 100644 --- a/circle.yml +++ b/circle.yml @@ -1,11 +1,22 @@ machine: + environment: + PATH: "${PATH}:${HOME}/${CIRCLE_PROJECT_REPONAME}/node_modules/.bin" node: version: 6.9.5 -test: + +dependencies: + pre: + - curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 0.28.1 + cache_directories: + - ~/.cache/yarn override: - - npm install -g yarn + - yarn - yarn run bootstrap -- --concurrency=1 + +test: + override: - yarn run ci + deployment: builds: owner: ngrx