joyent-portal/scripts/run-staged-pkg

152 lines
3.7 KiB
JavaScript
Executable File

#!/usr/bin/env node
const { readFile, exists } = require('mz/fs');
const sgf = require('staged-git-files');
const execa = require('execa');
const awaitify = require('apr-awaitify');
const asyncFilter = require('apr-filter');
const main = require('apr-main');
const map = require('apr-map');
const reduce = require('apr-reduce');
const globby = require('globby');
const path = require('path');
const uniq = require('lodash.uniq');
const argv = require('yargs').argv;
const checksum = require('checksum');
const { lstatSync, readdirSync } = require('fs');
const { join } = require('path');
const ROOT = path.join(__dirname, '..');
const getStaged = awaitify(sgf);
const statuses = [
'Added',
'Copied',
'Deleted',
'Modified',
'Renamed',
'Unmerged'
];
const exec = (args = []) =>
execa('lerna', args, {
stdio: 'inherit'
});
const lint = scope => exec(['run', 'lint', '--scope', scope]);
const test = scope => exec(['run', 'test', '--scope', scope]);
const run = async scope => {
if (argv.lint) {
await lint(scope);
}
if (argv.test) {
await test(scope);
}
};
const runLint = async scope => {
await lint(scope);
};
const runTest = async scope => {
await test(scope);
};
const getUnstaged = async () => {
const unstaged = await execa('git', ['ls-files', '-m']);
return unstaged.stdout.split('\n');
};
const asyncChecksum = awaitify(checksum.file);
const add = async filename => execa('git', ['add', filename]);
const runLintAndGitAdd = async (staged, pkgs) => {
const unstaged = (await getUnstaged()).map(file => path.resolve(ROOT, file));
const existing = await asyncFilter(staged, ({ filename }) =>
exists(filename)
);
const checksums = await map(existing, async file => {
const checksum = await asyncChecksum(file.filename);
return Object.assign({}, file, { checksum });
});
await map(pkgs.map(({ name }) => name), runLint);
const changed = await asyncFilter(
checksums,
async ({ filename, checksum }) => {
const newChecksum = await asyncChecksum(filename);
return checksum != newChecksum;
}
);
const modifieds = await reduce(
changed,
async (modifieds, file) => {
const isUnstaged = unstaged.filter(f => f === file.filename).length;
if (
(file.status === 'Modified' || file.status === 'Added') &&
isUnstaged
) {
modifieds.push(file);
} else {
await add(file.filename);
}
return modifieds;
},
[]
);
if (modifieds.length) {
modifieds.forEach(modified =>
console.log('PARTIALLY STAGED FILE ', modified.filename)
);
process.exit(0);
}
};
const gather = async () => {
const isDirectory = source => lstatSync(source).isDirectory();
const getDirectories = source =>
readdirSync(source)
.map(name => join(source, name))
.filter(isDirectory);
const locations = await globby(
getDirectories('./packages').concat(getDirectories('./prototypes')),
{ cwd: ROOT }
);
const staged = (await getStaged())
.filter(({ status }) => statuses.indexOf(status) >= 0)
// .map(({ filename }) => path.resolve(ROOT, filename));
.map(file =>
Object.assign({}, file, { filename: path.resolve(ROOT, file.filename) })
);
const folders = uniq(
locations
.map(folder => path.resolve(ROOT, folder))
.filter(folder => staged.some(i => i.filename.indexOf(folder) >= 0))
);
const pkgs = await map(folders, async folder =>
JSON.parse(await readFile(path.join(folder, 'package.json'), 'utf-8'))
);
if (argv.lint) {
await runLintAndGitAdd(staged, pkgs);
}
if (argv.test) {
await await map(pkgs.map(({ name }) => name), runTest);
}
};
main(gather());