Skip to content

Commit

Permalink
Merge pull request #27 from flo-sch/feature/esm
Browse files Browse the repository at this point in the history
Feature: ES modules
  • Loading branch information
flo-sch committed Apr 12, 2020
2 parents e5c6c2a + e457147 commit c2ac30b
Show file tree
Hide file tree
Showing 20 changed files with 379 additions and 110 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,7 @@ $RECYCLE.BIN/

package-lock.json
yarn.lock

# Dist subfolder

dist
89 changes: 68 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,61 @@
# **contributors**

[**semantic-release**](https://github.com/semantic-release/semantic-release) plugin to automatically update contributors list from git history

[![Travis](https://img.shields.io/travis/flo-sch/semantic-release-contributors.svg)](https://travis-ci.org/flo-sch/semantic-release-contributors)
[![Codecov](https://img.shields.io/codecov/c/github/flo-sch/semantic-release-contributors.svg)](https://codecov.io/gh/flo-sch/semantic-release-contributors)
[![Known Vulnerabilities](https://snyk.io/test/github/flo-sch/semantic-release-contributors/badge.svg?targetFile=package.json)](https://snyk.io/test/github/flo-sch/semantic-release-contributors?targetFile=package.json)
[![Maintainability](https://api.codeclimate.com/v1/badges/0c542e19db095ddb9947/maintainability)](https://codeclimate.com/github/flo-sch/semantic-release-contributors/maintainability)
<h1 align="center" style="border-bottom: none;">📦🤖 semantic-release-contributors</h1>
<p align="center">
<a href="https://github.com/semantic-release/semantic-release">semantic-release</a>
plugin to automatically update contributors list based on commits history
</p>
<p align="center">
<a href="https://github.com/semantic-release/semantic-release" rel="nofollow">
<img alt="Semantic Release" src="https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg">
</a>
<a href="http://commitizen.github.io/cz-cli/" rel="nofollow">
<img alt="Commitizen friendly" src="https://img.shields.io/badge/commitizen-friendly-brightgreen.svg">
</a>
</p>
<p align="center">
<a href="https://travis-ci.org/flo-sch/semantic-release-contributors" rel="nofollow">
<img alt="Travis" src="https://img.shields.io/travis/flo-sch/semantic-release-contributors.svg">
</a>
<a href="https://codecov.io/gh/flo-sch/semantic-release-contributors" rel="nofollow">
<img alt="Codecov" src="https://img.shields.io/codecov/c/github/flo-sch/semantic-release-contributors.svg">
</a>
<a href="https://snyk.io/test/github/flo-sch/semantic-release-contributors?targetFile=package.json" rel="nofollow">
<img alt="Known Vulnerabilities" src="https://snyk.io/test/github/flo-sch/semantic-release-contributors/badge.svg?targetFile=package.json">
</a>
<a href="https://codeclimate.com/github/flo-sch/semantic-release-contributors/maintainability" rel="nofollow">
<img alt="Maintainability" src="https://api.codeclimate.com/v1/badges/0c542e19db095ddb9947/maintainability">
</a>
</p>
<p align="center">
<a href="https://www.npmjs.com/package/semantic-release-contributors" rel="nofollow">
<img alt="npm latest version" src="https://img.shields.io/npm/v/semantic-release-contributors/latest.svg">
</a>
<a href="https://bundlephobia.com/result?p=semantic-release-contributors@2.0.2" rel="nofollow">
<img alt="npm bundle size" src="https://img.shields.io/bundlephobia/min/semantic-release-contributors">
</a>
<a href="https://bundlephobia.com/result?p=semantic-release-contributors@2.0.2" rel="nofollow">
<img alt="npm bundle size" src="https://img.shields.io/bundlephobia/minzip/semantic-release-contributors">
</a>
<a href="https://img.shields.io/npm/l/semantic-release-contributors" rel="nofollow">
<img alt="LICENSE" src="https://img.shields.io/npm/l/semantic-release-contributors">
</a>
</p>

[![npm latest version](https://img.shields.io/npm/v/semantic-release-contributors/latest.svg)](https://www.npmjs.com/package/semantic-release-contributors)
------------------

| Step | Description |
|----------------|------------------------------------------------------------------------------------------------------------|
| `prepare` | Determine the contributors list by analyzing git history. |
| Step | Description |
|----------------|-----------------------------------------------------------------------------------------------------|
| `prepare` | Determine the contributors list by analyzing commits history. |

## Install

```bash
$ npm install semantic-release-contributors -D
npm install semantic-release-contributors -D
```

## How does it work?
## How does it work

Whenener someone commit to the project, his/her name will be appended to the [contributors list of your package.json](https://docs.npmjs.com/files/package.json#people-fields-author-contributors) file.
Whenener someone commit to the project, his/her name will be appended
to the [contributors list of your package.json](https://docs.npmjs.com/files/package.json#people-fields-author-contributors) file.

If `Paul Smith` commits to a project with the following set-up:

Expand All @@ -48,26 +82,39 @@ The `package.json` file would then be updated to:
}
```

**NOTE**: this package internally deserialize the contributors to objects (name, email, url) and make sure duplicated emails are removed. Contributors objects are then potentially re-serialized before being written to the package file (unless you opt for a different format)
**NOTE**: this package internally deserialize the contributors to
objects (name, email, url) and make sure duplicated emails are removed.
Contributors objects are then potentially re-serialized before being written
to the package file (unless you opt for a different format)

## Usage

The plugin can be configured in the [**semantic-release** configuration file](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/configuration.md#configuration):

**IMPORTANT**: since this plugin acts on semantic-release's "prepare" step
and do not commit the updated package.json file itself,
it *requires* to be placed *before* "@semantic-release/git".

```json
{
"plugins": [
// important: insert it before @semantic-release/git
["semantic-release-contributors", {
"format": "string",
"pkgRoot": "."
}]
}],
// ...
"@semantic-release/git"
// ...
]
}
```

With this example:
- the contributors will be stringified to `name <email>`
- the package file containing the contributors will be read then updated in the current directory

* the contributors will be stringified to `name <email>`
* the package file containing the contributors will be read
then updated in the current directory

## Configuration

Expand All @@ -80,8 +127,8 @@ With this example:

## Similar or related projects

- [parse-author](https://www.npmjs.com/package/parse-author)
- [stringify-author](https://www.npmjs.com/package/stringify-author)
* [parse-author](https://www.npmjs.com/package/parse-author)
* [stringify-author](https://www.npmjs.com/package/stringify-author)

<p align="center">
<img alt="Kill all humans" src="media/bender-with-memory.jpg">
Expand Down
26 changes: 0 additions & 26 deletions index.js

This file was deleted.

18 changes: 18 additions & 0 deletions lib/contributors/get-contributors-from-commits.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import uniqBy from '../helpers/uniq-by';
import sortBy from '../helpers/sort-by';

/**
* Extract an array of contributors from an array of commits, removing duplicates on email
*
* @param array commits
*/
const getContributorsFromCommits = (commits = []) =>
uniqBy(
sortBy(commits, 'date').map((commit) => ({
email: commit.author.email,
name: commit.author.name,
})),
'email'
);

export default getContributorsFromCommits;
24 changes: 24 additions & 0 deletions lib/contributors/merge-contributors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import parseAuthor from 'parse-author';
import uniqBy from '../helpers/uniq-by';

/**
* Parse a contributor string with parse-author
*
* @param mixed contributor
*
* @return object
*/
const parseContributor = (contributor) => (typeof contributor === 'string' ? parseAuthor(contributor) : contributor);

/**
* Merge array of contributors, parsing them and removing duplicates on email
*
* @param array packageContributors
* @param array commitsContributors
*
* @return array
*/
const mergeContributors = (packageContributors = [], commitsContributors = []) =>
uniqBy(packageContributors.concat(commitsContributors).map(parseContributor), 'email');

export default mergeContributors;
33 changes: 33 additions & 0 deletions lib/contributors/save-contributors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {readFile, writeFile} from 'jsonfile';
import stringifyAuthor from 'stringify-author';
import mergeContributors from './merge-contributors';

/**
* Save an array of contributors to a package.json file
*
* @param string packageFilePath
* @param array contributors
* @param string format
* @param mixed logger
*/
const saveContributors = async (packageFilePath, contributors = [], format = 'string', logger = undefined) => {
const pkg = await readFile(packageFilePath);

let allContributors = mergeContributors(pkg.contributors, contributors);

if (format === 'string') {
allContributors = allContributors.map(stringifyAuthor);
}

if (logger) {
logger.info('Updated contributors list', allContributors);
}

pkg.contributors = allContributors;

await writeFile(packageFilePath, pkg, {
spaces: 2,
});
};

export default saveContributors;
10 changes: 0 additions & 10 deletions lib/get-contributors-from-commits.js

This file was deleted.

22 changes: 22 additions & 0 deletions lib/helpers/sort-by.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* Sort an array of objects by a given property
*
* @param array items
* @param string property
*
* @return array
*/
const sortBy = (items, property) =>
items.sort((itemA, itemB) => {
if (itemA[property] > itemB[property]) {
return -1;
}

if (itemA[property] < itemB[property]) {
return 1;
}

return 0;
});

export default sortBy;
21 changes: 21 additions & 0 deletions lib/helpers/uniq-by.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Remove duplicates from an array of objects by a given property
*
* @param array items
* @param string property
*
* @return array
*/
const uniqBy = (items, property) =>
items.reduce((uniqItems, item) => {
const value = item[property];
const uniqKeys = uniqItems.map((i) => i[property]);

if (typeof value === 'undefined' || !uniqKeys.includes(value)) {
uniqItems.push(item);
}

return uniqItems;
}, []);

export default uniqBy;
3 changes: 3 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import prepare from './steps/prepare';

export {prepare};
12 changes: 0 additions & 12 deletions lib/merge-contributors.js

This file was deleted.

23 changes: 0 additions & 23 deletions lib/save-contributors.js

This file was deleted.

29 changes: 29 additions & 0 deletions lib/steps/prepare.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import path from 'path';
import AggregateError from 'aggregate-error';
import getContributorsFromCommits from '../contributors/get-contributors-from-commits';
import saveContributors from '../contributors/save-contributors';

const prepare = async (pluginConfig, context) => {
const errors = [];
const {cwd, commits, logger} = context;

const format = ['string', 'object'].includes(pluginConfig.format) ? pluginConfig.format : 'string';
const pkgRoot = pluginConfig.pkgRoot || '.';

try {
await saveContributors(
path.resolve(cwd, pkgRoot, 'package.json'),
getContributorsFromCommits(commits),
format,
logger
);
} catch (error) {
errors.push(error);
}

if (errors.length > 0) {
throw new AggregateError(errors);
}
};

export default prepare;
Loading

0 comments on commit c2ac30b

Please sign in to comment.