Skip to content

Instantly share code, notes, and snippets.

@scottcorgan
Created August 10, 2017 18:41
Show Gist options
  • Save scottcorgan/028e113f008f1d669d927e67fa9fa6b7 to your computer and use it in GitHub Desktop.
Save scottcorgan/028e113f008f1d669d927e67fa9fa6b7 to your computer and use it in GitHub Desktop.
#!/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