Skip to content

Instantly share code, notes, and snippets.

@jameswomack
Last active February 2, 2022 21:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jameswomack/52bb358664b0105d1248951e5d146343 to your computer and use it in GitHub Desktop.
Save jameswomack/52bb358664b0105d1248951e5d146343 to your computer and use it in GitHub Desktop.
Monorepo test iteration. Logging your `lerna run test` output & using that to only re-run packages that haven't passed yet

usage

start a new test session

lerna-test-resume --init

run your tests w/ tee

npm t | tee ".lerna-test-resume/lerna-run-test-`date +%s`.log"

come across a failure, then have lerna-test-resume parse the log output(s)

lerna-test-resume

lerna-test-resume will output your new test command. run that. e.g.

lerna run test --concurrency=1 --stream --ignore @tectonic/babel-plugin-dedeepify-imports --ignore @tectonic/babel-plugin-extract-translations-properties --ignore @tectonic/babel-plugin-extract-user-preferences --ignore @tectonic/babel-plugin-jsx --ignore @tectonic/babel-utils --ignore @tectonic/build-support-mega-bundle-middleware --ignore @tectonic/config-core --ignore @tectonic/eslint-plugin-dependencies --ignore @tectonic/eslint-plugin-drivers --ignore @tectonic/eslint-plugin-only-warn --ignore @tectonic/pom --ignore @tectonic/test-fixtures-quebec-simple-snabbdom --ignore @tectonic/test-fixtures-quebec-sinon --ignore @tectonic/test-fixtures-san-diego-simple-snabbdom --ignore @tectonic/webpack-config-shared-component-loader --ignore @tectonic/webpack-plugin-emit-translations --ignore @tectonic/webpack-plugin-extract-call-expressions --ignore @tectonic/webpack-plugin-extract-user-preferences --ignore @tectonic/webpack-plugin-moment-locales --ignore @tectonic/webpack-plugin-simple-file-copy --ignore @tectonic/babel-plugin-invalid-imports --ignore @tectonic/metadata-transform-core --ignore @tectonic/logger --ignore @tectonic/eslint-plugin-tectonic --ignore @tectonic/babel-plugin-rename-deprecated-seismic --ignore @tectonic/build-plugin-bundle-analyzer --ignore @tectonic/build-plugins-common --ignore @tectonic/build-plugin-null-resolver --ignore @tectonic/build-plugin-reset-dist-directory --ignore @tectonic/esbuild-plugin-scss-compiler --ignore @tectonic/build-plugin-simple-copy --ignore @tectonic/build-plugin-write-disk-based-assets --ignore @tectonic/build-support-dependency-manifest-generator --ignore @tectonic/component-archetype -- --coverage=true && combine-coverage | tee ".lerna-test-resume/lerna-run-test-`date +%s`.log"

iterate until all of your tests pass

#!/usr/bin/env node
/* eslint-disable prefer-template */
module.exports = async function getPassedPackageNames () {
const {ensureDir, readdir, readFile, rmdir} = require('fs-extra');
const Path = require('path');
const logger = require('@my-scope/logger');
const argv = require('yargs-parser')(process.argv.slice(2));
const {init} = argv;
const rootDir = Path.join(process.cwd(), '.lerna-test-resume');
if (init) {
await rmdir(rootDir, {recursive: true});
await ensureDir(rootDir);
return;
}
const rootDirContents = await readdir(rootDir);
const logPaths = rootDirContents.filter(p => p.match(/\.log$/));
if (!logPaths || !logPaths.length)
return logger.attention('no lerna logs found. please run your tests like npm t | tee ".lerna-test-resume/lerna-run-test-`date +%s`.log"');
let logs = '';
for (const logPath of logPaths) {
const log = await readFile(Path.join(rootDir, logPath), {encoding:'utf-8'});
logs = `${logs}\n${log}`;
}
const allPackages = logs.match(/^@my-scope\/[a-zA-z-]+: /mg);
const failedPackages = logs.match(/^@my-scope\/[a-zA-z-]+: npm ERR!/mg);
function getUnique (packages) {
const o = {};
const a = [];
for (let i = 0; i < packages.length; i++)
o[packages[i]] = 1;
for (var e in o)
a.push(e);
return a;
}
function getOnlyPackageNames (packages) {
return packages.map(p => p.split(': ')[0]);
}
const allPackageNames = getOnlyPackageNames(getUnique(allPackages.slice(2)));
const failedPackageNames = getOnlyPackageNames(getUnique(failedPackages.slice(2)));
const passedPackageNames = allPackageNames.filter(p => !failedPackageNames.includes(p));
const passedPackagesNamesWithIgnore = passedPackageNames.map(p => `--ignore ${p}`);
const joinedPassedPackages = passedPackagesNamesWithIgnore.join(' ');
logger.info('lerna run test --concurrency=1 --stream ' + joinedPassedPackages + ' | tee ".lerna-test-resume/lerna-run-test-`date +%s`.log"');
return passedPackageNames;
};
if (require.main === module) {
(async function () {
await module.exports();
})();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment