Created
August 10, 2017 18:41
-
-
Save scottcorgan/028e113f008f1d669d927e67fa9fa6b7 to your computer and use it in GitHub Desktop.
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
#!/usr/bin/env node | |
/* eslint-disable import/no-dynamic-require,global-require,no-return-assign */ | |
const { resolve, join } = require('path'); | |
const parseOpts = require('minimist'); | |
const md5File = require('md5-file'); | |
const fs = require('fs-extra'); | |
const dependencyTree = require('dependency-tree'); | |
const _ = require('lodash'); | |
const tape = require('tape'); | |
const cwd = process.cwd(); | |
const cachePath = filename => resolve(cwd, 'tmp', 'client-tests', filename); | |
const opts = parseOpts(process.argv.slice(2), { | |
alias: { r: 'require' }, | |
string: 'require', | |
default: { r: [] }, | |
}); | |
const dependencyList = filename => | |
dependencyTree.toList({ filename, directory: cwd }); | |
const targetFiles = _(opts._) | |
.map(dependencyList) | |
.flatten() | |
.map(name => name.replace(join(cwd, '/'), '')) | |
.value(); | |
// Gets all helpful information for files | |
const fileStats = targetFiles.map((filename) => { | |
const newHash = md5File.sync(filename); | |
const filepath = cachePath(filename); | |
let oldHash = ''; | |
try { | |
oldHash = fs.readFileSync(filepath).toString(); | |
} catch (e) { | |
/* Cache file does not yet exist */ | |
} | |
return { | |
changed: newHash !== oldHash, | |
hash: newHash, | |
path: resolve(cwd, filename), | |
name: filename, | |
}; | |
}); | |
// Gets all changed files | |
const changedFiles = fileStats | |
.filter(({ changed }) => changed) | |
.map((file) => { | |
const depTree = dependencyTree.toList({ | |
filename: file.name, | |
directory: cwd, | |
}); | |
return Object.assign({}, file, { depTree }); | |
}); | |
// Gets all test files that have changed or have children that have changed | |
const testFileStats = changedFiles | |
.map((file) => { | |
if (file.name.endsWith('.test.es6')) { | |
return [file]; | |
} | |
const moreFiles = fileStats | |
.filter(({ name }) => name.endsWith('.test.es6')) | |
.filter((_file) => { | |
const depTree = dependencyTree.toList({ | |
filename: _file.name, | |
directory: cwd, | |
}); | |
return depTree.indexOf(file.path) > -1; | |
}); | |
return moreFiles; | |
}) | |
.filter(file => file.length !== 0); | |
// Gets the name of the file | |
const files = _.flatten(testFileStats).map(({ name }) => name); | |
if (files.length === 0) { | |
console.log('\n✅ No files have changed \n'); | |
process.exit(0); | |
} | |
// Test running set up. Putting these down here for performance reasons. | |
require('babel-register'); | |
require('./setup.js'); | |
// Set up output to stdout | |
const outputStream = tape.createStream(); | |
outputStream.pipe(process.stdout); | |
// Track failed tests and delete their cache | |
let outputString = ''; | |
outputStream.on('data', data => outputString += data.toString()); | |
outputStream.on('end', () => { | |
_(outputString) | |
.split('\n') | |
.filter(str => str.indexOf('.test.es6:') > -1) | |
.map(str => str.trim()) | |
.map((str) => { | |
const index = str.indexOf('app/client'); | |
return str.substr(index).split(':')[0]; | |
}) | |
.uniq() | |
// Invalidate failed files's cache | |
.forEach(filename => fs.removeSync(cachePath(filename))); | |
}); | |
files.forEach(file => require(resolve(cwd, file))); | |
// Write changed files's cache | |
changedFiles.forEach((stat) => { | |
fs.outputFileSync(resolve(cwd, 'tmp', 'client-tests', stat.name), stat.hash); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment