diff --git a/README.md b/README.md index a9c9b590..b25277dc 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,10 @@ This action will bump version, tag commit and generate a changelog with conventi - **Optional** `pre-release`: Marks the release as pre-release. Default `false`. - **Optional** `pre-release-identifier`: The identifier to use for the pre-release. Default `rc`. +### Presets +This action comes pre-compiled with the `angular` (default) and `conventionalcommits`, if you wish to use an other preset +you need to make sure it's installed with `npm install conventional-changelog-` + ### Pre-Commit hook > Function in a specified file will be run right before the git-add-git-commit phase, when the next diff --git a/dist/commit1.hbs b/dist/commit1.hbs index 3b2cd685..641c2f37 100644 --- a/dist/commit1.hbs +++ b/dist/commit1.hbs @@ -1,20 +1,15 @@ -* {{header}} +*{{#if scope}} **{{scope}}:** +{{~/if}} {{#if subject}} + {{~subject}} +{{~else}} + {{~header}} +{{~/if}} -{{~!-- commit link --}} -{{~#if @root.linkReferences}} ([{{hash}}]( - {{~#if @root.repository}} - {{~#if @root.host}} - {{~@root.host}}/ - {{~/if}} - {{~#if @root.owner}} - {{~@root.owner}}/ - {{~/if}} - {{~@root.repository}} - {{~else}} - {{~@root.repoUrl}} - {{~/if}}/ - {{~@root.commit}}/{{hash}})) -{{~else if hash}} {{hash}}{{~/if}} +{{~!-- commit link --}}{{~#if hash}} {{#if @root.linkReferences~}} + ([{{shortHash}}]({{commitUrlFormat}})) +{{~else}} + {{~shortHash}} +{{~/if}}{{~/if}} {{~!-- commit references --}} {{~#if references~}} @@ -24,31 +19,12 @@ {{~#if this.owner}} {{~this.owner}}/ {{~/if}} - {{~this.repository}}#{{this.issue}}]( - {{~#if @root.repository}} - {{~#if @root.host}} - {{~@root.host}}/ - {{~/if}} - {{~#if this.repository}} - {{~#if this.owner}} - {{~this.owner}}/ - {{~/if}} - {{~this.repository}} - {{~else}} - {{~#if @root.owner}} - {{~@root.owner}}/ - {{~/if}} - {{~@root.repository}} - {{~/if}} - {{~else}} - {{~@root.repoUrl}} - {{~/if}}/ - {{~@root.issue}}/{{this.issue}}) + {{~this.repository}}{{this.prefix}}{{this.issue}}]({{issueUrlFormat}}) {{~else}} {{~#if this.owner}} {{~this.owner}}/ {{~/if}} - {{~this.repository}}#{{this.issue}} + {{~this.repository}}{{this.prefix}}{{this.issue}} {{~/if}}{{/each}} {{~/if}} diff --git a/dist/commit2.hbs b/dist/commit2.hbs new file mode 100644 index 00000000..3b2cd685 --- /dev/null +++ b/dist/commit2.hbs @@ -0,0 +1,54 @@ +* {{header}} + +{{~!-- commit link --}} +{{~#if @root.linkReferences}} ([{{hash}}]( + {{~#if @root.repository}} + {{~#if @root.host}} + {{~@root.host}}/ + {{~/if}} + {{~#if @root.owner}} + {{~@root.owner}}/ + {{~/if}} + {{~@root.repository}} + {{~else}} + {{~@root.repoUrl}} + {{~/if}}/ + {{~@root.commit}}/{{hash}})) +{{~else if hash}} {{hash}}{{~/if}} + +{{~!-- commit references --}} +{{~#if references~}} + , closes + {{~#each references}} {{#if @root.linkReferences~}} + [ + {{~#if this.owner}} + {{~this.owner}}/ + {{~/if}} + {{~this.repository}}#{{this.issue}}]( + {{~#if @root.repository}} + {{~#if @root.host}} + {{~@root.host}}/ + {{~/if}} + {{~#if this.repository}} + {{~#if this.owner}} + {{~this.owner}}/ + {{~/if}} + {{~this.repository}} + {{~else}} + {{~#if @root.owner}} + {{~@root.owner}}/ + {{~/if}} + {{~@root.repository}} + {{~/if}} + {{~else}} + {{~@root.repoUrl}} + {{~/if}}/ + {{~@root.issue}}/{{this.issue}}) + {{~else}} + {{~#if this.owner}} + {{~this.owner}}/ + {{~/if}} + {{~this.repository}}#{{this.issue}} + {{~/if}}{{/each}} +{{~/if}} + diff --git a/dist/footer1.hbs b/dist/footer1.hbs index dca482f2..e69de29b 100644 --- a/dist/footer1.hbs +++ b/dist/footer1.hbs @@ -1,10 +0,0 @@ -{{#if noteGroups}} -{{#each noteGroups}} - -### {{title}} - -{{#each notes}} -* {{text}} -{{/each}} -{{/each}} -{{/if}} diff --git a/dist/footer2.hbs b/dist/footer2.hbs new file mode 100644 index 00000000..dca482f2 --- /dev/null +++ b/dist/footer2.hbs @@ -0,0 +1,10 @@ +{{#if noteGroups}} +{{#each noteGroups}} + +### {{title}} + +{{#each notes}} +* {{text}} +{{/each}} +{{/each}} +{{/if}} diff --git a/dist/header1.hbs b/dist/header1.hbs index 49f56073..d7efc8fb 100644 --- a/dist/header1.hbs +++ b/dist/header1.hbs @@ -1,9 +1,9 @@ -## {{#if isPatch~}} - {{~/if~}} {{version}} - {{~#if title}} "{{title}}" - {{~/if~}} - {{~#if date}} ({{date}}) - {{~/if~}} - {{~#if isPatch~}} - {{~/if}} - +## {{#if @root.linkCompare~}} + [{{version}}]({{compareUrlFormat}}) +{{~else}} + {{~version}} +{{~/if}} +{{~#if title}} "{{title}}" +{{~/if}} +{{~#if date}} ({{date}}) +{{/if}} diff --git a/dist/header2.hbs b/dist/header2.hbs new file mode 100644 index 00000000..49f56073 --- /dev/null +++ b/dist/header2.hbs @@ -0,0 +1,9 @@ +## {{#if isPatch~}} + {{~/if~}} {{version}} + {{~#if title}} "{{title}}" + {{~/if~}} + {{~#if date}} ({{date}}) + {{~/if~}} + {{~#if isPatch~}} + {{~/if}} + diff --git a/dist/index.js b/dist/index.js index 7103cf63..3fa67bed 100644 --- a/dist/index.js +++ b/dist/index.js @@ -5624,6 +5624,390 @@ function getWriterOpts () { } +/***/ }), + +/***/ 5498: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + + +const DEFAULT_COMMIT_TYPES = Object.freeze([ + { type: 'feat', section: 'Features' }, + { type: 'feature', section: 'Features' }, + { type: 'fix', section: 'Bug Fixes' }, + { type: 'perf', section: 'Performance Improvements' }, + { type: 'revert', section: 'Reverts' }, + { type: 'docs', section: 'Documentation', hidden: true }, + { type: 'style', section: 'Styles', hidden: true }, + { type: 'chore', section: 'Miscellaneous Chores', hidden: true }, + { type: 'refactor', section: 'Code Refactoring', hidden: true }, + { type: 'test', section: 'Tests', hidden: true }, + { type: 'build', section: 'Build System', hidden: true }, + { type: 'ci', section: 'Continuous Integration', hidden: true } +].map(Object.freeze)) + +exports.DEFAULT_COMMIT_TYPES = DEFAULT_COMMIT_TYPES + + +/***/ }), + +/***/ 8283: +/***/ ((module) => { + +"use strict"; + + +function createConventionalChangelogOpts (parserOpts, writerOpts) { + return { + parserOpts, + writerOpts + } +} + +module.exports.createConventionalChangelogOpts = createConventionalChangelogOpts + + +/***/ }), + +/***/ 2287: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; + + +const { addBangNotes } = __nccwpck_require__(4672) + +function createConventionalRecommendedBumpOpts (config, parserOpts) { + return { + parserOpts, + + whatBump (commits) { + let level = 2 + let breakings = 0 + let features = 0 + + commits.forEach(commit => { + // adds additional breaking change notes + // for the special case, test(system)!: hello world, where there is + // a '!' but no 'BREAKING CHANGE' in body: + addBangNotes(commit) + if (commit.notes.length > 0) { + breakings += commit.notes.length + level = 0 + } else if (commit.type === 'feat' || commit.type === 'feature') { + features += 1 + if (level === 2) { + level = 1 + } + } + }) + + if (config?.preMajor && level < 2) { + level++ + } + + return { + level, + reason: breakings === 1 + ? `There is ${breakings} BREAKING CHANGE and ${features} features` + : `There are ${breakings} BREAKING CHANGES and ${features} features` + } + } + } +} + +module.exports.createConventionalRecommendedBumpOpts = createConventionalRecommendedBumpOpts + + +/***/ }), + +/***/ 8761: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; + + +const { DEFAULT_COMMIT_TYPES } = __nccwpck_require__(5498) +const { createParserOpts } = __nccwpck_require__(748) +const { createWriterOpts } = __nccwpck_require__(4256) +const { createConventionalChangelogOpts } = __nccwpck_require__(8283) +const { createConventionalRecommendedBumpOpts } = __nccwpck_require__(2287) + +async function createPreset (config) { + const parserOpts = createParserOpts(config) + const writerOpts = await createWriterOpts(config) + const recommendedBumpOpts = createConventionalRecommendedBumpOpts(config, parserOpts) + const conventionalChangelog = createConventionalChangelogOpts(parserOpts, writerOpts) + + return { + gitRawCommitsOpts: { + ignore: config?.ignoreCommits, + noMerges: null + }, + parserOpts, + writerOpts, + recommendedBumpOpts, + conventionalChangelog + } +} + +module.exports = createPreset + +module.exports.DEFAULT_COMMIT_TYPES = DEFAULT_COMMIT_TYPES + + +/***/ }), + +/***/ 748: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; + + +const { breakingHeaderPattern } = __nccwpck_require__(4672) + +function createParserOpts (config) { + return { + headerPattern: /^(\w*)(?:\((.*)\))?!?: (.*)$/, + breakingHeaderPattern, + headerCorrespondence: [ + 'type', + 'scope', + 'subject' + ], + noteKeywords: ['BREAKING CHANGE', 'BREAKING-CHANGE'], + revertPattern: /^(?:Revert|revert:)\s"?([\s\S]+?)"?\s*This reverts commit (\w*)\./i, + revertCorrespondence: ['header', 'hash'], + issuePrefixes: config?.issuePrefixes || ['#'] + } +} + +module.exports.createParserOpts = createParserOpts + + +/***/ }), + +/***/ 4672: +/***/ ((module) => { + +const breakingHeaderPattern = /^(\w*)(?:\((.*)\))?!: (.*)$/ + +module.exports.breakingHeaderPattern = breakingHeaderPattern + +function addBangNotes (commit) { + const match = commit.header.match(breakingHeaderPattern) + if (match && commit.notes.length === 0) { + const noteText = match[3] // the description of the change. + commit.notes.push({ + text: noteText + }) + } +} + +module.exports.addBangNotes = addBangNotes + + +/***/ }), + +/***/ 4256: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; + + +const compareFunc = __nccwpck_require__(4623) +const { readFile } = (__nccwpck_require__(7147).promises) +const { resolve } = __nccwpck_require__(1017) +const { DEFAULT_COMMIT_TYPES } = __nccwpck_require__(5498) +const { addBangNotes } = __nccwpck_require__(4672) + +const releaseAsRegex = /release-as:\s*\w*@?([0-9]+\.[0-9]+\.[0-9a-z]+(-[0-9a-z.]+)?)\s*/i +/** + * Handlebar partials for various property substitutions based on commit context. + */ +const owner = '{{#if this.owner}}{{~this.owner}}{{else}}{{~@root.owner}}{{/if}}' +const host = '{{~@root.host}}' +const repository = '{{#if this.repository}}{{~this.repository}}{{else}}{{~@root.repository}}{{/if}}' + +async function createWriterOpts (config) { + const finalConfig = { + types: DEFAULT_COMMIT_TYPES, + issueUrlFormat: '{{host}}/{{owner}}/{{repository}}/issues/{{id}}', + commitUrlFormat: '{{host}}/{{owner}}/{{repository}}/commit/{{hash}}', + compareUrlFormat: '{{host}}/{{owner}}/{{repository}}/compare/{{previousTag}}...{{currentTag}}', + userUrlFormat: '{{host}}/{{user}}', + issuePrefixes: ['#'], + ...config + } + const commitUrlFormat = expandTemplate(finalConfig.commitUrlFormat, { + host, + owner, + repository + }) + const compareUrlFormat = expandTemplate(finalConfig.compareUrlFormat, { + host, + owner, + repository + }) + const issueUrlFormat = expandTemplate(finalConfig.issueUrlFormat, { + host, + owner, + repository, + id: '{{this.issue}}', + prefix: '{{this.prefix}}' + }) + + const [ + template, + header, + commit, + footer + ] = await Promise.all([ + readFile(__nccwpck_require__.ab + "template1.hbs", 'utf-8'), + readFile(__nccwpck_require__.ab + "header1.hbs", 'utf-8'), + readFile(__nccwpck_require__.ab + "commit1.hbs", 'utf-8'), + readFile(__nccwpck_require__.ab + "footer1.hbs", 'utf-8') + ]) + const writerOpts = getWriterOpts(finalConfig) + + writerOpts.mainTemplate = template + writerOpts.headerPartial = header + .replace(/{{compareUrlFormat}}/g, compareUrlFormat) + writerOpts.commitPartial = commit + .replace(/{{commitUrlFormat}}/g, commitUrlFormat) + .replace(/{{issueUrlFormat}}/g, issueUrlFormat) + writerOpts.footerPartial = footer + + return writerOpts +} + +module.exports.createWriterOpts = createWriterOpts + +function getWriterOpts (config) { + const commitGroupOrder = config.types.flatMap(t => t.section).filter(t => t) + + return { + transform: (commit, context) => { + let discard = true + const issues = [] + const entry = findTypeEntry(config.types, commit) + + // adds additional breaking change notes + // for the special case, test(system)!: hello world, where there is + // a '!' but no 'BREAKING CHANGE' in body: + addBangNotes(commit) + + // Add an entry in the CHANGELOG if special Release-As footer + // is used: + if ((commit.footer && releaseAsRegex.test(commit.footer)) || + (commit.body && releaseAsRegex.test(commit.body))) { + discard = false + } + + commit.notes.forEach(note => { + note.title = 'BREAKING CHANGES' + discard = false + }) + + // breaking changes attached to any type are still displayed. + if (discard && (entry === undefined || + entry.hidden)) return + + if (entry) commit.type = entry.section + + if (commit.scope === '*') { + commit.scope = '' + } + + if (typeof commit.hash === 'string') { + commit.shortHash = commit.hash.substring(0, 7) + } + + if (typeof commit.subject === 'string') { + // Issue URLs. + config.issuePrefixes.join('|') + const issueRegEx = '(' + config.issuePrefixes.join('|') + ')' + '([a-z0-9]+)' + const re = new RegExp(issueRegEx, 'g') + + commit.subject = commit.subject.replace(re, (_, prefix, issue) => { + issues.push(prefix + issue) + const url = expandTemplate(config.issueUrlFormat, { + host: context.host, + owner: context.owner, + repository: context.repository, + id: issue, + prefix + }) + return `[${prefix}${issue}](${url})` + }) + // User URLs. + commit.subject = commit.subject.replace(/\B@([a-z0-9](?:-?[a-z0-9/]){0,38})/g, (_, user) => { + // TODO: investigate why this code exists. + if (user.includes('/')) { + return `@${user}` + } + + const usernameUrl = expandTemplate(config.userUrlFormat, { + host: context.host, + owner: context.owner, + repository: context.repository, + user + }) + + return `[@${user}](${usernameUrl})` + }) + } + + // remove references that already appear in the subject + commit.references = commit.references.filter(reference => { + if (issues.indexOf(reference.prefix + reference.issue) === -1) { + return true + } + + return false + }) + + return commit + }, + groupBy: 'type', + // the groupings of commit messages, e.g., Features vs., Bug Fixes, are + // sorted based on their probable importance: + commitGroupsSort: (a, b) => { + const gRankA = commitGroupOrder.indexOf(a.title) + const gRankB = commitGroupOrder.indexOf(b.title) + return gRankA - gRankB + }, + commitsSort: ['scope', 'subject'], + noteGroupsSort: 'title', + notesSort: compareFunc + } +} + +function findTypeEntry (types, commit) { + const typeKey = (commit.revert ? 'revert' : (commit.type || '')).toLowerCase() + return types.find((entry) => { + if (entry.type !== typeKey) { + return false + } + if (entry.scope && entry.scope !== commit.scope) { + return false + } + return true + }) +} + +// expand on the simple mustache-style templates supported in +// configuration (we may eventually want to use handlebars for this). +function expandTemplate (template, context) { + let expanded = template + Object.keys(context).forEach(key => { + expanded = expanded.replace(new RegExp(`{{${key}}}`, 'g'), context[key]) + }) + return expanded +} + + /***/ }), /***/ 3064: @@ -6353,10 +6737,10 @@ async function conventionalChangelogWriterInit (context, options) { commitPartial, footerPartial ] = await Promise.all([ - readFile(__nccwpck_require__.ab + "template1.hbs", 'utf-8'), - readFile(__nccwpck_require__.ab + "header1.hbs", 'utf-8'), - readFile(__nccwpck_require__.ab + "commit1.hbs", 'utf-8'), - readFile(__nccwpck_require__.ab + "footer1.hbs", 'utf-8') + readFile(__nccwpck_require__.ab + "template2.hbs", 'utf-8'), + readFile(__nccwpck_require__.ab + "header2.hbs", 'utf-8'), + readFile(__nccwpck_require__.ab + "commit2.hbs", 'utf-8'), + readFile(__nccwpck_require__.ab + "footer2.hbs", 'utf-8') ]) options = { @@ -23643,11 +24027,14 @@ module.exports = new (class Git { * Skips loading of the "angular" preset as that one is compiled with this action */ module.exports.loadPreset = async(preset) => { - if (preset === 'angular') { - return null - } + switch (preset) { + case 'angular': + case 'conventionalcommits': + return null - return preset + default: + return preset + } } /** @@ -23659,11 +24046,16 @@ module.exports.loadPresetConfig = async(preset, providedConfig = {}) => { return providedConfig } - if (preset === 'angular') { - return await __nccwpck_require__(8143)() - } + switch (preset) { + case 'angular': + return await __nccwpck_require__(8143)() - return {} + case 'conventionalcommits': + return await __nccwpck_require__(8761)() + + default: + return {} + } } diff --git a/dist/template1.hbs b/dist/template1.hbs index 2c1349a6..3b194f06 100644 --- a/dist/template1.hbs +++ b/dist/template1.hbs @@ -1,11 +1,23 @@ {{> header}} -{{#each commitGroups}} -{{#each commits}} -{{> commit root=@root}} +{{#if noteGroups}} +{{#each noteGroups}} + +### ⚠ {{title}} + +{{#each notes}} +* {{#if commit.scope}}**{{commit.scope}}:** {{/if}}{{text}} {{/each}} {{/each}} +{{/if}} +{{#each commitGroups}} -{{> footer}} +{{#if title}} +### {{title}} +{{/if}} +{{#each commits}} +{{> commit root=@root}} +{{/each}} +{{/each}} diff --git a/dist/template2.hbs b/dist/template2.hbs new file mode 100644 index 00000000..2c1349a6 --- /dev/null +++ b/dist/template2.hbs @@ -0,0 +1,11 @@ +{{> header}} + +{{#each commitGroups}} +{{#each commits}} +{{> commit root=@root}} +{{/each}} +{{/each}} + +{{> footer}} + + diff --git a/package-lock.json b/package-lock.json index a5514b46..04b55d9d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "conventional-changelog-action", - "version": "4.1.1", + "version": "5.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "conventional-changelog-action", - "version": "4.1.1", + "version": "5.0.0", "license": "MIT", "dependencies": { "@actions/core": "^1.10.1", @@ -15,6 +15,7 @@ "@vercel/ncc": "^0.38.1", "conventional-changelog": "^5.1.0", "conventional-changelog-angular": "^7.0.0", + "conventional-changelog-conventionalcommits": "^7.0.2", "conventional-recommended-bump": "^9.0.0", "git-semver-tags": "7.0.1", "object-path": "^0.11.8", diff --git a/package.json b/package.json index 987b944f..76fc0f8a 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "@vercel/ncc": "^0.38.1", "conventional-changelog": "^5.1.0", "conventional-changelog-angular": "^7.0.0", + "conventional-changelog-conventionalcommits": "^7.0.2", "conventional-recommended-bump": "^9.0.0", "git-semver-tags": "7.0.1", "object-path": "^0.11.8", diff --git a/src/helpers/load-preset.js b/src/helpers/load-preset.js index 70fcd639..c7ff2552 100644 --- a/src/helpers/load-preset.js +++ b/src/helpers/load-preset.js @@ -2,11 +2,14 @@ * Skips loading of the "angular" preset as that one is compiled with this action */ module.exports.loadPreset = async(preset) => { - if (preset === 'angular') { - return null - } + switch (preset) { + case 'angular': + case 'conventionalcommits': + return null - return preset + default: + return preset + } } /** @@ -18,9 +21,14 @@ module.exports.loadPresetConfig = async(preset, providedConfig = {}) => { return providedConfig } - if (preset === 'angular') { - return await require('conventional-changelog-angular')() - } + switch (preset) { + case 'angular': + return await require('conventional-changelog-angular')() - return {} + case 'conventionalcommits': + return await require('conventional-changelog-conventionalcommits')() + + default: + return {} + } }