Skip to content

Commit

Permalink
feat(cli): add copy-values command
Browse files Browse the repository at this point in the history
  • Loading branch information
JamieMason committed Aug 22, 2017
1 parent cebae99 commit b51a2c9
Show file tree
Hide file tree
Showing 9 changed files with 184 additions and 34 deletions.
113 changes: 98 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,57 @@
[![NPM downloads](http://img.shields.io/npm/dm/syncpack.svg?style=flat-square)](https://www.npmjs.com/package/syncpack)
[![Build Status](http://img.shields.io/travis/JamieMason/syncpack/master.svg?style=flat-square)](https://travis-ci.org/JamieMason/syncpack)
[![Dependency Status](http://img.shields.io/david/JamieMason/syncpack.svg?style=flat-square)](https://david-dm.org/JamieMason/syncpack)
[![Code Climate](https://img.shields.io/codeclimate/github/JamieMason/syncpack.svg?style=flat-square)](https://codeclimate.com/github/JamieMason/syncpack)
[![Join the chat at https://gitter.im/JamieMason/syncpack](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/JamieMason/syncpack)
[![Analytics](https://ga-beacon.appspot.com/UA-45466560-5/syncpack?flat&useReferer)](https://github.com/igrigorik/ga-beacon)
<br>
[![Donate via Gratipay](https://img.shields.io/gratipay/user/JamieMason.svg)](https://gratipay.com/~JamieMason/)
[![Follow JamieMason on GitHub](https://img.shields.io/github/followers/JamieMason.svg?style=social&label=Follow)](https://github.com/JamieMason)
[![Follow fold_left on Twitter](https://img.shields.io/twitter/follow/fold_left.svg?style=social&label=Follow)](https://twitter.com/fold_left)

Synchronises the versions of dependencies used across multiple `package.json` files, such as
`packages/*/package.json` in [Lerna](https://lernajs.io) Monorepos.
Synchronises the contents of multiple `package.json` files, such as `packages/*/package.json` in
[Lerna](https://lernajs.io) Monorepos.

## Overview
## Contents

* [Installation](#installation)
* [Usage](#usage)
* [`sync-versions`](#sync-versions)
* [`copy-values`](#copy-values)

## Installation

```
npm install --global syncpack
```

## Usage

```
Usage: syncpack [options] [command]
Options:
-V, --version output the version number
-h, --help output usage information
Commands:
sync-versions synchronise dependency versions between packages
copy-values <keys...> copy values from eg. ./package.json to ./packages/*/package.json
help [cmd] display help for [cmd]
```

### `sync-versions`

```
Usage: syncpack sync-versions [options]
Options:
-p, --packages <glob> location of packages. defaults to ./packages/*/package.json
-h, --help output usage information
```

Imagine the packages `guybrush`, `herman`, and `elaine` all have `react` as a dependency, but
versions `'15.4.0'`, `'15.5.4'`, and `'15.6.1'` respectively.
Expand All @@ -25,27 +69,66 @@ versions `'15.4.0'`, `'15.5.4'`, and `'15.6.1'` respectively.
└── package.json
```

Running `syncpack` will update each `package.json` to use version `'15.6.1'` of `react` in
`dependencies`, `devDependencies`, and `peerDependencies` as needed.
To update each `package.json` to use version `'15.6.1'` of `react` in `dependencies`,
`devDependencies`, and `peerDependencies` (as needed) you can run

## Installation
```
syncpack sync-versions
```

### `copy-values`

```
npm install --global syncpack
Usage: syncpack copy-values [options] <keys...>
Options:
-p, --packages <glob> location of packages. defaults to ./packages/*/package.json
-s, --source <glob> location of source. defaults to ./package.json
-h, --help output usage information
```

## Usage
Imagine the packages `carla` and `murray` were previously hosted at their own repositories, but are
now part of your new Monorepo.

```
/Users/foldleft/Dev/monorepo/packages/
├── carla
│   └── package.json
└── murray
└── package.json
```

With the following contents

### Command Line
```
"bugs": "https://github.com/Scumm/carla/issues",
"homepage": "https://github.com/Scumm/carla#readme",
"repository": "Scumm/carla",
```

```
Usage: syncpack [options] [pattern]
"bugs": "https://github.com/Scumm/murray/issues",
"homepage": "https://github.com/Scumm/murray#readme",
"repository": "Scumm/murray",
```

Options:
To copy these fields from your Monorepo's `package.json` to each of its packages, you can run

-h, --help output usage information
-V, --version output the version number
```
syncpack copy-values bugs homepage repository
```

The default pattern of `'./packages/*/package.json'` can be overridden as follows
`syncpack './**/package.json'`
to copy the value of those properties, leaving them like so

```
"bugs": "https://github.com/Scumm/monorepo/issues",
"homepage": "https://github.com/Scumm/monorepo#readme",
"repository": "Scumm/monorepo",
```

to copy deeply nested values, pass the path to the key as follows

```
syncpack copy-values scripts.test
```
3 changes: 1 addition & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@
"version": "0.2.1",
"author": "Jamie Mason <jamie@foldleft.io> (https://github.com/JamieMason)",
"bin": {
"syncpack": "dist/bin.js"
"syncpack": "dist/bin.js",
"syncpack-sync-versions": "dist/bin-sync-versions.js",
"syncpack-copy-values": "dist/bin-copy-values.js"
},
"bugs": "https://github.com/JamieMason/syncpack/issues",
"dependencies": {
"bluebird": "3.5.0",
"chalk": "2.1.0",
"commander": "2.11.0",
"glob": "7.1.2",
"lodash": "4.17.4",
"nodent-runtime": "3.0.4",
"semver": "5.4.1"
},
Expand Down
23 changes: 23 additions & 0 deletions src/bin-copy-values.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env node

import 'nodent-runtime';
import program from 'commander';
import * as log from './lib/log';
import copyValues from './copy-values';
import { DEFAULT_PACKAGES, DEFAULT_SOURCE } from './constants';

program
.option('-p, --packages <glob>', `location of packages. defaults to ${DEFAULT_PACKAGES}`)
.option('-s, --source <glob>', `location of source. defaults to ${DEFAULT_SOURCE}`)
.parse(process.argv);

const { args = [], packages = DEFAULT_PACKAGES, source = DEFAULT_SOURCE } = program;

copyValues({
keys: args,
packagesPattern: packages,
sourcePattern: source
}).catch(err => {
log.bug('uncaught error in copyValues', err);
process.exit(1);
});
20 changes: 20 additions & 0 deletions src/bin-sync-versions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env node

import 'nodent-runtime';
import program from 'commander';
import * as log from './lib/log';
import syncVersions from './sync-versions';
import { DEFAULT_PACKAGES } from './constants';

program
.option('-p, --packages <glob>', `location of packages. defaults to ${DEFAULT_PACKAGES}`)
.parse(process.argv);

const { packages = DEFAULT_PACKAGES } = program;

syncVersions({
packagesPattern: packages
}).catch(err => {
log.bug('uncaught error in syncVersions', err);
process.exit(1);
});
21 changes: 7 additions & 14 deletions src/bin.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,13 @@
import 'nodent-runtime';
import program from 'commander';
import { version } from '../package.json';
import * as log from './lib/log';
import syncpack from './index';
import { DEFAULT_PACKAGES, DEFAULT_SOURCE } from './constants';

let patternValue;

program.version(version).arguments('[pattern]').action(pattern => {
patternValue = pattern;
});
program
.version(version)
.command('sync-versions', 'synchronise dependency versions between packages', {
isDefault: true
})
.command('copy-values <keys...>', `copy values from eg. ${DEFAULT_SOURCE} to ${DEFAULT_PACKAGES}`);

program.parse(process.argv);

syncpack({
pattern: patternValue
}).catch(err => {
log.bug('uncaught error in syncpack', err);
process.exit(1);
});
2 changes: 2 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const DEFAULT_PACKAGES = './packages/*/package.json';
export const DEFAULT_SOURCE = './package.json';
27 changes: 27 additions & 0 deletions src/copy-values.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import path from 'path';
import chalk from 'chalk';
import { get, set } from 'lodash';
import getFiles from './lib/get-files';

const getPackage = location => ({ location, json: require(location) });
const formatValue = value => JSON.stringify(value);

export default async ({ keys, packagesPattern, sourcePattern }) => {
const [source] = (await getFiles(sourcePattern)).map(getPackage);
const packages = (await getFiles(packagesPattern)).map(getPackage);

packages.forEach(pkg => {
console.log(chalk.grey.underline(path.relative(process.cwd(), pkg.location)));
keys.forEach(key => {
const value = get(source.json, key);
const previousValue = formatValue(get(pkg.json, key));
set(pkg.json, key, value);
const nextValue = formatValue(value);
if (previousValue === nextValue) {
console.log(`${key}: ${chalk.green('✓ unchanged')}`);
} else {
console.log(`${key}: ${chalk.red(previousValue)}${chalk.green(nextValue)}`);
}
});
});
};
4 changes: 2 additions & 2 deletions src/index.js → src/sync-versions.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ const reportChanges = (key, pkg, changes) => {
}
};

export default async ({ pattern = './packages/*/package.json' }) => {
const packages = (await getFiles(pattern)).map(getPackage);
export default async ({ packagesPattern }) => {
const packages = (await getFiles(packagesPattern)).map(getPackage);
const changedDeps = getChangedDeps('dependencies', packages);
const changedDevDeps = getChangedDeps('devDependencies', packages);
const changedPeerDeps = getChangedDeps('peerDependencies', packages);
Expand Down

0 comments on commit b51a2c9

Please sign in to comment.