Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

lerna-changelog

Package Overview
Dependencies
Maintainers
3
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

lerna-changelog - npm Package Compare versions

Comparing version 0.2.3 to 0.3.0

.changelog/github/issue/13

4

lib/ApiDataCache.js

@@ -31,4 +31,4 @@ "use strict";

function ApiDataCache(host, _ref) {
var rootPath = _ref.rootPath;
var cacheDir = _ref.cacheDir;
var rootPath = _ref.rootPath,
cacheDir = _ref.cacheDir;

@@ -35,0 +35,0 @@ _classCallCheck(this, ApiDataCache);

@@ -7,2 +7,4 @@ "use strict";

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

@@ -32,6 +34,13 @@

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var UNRELEASED_TAG = "___unreleased___";
var COMMIT_FIX_REGEX = /(fix|close|resolve)(e?s|e?d)? [T#](\d+)/i;
var Changelog = function () {
function Changelog(config) {
function Changelog() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
_classCallCheck(this, Changelog);

@@ -41,2 +50,6 @@

this.remote = new _RemoteRepo2.default(this.config);
// CLI options
this.tagFrom = options["tag-from"];
this.tagTo = options["tag-to"];
}

@@ -64,84 +77,98 @@

var commitInfo = this.getCommitInfo();
var committers = this.getCommitters(commitInfo);
var commitsByCategory = this.getCommitsByCategory(commitInfo);
var fixesRegex = /(fix|close|resolve)(e?s|e?d)? [T#](\d+)/i;
var date = new Date().toISOString();
date = date.slice(0, date.indexOf("T"));
var markdown = "\n";
markdown += "## Unreleased (" + date + ")";
// Get all info about commits in a certain tags range
var commitsInfo = this.getCommitsInfo();
var commitsByTag = this.getCommitsByTag(commitsInfo);
_progressBar2.default.init(commitsByCategory.length);
Object.keys(commitsByTag).forEach(function (tag) {
var commitsForTag = commitsByTag[tag].commits;
var commitsByCategory = _this.getCommitsByCategory(commitsForTag);
var committers = _this.getCommitters(commitsForTag);
commitsByCategory.filter(function (category) {
return category.commits.length > 0;
}).forEach(function (category) {
_progressBar2.default.tick(category.heading);
// Skip this iteration if there are no commits available for the tag
var hasCommitsForCurrentTag = commitsByCategory.some(function (category) {
return category.commits.length > 0;
});
if (!hasCommitsForCurrentTag) return;
var commitsByPackage = {};
var releaseTitle = tag === UNRELEASED_TAG ? "Unreleased" : tag;
markdown += "## " + releaseTitle + " (" + commitsByTag[tag].date + ")";
category.commits.forEach(function (commit) {
_progressBar2.default.init(commitsByCategory.length);
// Array of unique packages.
var changedPackages = Object.keys((0, _execSync2.default)("git show -m --name-only --pretty='format:' --first-parent " + commit.commitSHA)
// turn into an array
.split("\n")
// extract base package name, and stuff into an object for deduping.
.reduce(function (obj, files) {
if (files.indexOf("packages/") === 0) {
obj[files.slice(9).split("/", 1)[0]] = true;
}
return obj;
}, {}));
commitsByCategory.filter(function (category) {
return category.commits.length > 0;
}).forEach(function (category) {
_progressBar2.default.tick(category.heading);
var heading = changedPackages.length > 0 ? "* " + changedPackages.map(function (pkg) {
return "`" + pkg + "`";
}).join(", ") : "* Other"; // No changes to packages, but still relevant.
var commitsByPackage = category.commits.reduce(function (acc, commit) {
// Array of unique packages.
var changedPackages = _this.getListOfUniquePackages(commit.commitSHA);
if (!commitsByPackage[heading]) {
commitsByPackage[heading] = [];
}
var heading = changedPackages.length > 0 ? "* " + changedPackages.map(function (pkg) {
return "`" + pkg + "`";
}).join(", ") : "* Other";
// No changes to packages, but still relevant.
var existingCommitsForHeading = acc[heading] || [];
return _extends({}, acc, _defineProperty({}, heading, existingCommitsForHeading.concat(commit)));
}, {});
commitsByPackage[heading].push(commit);
});
markdown += "\n";
markdown += "\n";
markdown += "#### " + category.heading;
markdown += "\n";
markdown += "\n";
markdown += "#### " + category.heading;
Object.keys(commitsByPackage).forEach(function (heading) {
markdown += "\n" + heading;
Object.keys(commitsByPackage).forEach(function (heading) {
markdown += "\n" + heading;
commitsByPackage[heading].forEach(function (commit) {
markdown += "\n * ";
commitsByPackage[heading].forEach(function (commit) {
if (commit.number) {
var prUrl = _this.remote.getBasePullRequestUrl() + commit.number;
markdown += "[#" + commit.number + "](" + prUrl + ") ";
}
markdown += "\n * ";
if (commit.title.match(COMMIT_FIX_REGEX)) {
commit.title = commit.title.replace(COMMIT_FIX_REGEX, "Closes [#$3](" + _this.remote.getBaseIssueUrl() + "$3)");
}
if (commit.number) {
var prUrl = _this.remote.getBasePullRequestUrl() + commit.number;
markdown += "[#" + commit.number + "](" + prUrl + ") ";
}
if (commit.title.match(fixesRegex)) {
commit.title = commit.title.replace(fixesRegex, "Closes [#$3](" + _this.remote.getBaseIssueUrl() + "$3)");
}
markdown += commit.title + "." + " ([@" + commit.user.login + "](" + commit.user.html_url + "))";
markdown += commit.title + "." + " ([@" + commit.user.login + "](" + commit.user.html_url + "))";
});
});
});
});
_progressBar2.default.terminate();
_progressBar2.default.terminate();
markdown += "\n\n#### Committers: " + committers.length + "\n";
markdown += committers.map(function (commiter) {
return "- " + commiter;
}).join("\n");
markdown += "\n\n#### Committers: " + committers.length + "\n";
markdown += committers.map(function (commiter) {
return "- " + commiter;
}).join("\n");
markdown += "\n\n\n";
});
return markdown;
return markdown.substring(0, markdown.length - 3);
}
}, {
key: "getListOfUniquePackages",
value: function getListOfUniquePackages(sha) {
return Object.keys(
// turn into an array
(0, _execSync2.default)("git show -m --name-only --pretty='format:' --first-parent " + sha).split("\n").reduce(function (acc, files) {
if (files.indexOf("packages/") === 0) {
acc[files.slice(9).split("/", 1)[0]] = true;
}
return acc;
}, {}));
}
}, {
key: "getListOfTags",
value: function getListOfTags() {
var tags = (0, _execSync2.default)("git tag");
if (tags) {
return tags.split("\n");
}
return [];
}
}, {
key: "getLastTag",

@@ -154,5 +181,16 @@ value: function getLastTag() {

value: function getListOfCommits() {
var lastTag = this.getLastTag();
var commits = (0, _execSync2.default)("git log --oneline " + lastTag + "..").split("\n");
return commits;
// Determine the tags range to get the commits for. Custom from/to can be
// provided via command-line options.
// Default is "from last tag".
var tagFrom = this.tagFrom || this.getLastTag();
var tagTo = this.tagTo || "";
var tagsRange = tagFrom + ".." + tagTo;
var commits = (0, _execSync2.default)(
// Prints "<short-hash>;<ref-name>;<summary>;<date>"
// This format is used in `getCommitsInfo` for easily analize the commit.
"git log --oneline --pretty=\"%h;%D;%s;%cd\" --date=short " + tagsRange);
if (commits) {
return commits.split("\n");
}
return [];
}

@@ -168,3 +206,8 @@ }, {

var login = (commit.user || {}).login;
if (login && !committers[login]) {
// If a list of `ignoreCommitters` is provided in the lerna.json config
// check if the current committer should be kept or not.
var shouldKeepCommiter = login && (!_this2.config.ignoreCommitters || !_this2.config.ignoreCommitters.some(function (c) {
return c === login || login.indexOf(c) > -1;
}));
if (login && shouldKeepCommiter && !committers[login]) {
var user = _this2.remote.getUserData(login);

@@ -185,15 +228,29 @@ var userNameAndLink = "[" + login + "](" + user.html_url + ")";

}, {
key: "getCommitInfo",
value: function getCommitInfo() {
key: "getCommitsInfo",
value: function getCommitsInfo() {
var _this3 = this;
var commits = this.getListOfCommits();
var allTags = this.getListOfTags();
_progressBar2.default.init(commits.length);
var logs = commits.map(function (commit) {
var commitsInfo = commits.map(function (commit) {
// commit is formatted as following:
// <short-hash>;<ref-name>;<summary>;<date>
var parts = commit.split(";");
var sha = parts[0];
var _refs = parts[1];
var tagsInCommit = void 0;
if (_refs.length > 1) {
// Since there might be multiple tags referenced by the same commit,
// we need to treat all of them as a list.
tagsInCommit = allTags.reduce(function (acc, tag) {
if (_refs.indexOf(tag) < 0) return acc;
return acc.concat(tag);
}, []);
}
var message = parts[2];
var date = parts[3];
var sha = commit.slice(0, 7);
var message = commit.slice(8);
var response;
_progressBar2.default.tick(sha);

@@ -203,55 +260,96 @@

if (message.indexOf("Merge pull request ") === 0) {
var start = message.indexOf("#") + 1;
var end = message.slice(start).indexOf(" ");
var issueNumber = message.slice(start, start + end);
var commitInfo = {
commitSHA: sha,
message: message,
// Note: Only merge commits or commits referencing an issue / PR
// will be kept in the changelog.
labels: [],
tags: tagsInCommit,
date: date
};
response = _this3.remote.getIssueData(issueNumber);
if (message.indexOf("Merge pull request ") === 0 || mergeCommit) {
var issueNumber = void 0;
if (message.indexOf("Merge pull request ") === 0) {
var start = message.indexOf("#") + 1;
var end = message.slice(start).indexOf(" ");
issueNumber = message.slice(start, start + end);
} else issueNumber = mergeCommit[1];
var response = _this3.remote.getIssueData(issueNumber);
response.commitSHA = sha;
response.mergeMessage = message;
return response;
} else if (mergeCommit) {
var issueNumber = mergeCommit[1];
response = _this3.remote.getIssueData(issueNumber);
response.commitSHA = sha;
response.mergeMessage = message;
return response;
Object.assign(commitInfo, response);
}
return {
commitSHA: sha,
message: message,
labels: []
};
return commitInfo;
});
_progressBar2.default.terminate();
return logs;
return commitsInfo;
}
}, {
key: "getCommitsByCategory",
value: function getCommitsByCategory(logs) {
key: "getCommitsByTag",
value: function getCommitsByTag(commits) {
var _this4 = this;
var categories = this.remote.getLabels().map(function (label) {
var commits = [];
// Analyze the commits and group them by tag.
// This is useful to generate multiple release logs in case there are
// multiple release tags.
var currentTags = [UNRELEASED_TAG];
return commits.reduce(function (acc, commit) {
if (commit.tags && commit.tags.length > 0) {
currentTags = commit.tags;
}
logs.forEach(function (log) {
var labels = log.labels.map(function (label) {
return label.name.toLowerCase();
});
// Tags referenced by commits are treated as a list. When grouping them,
// we split the commits referenced by multiple tags in their own group.
// This results in having one group of commits for each tag, even if
// the same commits are "duplicated" across the different tags
// referencing them.
var commitsForTags = currentTags.reduce(function (acc2, currentTag) {
var existingCommitsForTag = [];
if ({}.hasOwnProperty.call(acc, currentTag)) {
existingCommitsForTag = acc[currentTag].commits;
}
if (labels.indexOf(label.toLowerCase()) >= 0) {
commits.push(log);
var releaseDate = _this4.getToday();
if (currentTag !== UNRELEASED_TAG) {
releaseDate = acc[currentTag] ? acc[currentTag].date : commit.date;
}
});
return _extends({}, acc2, _defineProperty({}, currentTag, {
date: releaseDate,
commits: existingCommitsForTag.concat(commit)
}));
}, {});
return _extends({}, acc, commitsForTags);
}, {});
}
}, {
key: "getCommitsByCategory",
value: function getCommitsByCategory(commits) {
var _this5 = this;
return this.remote.getLabels().map(function (label) {
return {
heading: _this4.remote.getHeadingForLabel(label),
commits: commits
heading: _this5.remote.getHeadingForLabel(label),
// Keep only the commits that have a matching label with the one
// provided in the lerna.json config.
commits: commits.reduce(function (acc, commit) {
if (commit.labels.some(function (l) {
return l.name.toLowerCase() === label.toLowerCase();
})) return acc.concat(commit);
return acc;
}, [])
};
});
return categories;
}
}, {
key: "getToday",
value: function getToday() {
var date = new Date().toISOString();
return date.slice(0, date.indexOf("T"));
}
}]);

@@ -262,9 +360,2 @@

exports.default = Changelog;
function toTitleCase(str) {
return str.replace(/\w\S*/g, function (text) {
return text.charAt(0).toUpperCase() + text.substr(1).toLowerCase();
});
}
exports.default = Changelog;

@@ -1,2 +0,2 @@

'use strict';
"use strict";

@@ -14,3 +14,3 @@ Object.defineProperty(exports, "__esModule", {

function ConfigurationError(message) {
this.name = 'ConfigurationError';
this.name = "ConfigurationError";
this.message = message;

@@ -17,0 +17,0 @@ this.stack = new Error().stack;

@@ -32,4 +32,4 @@ "use strict";

this.repo = repo;
this.cache = new _ApiDataCache2.default('github', config);
this.auth = process.env.GITHUB_AUTH;
this.cache = new _ApiDataCache2.default("github", config);
this.auth = this.getAuthToken();
if (!this.auth) {

@@ -41,5 +41,10 @@ throw new _ConfigurationError2.default("Must provide GITHUB_AUTH");

_createClass(GithubAPI, [{
key: "getAuthToken",
value: function getAuthToken() {
return process.env.GITHUB_AUTH;
}
}, {
key: "getIssueData",
value: function getIssueData(issue) {
return this._get('issue', issue);
return this._get("issue", issue);
}

@@ -49,3 +54,3 @@ }, {

value: function getUserData(login) {
return this._get('user', login);
return this._get("user", login);
}

@@ -70,3 +75,3 @@ }, {

var url = "https://api.github.com" + path;
return (0, _execSync2.default)("curl -H 'Authorization: token " + process.env.GITHUB_AUTH + "' --silent " + url);
return (0, _execSync2.default)("curl -H 'Authorization: token " + process.env.GITHUB_AUTH + "' --silent --globoff " + url);
}

@@ -73,0 +78,0 @@ }]);

@@ -21,4 +21,4 @@ "use strict";

var repo = config.repo;
var labels = config.labels;
var repo = config.repo,
labels = config.labels;

@@ -25,0 +25,0 @@ this.repo = repo;

{
"name": "lerna-changelog",
"version": "0.2.3",
"version": "0.3.0",
"description": "Generate a changelog for a lerna monorepo",
"main": "index.js",
"bin": {
"lerna-changelog": "cli.js"
"lerna-changelog": "./bin/cli.js"
},
"scripts": {
"build": "babel src -d lib",
"build": "npm run clean && babel src --out-dir lib --ignore src/__mocks__",
"watch": "npm run build -- --watch",
"clean": "rimraf lib",
"test": "eslint index.js cli.js src/",
"prepublish": "npm run build"
"lint": "eslint index.js cli.js src",
"fix": "npm run lint -- --fix",
"test": "jest",
"test-ci": "npm run build && jest",
"prepublish": "npm run build",
"changelog": "node ./bin/cli.js"
},

@@ -30,6 +35,13 @@ "repository": {

"devDependencies": {
"babel-cli": "^6.9.0",
"babel-preset-es2015": "^6.9.0",
"eslint": "^2.10.2",
"rimraf": "^2.5.2"
"babel-cli": "^6.18.0",
"babel-eslint": "^7.1.1",
"babel-jest": "^18.0.0",
"babel-plugin-transform-object-rest-spread": "6.20.2",
"babel-preset-es2015": "^6.18.0",
"eslint": "^3.13.1",
"eslint-config-babel": "^6.0.0",
"eslint-plugin-flowtype": "^2.30.0",
"jest": "^18.1.0",
"lerna": "^2.0.0-beta.32",
"rimraf": "^2.5.4"
},

@@ -41,4 +53,5 @@ "peerDependencies": {

"chalk": "^1.1.3",
"mkdirp": "^0.5.1"
"mkdirp": "^0.5.1",
"yargs": "^6.6.0"
}
}

@@ -74,5 +74,27 @@ # Lerna Changelog

- `labels`: GitHub issue/PR labels mapped to changelog section headers
- `ignoreCommitters` [optional]: list of commiters to ignore (exact or partial match). Useful for example to ignore commits from bot agents
## CLI
```bash
$ lerna-changelog
Usage: lerna-changelog [options]
Options:
--tag-from A git tag that determines the lower bound of the range of commits
(defaults to last available) [string]
--tag-to A git tag that determines the upper bound of the range of commits
[string]
--version Show version number [boolean]
--help Show help [boolean]
Examples:
lerna-changelog create a changelog for the changes
after the latest available tag
lerna-changelog --tag-from 0.1.0 create a changelog for the changes
--tag-to 0.3.0 in all tags within the given range
```
[lerna-homepage]: https://lernajs.io
[hzoo-profile]: https://github.com/hzoo
[original-pr]: https://github.com/lerna/lerna/pull/29

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc