Installing dependencies.

This commit is contained in:
2025-11-11 06:53:11 -05:00
parent 2c36c04da6
commit 0d2fea3c88
14371 changed files with 2770923 additions and 25 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Pierre-Denis Vanduynslager
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+184
View File
@@ -0,0 +1,184 @@
# **commit-analyzer**
[**semantic-release**](https://github.com/semantic-release/semantic-release) plugin to analyze commits with [conventional-changelog](https://github.com/conventional-changelog/conventional-changelog)
[![Build Status](https://github.com/semantic-release/commit-analyzer/workflows/Test/badge.svg)](https://github.com/semantic-release/commit-analyzer/actions?query=workflow%3ATest+branch%3Amaster) [![npm latest version](https://img.shields.io/npm/v/@semantic-release/commit-analyzer/latest.svg)](https://www.npmjs.com/package/@semantic-release/commit-analyzer)
[![npm next version](https://img.shields.io/npm/v/@semantic-release/commit-analyzer/next.svg)](https://www.npmjs.com/package/@semantic-release/commit-analyzer)
[![npm beta version](https://img.shields.io/npm/v/@semantic-release/commit-analyzer/beta.svg)](https://www.npmjs.com/package/@semantic-release/commit-analyzer)
| Step | Description |
|------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|
| `analyzeCommits` | Determine the type of release by analyzing commits with [conventional-changelog](https://github.com/conventional-changelog/conventional-changelog). |
## Install
```bash
$ npm install @semantic-release/commit-analyzer -D
```
## 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):
```json
{
"plugins": [
["@semantic-release/commit-analyzer", {
"preset": "angular",
"releaseRules": [
{"type": "docs", "scope":"README", "release": "patch"},
{"type": "refactor", "release": "patch"},
{"type": "style", "release": "patch"}
],
"parserOpts": {
"noteKeywords": ["BREAKING CHANGE", "BREAKING CHANGES"]
}
}],
"@semantic-release/release-notes-generator"
]
}
```
With this example:
- the commits that contains `BREAKING CHANGE` or `BREAKING CHANGES` in their body will be considered breaking changes.
- the commits with a 'docs' `type`, a 'README' `scope` will be associated with a `patch` release
- the commits with a 'refactor' `type` will be associated with a `patch` release
- the commits with a 'style' `type` will be associated with a `patch` release
**Note**: Your commits must be formatted **exactly** as specified by the chosen convention. For example the [Angular Commit Message Conventions](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#-git-commit-guidelines) require the `BREAKING CHANGE` keyword to be followed by a colon (`:`) and to be in the **footer** of the commit message.
## Configuration
### Options
| Option | Description | Default |
|----------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
| `preset` | [conventional-changelog](https://github.com/conventional-changelog/conventional-changelog) preset (possible values: [`angular`](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular), [`atom`](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-atom), [`codemirror`](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-codemirror), [`ember`](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-ember), [`eslint`](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-eslint), [`express`](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-express), [`jquery`](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-jquery), [`jshint`](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-jshint), [`conventionalcommits`](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-conventionalcommits)). | [`angular`](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular) |
| `config` | npm package name of a custom [conventional-changelog](https://github.com/conventional-changelog/conventional-changelog) preset. | - |
| `parserOpts` | Additional [conventional-commits-parser](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-commits-parser#conventionalcommitsparseroptions) options that will extends the ones loaded by `preset` or `config`. This is convenient to use a [conventional-changelog](https://github.com/conventional-changelog/conventional-changelog) preset with some customizations without having to create a new module. | - |
| `releaseRules` | An external module, a path to a module or an `Array` of rules. See [`releaseRules`](#releaserules). | See [`releaseRules`](#releaserules) |
| `presetConfig` | Additional configuration passed to the [conventional-changelog](https://github.com/conventional-changelog/conventional-changelog) preset. Used for example with [conventional-changelog-conventionalcommits](https://github.com/conventional-changelog/conventional-changelog-config-spec/blob/master/versions/2.0.0/README.md). | - |
**Notes**: in order to use a `preset` it must be installed (for example to use the [eslint preset](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-eslint) you must install it with `npm install conventional-changelog-eslint -D`)
**Note**: `config` will be overwritten by the values of `preset`. You should use either `preset` or `config`, but not both.
**Note**: Individual properties of `parserOpts` will override ones loaded with an explicitly set `preset` or `config`. If `preset` or `config` are not set, only the properties set in `parserOpts` will be used.
**Note**: For presets that expects a configuration object, such as [`conventionalcommits`](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-conventionalcommits), the `presetConfig` option **must** be set.
#### releaseRules
Release rules are used when deciding if the commits since the last release warrant a new release. If you define custom release rules the [default rules](lib/default-release-rules.js) will be used if nothing matched. Those rules will be matched against the commit objects resulting of [conventional-commits-parser](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-commits-parser) parsing. Each rule property can be defined as a [glob](https://github.com/micromatch/micromatch#matching-features).
##### Rules definition
This is an `Array` of rule objects. A rule object has a `release` property and 1 or more criteria.
```json
{
"plugins": [
["@semantic-release/commit-analyzer", {
"preset": "angular",
"releaseRules": [
{"type": "docs", "scope": "README", "release": "patch"},
{"type": "refactor", "scope": "core-*", "release": "minor"},
{"type": "refactor", "release": "patch"},
{"scope": "no-release", "release": false}
]
}],
"@semantic-release/release-notes-generator"
]
}
```
##### Rules matching
Each commit will be compared with each rule and when it matches, the commit will be associated with the release type in the rule's `release` property. If a commit match multiple rules, the highest release type (`major` > `minor` > `patch`) is associated with the commit.
See [release types](lib/default-release-types.js) for the release types hierarchy.
With the previous example:
- Commits with `type` 'docs' and `scope` 'README' will be associated with a `patch` release.
- Commits with `type` 'refactor' and `scope` starting with 'core-' (i.e. 'core-ui', 'core-rules', ...) will be associated with a `minor` release.
- Other commits with `type` 'refactor' (without `scope` or with a `scope` not matching the glob `core-*`) will be associated with a `patch` release.
- Commits with scope `no-release` will not be associated with a release type.
##### Default rules matching
If a commit doesn't match any rule in `releaseRules` it will be evaluated against the [default release rules](lib/default-release-rules.js).
With the previous example:
- Commits with a breaking change will be associated with a `major` release.
- Commits with `type` 'feat' will be associated with a `minor` release.
- Commits with `type` 'fix' will be associated with a `patch` release.
- Commits with `type` 'perf' will be associated with a `patch` release.
- Commits with scope `no-release` will not be associated with a release type even if they have a breaking change or the `type` 'feat', 'fix' or 'perf'.
##### No rules matching
If a commit doesn't match any rules in `releaseRules` or in [default release rules](lib/default-release-rules.js) then no release type will be associated with the commit.
With the previous example:
- Commits with `type` 'style' will not be associated with a release type.
- Commits with `type` 'test' will not be associated with a release type.
- Commits with `type` 'chore' will not be associated with a release type.
##### Multiple commits
If there is multiple commits that match one or more rules, the one with the highest release type will determine the global release type.
Considering the following commits:
- `docs(README): Add more details to the API docs`
- `feat(API): Add a new method to the public API`
With the previous example the release type determined by the plugin will be `minor`.
##### Specific commit properties
The properties to set in the rules will depends on the commit style chosen. For example [conventional-changelog-angular](https://github.com/conventional-changelog/conventional-changelog/blob/master/packages/conventional-changelog-angular) use the commit properties `type`, `scope` and `subject` but [conventional-changelog-eslint](https://github.com/conventional-changelog/conventional-changelog/blob/master/packages/conventional-changelog-eslint) uses `tag` and `message`.
For example with `eslint` preset:
```json
{
"plugins": [
["@semantic-release/commit-analyzer", {
"preset": "eslint",
"releaseRules": [
{"tag": "Docs", "message":"*README*", "release": "patch"},
{"tag": "New", "release": "patch"}
]
}],
"@semantic-release/release-notes-generator"
]
}
```
With this configuration:
- Commits with `tag` 'Docs', that contains 'README' in their header message will be associated with a `patch` release.
- Commits with `tag` 'New' will be associated with a `patch` release.
- Commits with `tag` 'Breaking' will be associated with a `major` release (per [default release rules](lib/default-release-rules.js)).
- Commits with `tag` 'Fix' will be associated with a `patch` release (per [default release rules](lib/default-release-rules.js)).
- Commits with `tag` 'Update' will be associated with a `minor` release (per [default release rules](lib/default-release-rules.js)).
- All other commits will not be associated with a release type.
##### External package / file
`releaseRules` can also reference a module, either by it's `npm` name or path:
```json
{
"plugins": [
["@semantic-release/commit-analyzer", {
"preset": "angular",
"releaseRules": "./config/release-rules.js"
}],
"@semantic-release/release-notes-generator"
]
}
```
```js
// File: config/release-rules.js
module.exports = [
{type: 'docs', scope: 'README', release: 'patch'},
{type: 'refactor', scope: 'core-*', release: 'minor'},
{type: 'refactor', release: 'patch'},
];
```
+82
View File
@@ -0,0 +1,82 @@
const {isUndefined} = require('lodash');
const parser = require('conventional-commits-parser').sync;
const filter = require('conventional-commits-filter');
const debug = require('debug')('semantic-release:commit-analyzer');
const loadParserConfig = require('./lib/load-parser-config');
const loadReleaseRules = require('./lib/load-release-rules');
const analyzeCommit = require('./lib/analyze-commit');
const compareReleaseTypes = require('./lib/compare-release-types');
const RELEASE_TYPES = require('./lib/default-release-types');
const DEFAULT_RELEASE_RULES = require('./lib/default-release-rules');
/**
* Determine the type of release to create based on a list of commits.
*
* @param {Object} pluginConfig The plugin configuration.
* @param {String} pluginConfig.preset conventional-changelog preset ('angular', 'atom', 'codemirror', 'ember', 'eslint', 'express', 'jquery', 'jscs', 'jshint')
* @param {String} pluginConfig.config Requirable npm package with a custom conventional-changelog preset
* @param {String|Array} pluginConfig.releaseRules A `String` to load an external module or an `Array` of rules.
* @param {Object} pluginConfig.parserOpts Additional `conventional-changelog-parser` options that will overwrite ones loaded by `preset` or `config`.
* @param {Object} context The semantic-release context.
* @param {Array<Object>} context.commits The commits to analyze.
* @param {String} context.cwd The current working directory.
*
* @returns {String|null} the type of release to create based on the list of commits or `null` if no release has to be done.
*/
async function analyzeCommits(pluginConfig, context) {
const {commits, logger} = context;
const releaseRules = loadReleaseRules(pluginConfig, context);
const config = await loadParserConfig(pluginConfig, context);
let releaseType = null;
filter(
commits
.filter(({message, hash}) => {
if (!message.trim()) {
debug('Skip commit %s with empty message', hash);
return false;
}
return true;
})
.map(({message, ...commitProps}) => ({rawMsg: message, message, ...commitProps, ...parser(message, config)}))
).every(({rawMsg, ...commit}) => {
logger.log(`Analyzing commit: %s`, rawMsg);
let commitReleaseType;
// Determine release type based on custom releaseRules
if (releaseRules) {
debug('Analyzing with custom rules');
commitReleaseType = analyzeCommit(releaseRules, commit);
}
// If no custom releaseRules or none matched the commit, try with default releaseRules
if (isUndefined(commitReleaseType)) {
debug('Analyzing with default rules');
commitReleaseType = analyzeCommit(DEFAULT_RELEASE_RULES, commit);
}
if (commitReleaseType) {
logger.log('The release type for the commit is %s', commitReleaseType);
} else {
logger.log('The commit should not trigger a release');
}
// Set releaseType if commit's release type is higher
if (commitReleaseType && compareReleaseTypes(releaseType, commitReleaseType)) {
releaseType = commitReleaseType;
}
// Break loop if releaseType is the highest
if (releaseType === RELEASE_TYPES[0]) {
return false;
}
return true;
});
logger.log('Analysis of %s commits complete: %s release', commits.length, releaseType || 'no');
return releaseType;
}
module.exports = {analyzeCommits};
+50
View File
@@ -0,0 +1,50 @@
const {isMatchWith, isString} = require('lodash');
const micromatch = require('micromatch');
const debug = require('debug')('semantic-release:commit-analyzer');
const RELEASE_TYPES = require('./default-release-types');
const compareReleaseTypes = require('./compare-release-types');
/**
* Find all the rules matching and return the highest release type of the matching rules.
*
* @param {Array} releaseRules the rules to match the commit against.
* @param {Commit} commit a parsed commit.
* @return {string} the highest release type of the matching rules or `undefined` if no rule match the commit.
*/
module.exports = (releaseRules, commit) => {
let releaseType;
releaseRules
.filter(
({breaking, revert, release, ...rule}) =>
// If the rule is not `breaking` or the commit doesn't have a breaking change note
(!breaking || (commit.notes && commit.notes.length > 0)) &&
// If the rule is not `revert` or the commit is not a revert
(!revert || commit.revert) &&
// Otherwise match the regular rules
isMatchWith(commit, rule, (object, src) =>
isString(src) && isString(object) ? micromatch.isMatch(object, src) : undefined
)
)
.every(match => {
if (compareReleaseTypes(releaseType, match.release)) {
releaseType = match.release;
debug('The rule %o match commit with release type %o', match, releaseType);
if (releaseType === RELEASE_TYPES[0]) {
debug('Release type %o is the highest possible. Stop analysis.', releaseType);
return false;
}
} else {
debug(
'The rule %o match commit with release type %o but the higher release type %o has already been found for this commit',
match,
match.release,
releaseType
);
}
return true;
});
return releaseType;
};
@@ -0,0 +1,11 @@
const RELEASE_TYPES = require('./default-release-types');
/**
* Test if a realease type is of higher level than a given one.
*
* @param {string} currentReleaseType the current release type.
* @param {string} releaseType the release type to compare with.
* @return {Boolean} true if `releaseType` is higher than `currentReleaseType`.
*/
module.exports = (currentReleaseType, releaseType) =>
!currentReleaseType || RELEASE_TYPES.indexOf(releaseType) < RELEASE_TYPES.indexOf(currentReleaseType);
@@ -0,0 +1,34 @@
/**
* Default `releaseRules` rules for common commit formats, following conventions.
*
* @type {Array}
*/
module.exports = [
{breaking: true, release: 'major'},
{revert: true, release: 'patch'},
// Angular
{type: 'feat', release: 'minor'},
{type: 'fix', release: 'patch'},
{type: 'perf', release: 'patch'},
// Atom
{emoji: ':racehorse:', release: 'patch'},
{emoji: ':bug:', release: 'patch'},
{emoji: ':penguin:', release: 'patch'},
{emoji: ':apple:', release: 'patch'},
{emoji: ':checkered_flag:', release: 'patch'},
// Ember
{tag: 'BUGFIX', release: 'patch'},
{tag: 'FEATURE', release: 'minor'},
{tag: 'SECURITY', release: 'patch'},
// ESLint
{tag: 'Breaking', release: 'major'},
{tag: 'Fix', release: 'patch'},
{tag: 'Update', release: 'minor'},
{tag: 'New', release: 'minor'},
// Express
{component: 'perf', release: 'patch'},
{component: 'deps', release: 'patch'},
// JSHint
{type: 'FEAT', release: 'minor'},
{type: 'FIX', release: 'patch'},
];
@@ -0,0 +1,6 @@
/**
* Type of release supported by Semver/NPM.
*
* @type {Array}
*/
module.exports = ['major', 'premajor', 'minor', 'preminor', 'patch', 'prepatch', 'prerelease'];
@@ -0,0 +1,36 @@
const {promisify} = require('util');
const {isPlainObject} = require('lodash');
const importFrom = require('import-from');
const conventionalChangelogAngular = require('conventional-changelog-angular');
/**
* Load `conventional-changelog-parser` options. Handle presets that return either a `Promise<Array>` or a `Promise<Function>`.
*
* @param {Object} pluginConfig The plugin configuration.
* @param {Object} pluginConfig.preset conventional-changelog preset ('angular', 'atom', 'codemirror', 'ember', 'eslint', 'express', 'jquery', 'jscs', 'jshint')
* @param {String} pluginConfig.config Requirable npm package with a custom conventional-changelog preset
* @param {Object} pluginConfig.parserOpts Additionnal `conventional-changelog-parser` options that will overwrite ones loaded by `preset` or `config`.
* @param {Object} context The semantic-release context.
* @param {String} context.cwd The current working directory.
* @return {Promise<Object>} a `Promise` that resolve to the `conventional-changelog-parser` options.
*/
module.exports = async ({preset, config, parserOpts, presetConfig}, {cwd}) => {
let loadedConfig;
if (preset) {
const presetPackage = `conventional-changelog-${preset.toLowerCase()}`;
loadedConfig = importFrom.silent(__dirname, presetPackage) || importFrom(cwd, presetPackage);
} else if (config) {
loadedConfig = importFrom.silent(__dirname, config) || importFrom(cwd, config);
} else {
loadedConfig = conventionalChangelogAngular;
}
loadedConfig = await (typeof loadedConfig === 'function'
? isPlainObject(presetConfig)
? loadedConfig(presetConfig)
: promisify(loadedConfig)()
: loadedConfig);
return {...loadedConfig.parserOpts, ...parserOpts};
};
@@ -0,0 +1,45 @@
const {isUndefined} = require('lodash');
const importFrom = require('import-from');
const RELEASE_TYPES = require('./default-release-types');
/**
* Load and validate the `releaseRules` rules.
*
* If `releaseRules` parameter is a `string` then load it as an external module with `require`.
* Verifies that the loaded/parameter `releaseRules` is an `Array` and each element has a valid `release` attribute.
*
* @param {Object} pluginConfig The plugin configuration.
* @param {String|Array} pluginConfig.releaseRules A `String` to load an external module or an `Array` of rules.
* @param {Object} context The semantic-release context.
* @param {String} context.cwd The current working directory.
*
* @return {Array} the loaded and validated `releaseRules`.
*/
module.exports = ({releaseRules}, {cwd}) => {
let loadedReleaseRules;
if (releaseRules) {
loadedReleaseRules =
typeof releaseRules === 'string'
? importFrom.silent(__dirname, releaseRules) || importFrom(cwd, releaseRules)
: releaseRules;
if (!Array.isArray(loadedReleaseRules)) {
throw new TypeError('Error in commit-analyzer configuration: "releaseRules" must be an array of rules');
}
loadedReleaseRules.forEach(rule => {
if (!rule || isUndefined(rule.release)) {
throw new Error('Error in commit-analyzer configuration: rules must be an object with a "release" property');
} else if (!RELEASE_TYPES.includes(rule.release) && rule.release !== null && rule.release !== false) {
throw new Error(
`Error in commit-analyzer configuration: "${
rule.release
}" is not a valid release type. Valid values are: ${JSON.stringify(RELEASE_TYPES)}`
);
}
});
}
return loadedReleaseRules;
};
+105
View File
@@ -0,0 +1,105 @@
{
"name": "@semantic-release/commit-analyzer",
"description": "semantic-release plugin to analyze commits with conventional-changelog",
"version": "9.0.2",
"author": "Pierre Vanduynslager (https://twitter.com/@pvdlg_)",
"ava": {
"files": [
"test/**/*.test.js"
]
},
"bugs": {
"url": "https://github.com/semantic-release/commit-analyzer/issues"
},
"contributors": [
"Stephan Bönnemann <stephan@boennemann.me> (http://boennemann.me)",
"Gregor Martynus (https://twitter.com/gr2m)"
],
"dependencies": {
"conventional-changelog-angular": "^5.0.0",
"conventional-commits-filter": "^2.0.0",
"conventional-commits-parser": "^3.2.3",
"debug": "^4.0.0",
"import-from": "^4.0.0",
"lodash": "^4.17.4",
"micromatch": "^4.0.2"
},
"devDependencies": {
"ava": "3.15.0",
"conventional-changelog-atom": "2.0.8",
"conventional-changelog-conventionalcommits": "4.6.1",
"conventional-changelog-ember": "2.0.9",
"conventional-changelog-eslint": "3.0.9",
"conventional-changelog-express": "2.0.6",
"conventional-changelog-jshint": "2.0.9",
"nyc": "15.1.0",
"semantic-release": "18.0.0",
"sinon": "12.0.1",
"xo": "0.28.3"
},
"engines": {
"node": ">=14.17"
},
"files": [
"lib",
"index.js"
],
"homepage": "https://github.com/semantic-release/commit-analyzer#readme",
"keywords": [
"changelog",
"commit-analyzer",
"conventional-changelog",
"conventional-commits",
"github",
"publish",
"release",
"semantic-release"
],
"license": "MIT",
"main": "index.js",
"nyc": {
"include": [
"lib/**/*.js",
"index.js"
],
"reporter": [
"json",
"text",
"html"
],
"all": true
},
"peerDependencies": {
"semantic-release": ">=18.0.0-beta.1"
},
"prettier": {
"printWidth": 120,
"trailingComma": "es5"
},
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "https://github.com/semantic-release/commit-analyzer.git"
},
"scripts": {
"lint": "xo",
"pretest": "npm run lint",
"semantic-release": "semantic-release",
"test": "nyc ava -v",
"test:ci": "nyc ava -v"
},
"xo": {
"prettier": true,
"space": true,
"rules": {
"unicorn/string-content": "off"
}
},
"renovate": {
"extends": [
"github>semantic-release/.github"
]
}
}