Compare commits

..

10 Commits

Author SHA1 Message Date
f8d78d05fc fix: handle alternate workspaces config 2019-04-08 11:10:13 -07:00
6e2288f157 docs: update readme 2019-04-05 15:55:41 -07:00
9aebeb31a6 feat: support workspaces 2019-04-05 15:49:59 -07:00
b93defbf4d fix: compare stringified objects
fixes issue with packages that have no dependencies or devDependencies
2019-04-05 15:49:16 -07:00
4cd6e2922c feat: provide package info instead of just ident
useful for reading other properties out of the package.json file
2019-04-05 15:46:10 -07:00
9fb86bf32e fix: fail on ident read
remove getRootFileContents util, easily replaced in the one place it's used
2019-04-05 15:00:34 -07:00
71f8bb7729 feat: show skip output in verbose mode 2019-04-04 17:33:53 -07:00
4fec26c796 chore: add test script 2019-04-04 17:13:25 -07:00
bce054516b chore: update repository url 2019-04-04 17:11:55 -07:00
3f29429d1a docs: add usage info to readme 2019-04-04 17:10:24 -07:00
7 changed files with 78 additions and 18 deletions

View File

@@ -6,6 +6,17 @@ Node package compare and change runner.
[![npm](https://img.shields.io/npm/v/pkgcomp.svg)](https://www.npmjs.com/package/pkgcomp) [![npm](https://img.shields.io/npm/v/pkgcomp.svg)](https://www.npmjs.com/package/pkgcomp)
[![Project Status](https://img.shields.io/badge/status-experimental-orange.svg)](https://nodejs.org/api/documentation.html#documentation_stability_index) [![Project Status](https://img.shields.io/badge/status-experimental-orange.svg)](https://nodejs.org/api/documentation.html#documentation_stability_index)
This tool will execute a command if the dependencies or lock files of your module have changed since the last time it was run. Any of the following will be considered a change:
- If the `dependencies` or `devDependencies` in `package.json` change
- If the `dependencies` or `devDependencies` in any of your workspaces change
- Uses `workspaces` property in root `package.json`, works with Yarn workspaces
- If one of the files in your `checkFiles` config's md5 hash changes
If the command exits with a non-zero exit code, `pkgcomp` will exit with the same exit code.
**NOTE:** Out of the box the script will do nothing, you have to provide a command to run, via the `cmd` config. See [Configuration](#configuration) below.
## Usage ## Usage
Simply install the package and run it from the command line in your project. You can install it globally and run it that way, but installing locally is generally better. Simply install the package and run it from the command line in your project. You can install it globally and run it that way, but installing locally is generally better.
@@ -15,9 +26,7 @@ yarn add -D pkgcomp
npx pkgcomp npx pkgcomp
``` ```
If the `dependencies` or `devDependencies` in `package.json` change, or if one of the files in your `checkFiles` config's md5 hash changes, your command will run. If the command exits with a non-zero exit code, `pkgcomp` will exit with the same exit code. **NOTE:** Out of the box the script will do nothing, you have to provide a command to run, via the `cmd` config. See [Configuration](#configuration) below.
Out of the box the script will do nothing, you have to provide a command to run, via the `cmd` config. See [Configuration](#configuration) below.
You can also set the command, and control how the script works, via the available [command line arguments](#cli-arguments) You can also set the command, and control how the script works, via the available [command line arguments](#cli-arguments)
@@ -54,7 +63,7 @@ Configuration is provided as JSON, and can be defined in any of the following (l
### Config options ### Config options
Name | Default | Description Name | Default | Description
-- | -- | -- ---- | ------- | -----------
`checkFiles` | `['package-lock.json', 'yarn.lock']` | Additional files to checksum and compare, files that are not included will be skipped `checkFiles` | `['package-lock.json', 'yarn.lock']` | Additional files to checksum and compare, files that are not included will be skipped
`rootDir` | `process.cwd()` | The root path to your project `rootDir` | `process.cwd()` | The root path to your project
`dataDir` | `<Home>/.local/share` | Directory where this module's data should be written to `dataDir` | `<Home>/.local/share` | Directory where this module's data should be written to
@@ -88,7 +97,7 @@ As a property in `package.json`:
## CLI Arguments ## CLI Arguments
Argument | Default | Description Argument | Default | Description
-- | -- | -- -------- | ------- | -----------
`--verbose` | `false` | Shows more verbose output, like if the command is being skipped or a file in `checkFiles` does not exist `--verbose` | `false` | Shows more verbose output, like if the command is being skipped or a file in `checkFiles` does not exist
`--force` | `false` | Runs your command regardless of whether or not there were changes in the package `--force` | `false` | Runs your command regardless of whether or not there were changes in the package
`--cmd` | | Specify the command to run when changes are found (ex. `--cmd="yarn install"`) `--cmd` | | Specify the command to run when changes are found (ex. `--cmd="yarn install"`)

View File

@@ -9,11 +9,12 @@
"scripts": { "scripts": {
"lint": "eslint 'src/**/*.{js,mjs}'", "lint": "eslint 'src/**/*.{js,mjs}'",
"version": "npm-auto-version", "version": "npm-auto-version",
"start": "node ." "start": "node .",
"test": "npm run lint"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/w33ble/pkgcomp.git" "url": "git+https://git.w33ble.com/w33ble/pkgcomp.git"
}, },
"keywords": [ "keywords": [
"spawn", "spawn",
@@ -63,7 +64,7 @@
"trailingComma": "es5" "trailingComma": "es5"
}, },
"dependencies": { "dependencies": {
"fast-deep-equal": "^2.0.1", "glob-parent": "^5.0.0",
"joycon": "^2.2.4", "joycon": "^2.2.4",
"md5-file": "^4.0.0", "md5-file": "^4.0.0",
"mkdirp": "^0.5.1", "mkdirp": "^0.5.1",

View File

@@ -36,7 +36,9 @@ function buildConfig(args) {
// parse args from CLI // parse args from CLI
const args = parseArgs(); const args = parseArgs();
pkgcomp(buildConfig(args), utils.getIdent(), args).catch(err => { const { name } = utils.getPackageInfo();
pkgcomp(buildConfig(args), name, args).catch(err => {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.error(err); console.error(err);
process.exit(err.exitCode); process.exit(err.exitCode);

View File

@@ -18,7 +18,7 @@ exports.read = (fileRoot, ident) => {
try { try {
const data = JSON.parse(fs.readFileSync(filePath)); const data = JSON.parse(fs.readFileSync(filePath));
return data[ident] || {}; return JSON.stringify(data[ident] || {});
} catch (err) { } catch (err) {
if (err.code === 'ENOENT') { if (err.code === 'ENOENT') {
fs.writeFileSync(filePath, JSON.stringify({})); fs.writeFileSync(filePath, JSON.stringify({}));

View File

@@ -1,6 +1,5 @@
const path = require('path'); const path = require('path');
const md5File = require('md5-file'); const md5File = require('md5-file');
const deepEqual = require('fast-deep-equal');
const shellExec = require('shell-exec'); const shellExec = require('shell-exec');
const data = require('./data'); const data = require('./data');
const utils = require('./utils'); const utils = require('./utils');
@@ -43,14 +42,25 @@ module.exports = async function pkgcomp(config, ident, opts = defaultOptions) {
// read dependencies from package.json // read dependencies from package.json
const pkg = utils.getFileContents(path.join(config.rootDir, 'package.json'), { format: 'json' }); const pkg = utils.getFileContents(path.join(config.rootDir, 'package.json'), { format: 'json' });
// read dependencies from workspace packages
const workspaces = utils.getPackageWorkspaces().map(({ name, package }) => {
const wpkg = utils.getFileContents(path.join(config.rootDir, package), { format: 'json' });
return {
name,
dependencies: wpkg.dependencies,
devDependencies: wpkg.devDependencies,
};
});
const payload = { const payload = {
hashes, hashes,
dependencies: pkg.dependencies, dependencies: pkg.dependencies,
devDependencies: pkg.devDependencies, devDependencies: pkg.devDependencies,
workspaces,
}; };
// check if the command should be run // check if the command should be run
const runCmd = Boolean(opts.force || (doExec && !deepEqual(packageHistory, payload))); const runCmd = Boolean(opts.force || (doExec && packageHistory !== JSON.stringify(payload)));
if (runCmd) { if (runCmd) {
const res = await execCommand(config.cmd); const res = await execCommand(config.cmd);
@@ -60,6 +70,9 @@ module.exports = async function pkgcomp(config, ident, opts = defaultOptions) {
err.cmd = res.cmd; err.cmd = res.cmd;
throw err; throw err;
} }
} else if (opts.verbose) {
// eslint-disable-next-line no-console
console.log('No changes, command skipped');
} }
data.write(config.dataDir, ident, payload); data.write(config.dataDir, ident, payload);

View File

@@ -2,6 +2,7 @@ const path = require('path');
const fs = require('fs'); const fs = require('fs');
const os = require('os'); const os = require('os');
const JoyCon = require('joycon'); const JoyCon = require('joycon');
const globParent = require('glob-parent');
exports.getRootPath = () => process.cwd(); exports.getRootPath = () => process.cwd();
@@ -27,13 +28,40 @@ exports.getFileContents = (filePath, opts = {}) => {
return content; return content;
}; };
exports.getRootFileContents = (filename, opts = {}) => { exports.getPackageInfo = () => {
return exports.getFileContents(path.join(exports.getRootPath(), filename), opts); const { name, workspaces } = exports.getFileContents(
path.join(exports.getRootPath(), 'package.json'),
{
format: 'json',
}
);
if (!name) throw new Error('Unable to read project name from package.json');
// handle nohoist config: https://yarnpkg.com/blog/2018/02/15/nohoist/
const realWorkspaces = workspaces.packages ? workspaces.packages : workspaces;
return { name, workspaces: realWorkspaces };
}; };
exports.getIdent = () => { exports.getPackageWorkspaces = () => {
const { name } = exports.getRootFileContents('package.json', { format: 'json' }); const { workspaces } = exports.getPackageInfo();
return name; if (!workspaces) return [];
return workspaces.reduce((acc, glob) => {
const parent = globParent(glob);
const packages = fs
.readdirSync(parent)
.map(package => {
const packageJson = path.join(parent, package, 'package.json');
if (!exports.canAccessFile(packageJson)) return false;
return {
name: package,
package: packageJson,
};
})
.filter(Boolean);
return acc.concat(packages);
}, []);
}; };
exports.getConfig = (overrides = {}) => { exports.getConfig = (overrides = {}) => {

View File

@@ -1027,6 +1027,13 @@ getopts@^2.0.6:
resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.2.4.tgz#3137fe8a5fddf304904059a851bdc1c22f0f54fb" resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.2.4.tgz#3137fe8a5fddf304904059a851bdc1c22f0f54fb"
integrity sha512-Rz7DGyomZjrenu9Jx4qmzdlvJgvrEFHXHvjK0FcZtcTC1U5FmES7OdZHUwMuSnEE6QvBvwse1JODKj7TgbSEjQ== integrity sha512-Rz7DGyomZjrenu9Jx4qmzdlvJgvrEFHXHvjK0FcZtcTC1U5FmES7OdZHUwMuSnEE6QvBvwse1JODKj7TgbSEjQ==
glob-parent@^5.0.0:
version "5.0.0"
resolved "https://npm.w33ble.com:443/glob-parent/-/glob-parent-5.0.0.tgz#1dc99f0f39b006d3e92c2c284068382f0c20e954"
integrity sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==
dependencies:
is-glob "^4.0.1"
glob@^7.0.3, glob@^7.1.2, glob@^7.1.3: glob@^7.0.3, glob@^7.1.2, glob@^7.1.3:
version "7.1.3" version "7.1.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
@@ -1324,7 +1331,7 @@ is-fullwidth-code-point@^2.0.0:
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
is-glob@^4.0.0: is-glob@^4.0.0, is-glob@^4.0.1:
version "4.0.1" version "4.0.1"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==