@@ -9,10 +9,20 @@ const conventionalChangelog = require('conventional-changelog');
const changelogCompare = require ( 'conventional-changelog-writer/lib/util' ) ;
const merge2 = require ( 'merge2' ) ;
/**
* Maps a commit note to a string that will be used to match notes of the
* given type in commit messages.
*/
const enum CommitNote {
Deprecation = 'DEPRECATED' ,
BreakingChange = 'BREAKING CHANGE' ,
}
/** Interface that describes a package in the changelog. */
interface ChangelogPackage {
commits : any [ ] ;
breakingChanges : any [ ] ;
deprecations : any [ ] ;
}
/** Hardcoded order of packages shown in the changelog. */
@@ -41,6 +51,7 @@ export async function promptAndGenerateChangelog(changelogPath: string) {
* @param releaseName Name of the release that should show up in the changelog.
*/
export async function prependChangelogFromLatestTag ( changelogPath : string , releaseName : string ) {
const angularPresetWriterOptions = await require ( 'conventional-changelog-angular/writer-opts' ) ;
const outputStream : Readable = conventionalChangelog (
/* core options */ { preset : 'angular' } ,
/* context options */ { title : releaseName } ,
@@ -50,8 +61,9 @@ export async function prependChangelogFromLatestTag(changelogPath: string, relea
// name from the commit message.
headerPattern : /^ ( \w * ) (?: \( (?: ( [ ^/] + ) \/ ) ?( .* ) \) ) ?: ( .* ) $ / ,
headerCorrespondence : [ 'type' , 'package' , 'scope' , 'subject' ] ,
noteKeywords : [ CommitNote . BreakingChange , CommitNote . Deprecation ] ,
} ,
/* writer options */ createChangelogWriterOptions ( changelogPath ) ) ;
/* writer options */ createChangelogWriterOptions ( changelogPath , angularPresetWriterOptions ) ) ;
// Stream for reading the existing changelog. This is necessary because we want to
// actually prepend the new changelog to the existing one.
@@ -93,7 +105,7 @@ export async function promptChangelogReleaseName(): Promise<string> {
* build the changelog from last major version to master's HEAD when a new major version is being
* published from the "master" branch.
*/
function createChangelogWriterOptions ( changelogPath : string ) {
function createChangelogWriterOptions ( changelogPath : string , presetWriterOptions : any ) {
const existingChangelogContent = readFileSync ( changelogPath , 'utf8' ) ;
const commitSortFunction = changelogCompare . functionify ( [ 'type' , 'scope' , 'subject' ] ) ;
const allPackages = [ ...orderedChangelogPackages , ...excludedChangelogPackages ] ;
@@ -105,6 +117,14 @@ function createChangelogWriterOptions(changelogPath: string) {
mainTemplate : readFileSync ( join ( __dirname , 'changelog-root-template.hbs' ) , 'utf8' ) ,
commitPartial : readFileSync ( join ( __dirname , 'changelog-commit-template.hbs' ) , 'utf8' ) ,
// Overwrites the conventional-changelog-angular preset transform function. This is necessary
// because the Angular preset changes every commit note to a breaking change note. Since we
// have a custom note type for deprecations, we need to keep track of the original type.
transform : ( commit , context ) => {
commit . notes . forEach ( n => n . type = n . title ) ;
return presetWriterOptions . transform ( commit , context ) ;
} ,
// Specify a writer option that can be used to modify the content of a new changelog section.
// See: conventional-changelog/tree/master/packages/conventional-changelog-writer
finalizeContext : ( context : any ) => {
@@ -139,11 +159,21 @@ function createChangelogWriterOptions(changelogPath: string) {
const type = getTypeOfCommitGroupDescription ( group . title ) ;
if ( !packageGroups [ packageName ] ) {
packageGroups [ packageName ] = { commits : [ ] , breakingChanges : [ ] } ;
packageGroups [ packageName ] = { commits : [ ] , breakingChanges : [ ] , deprecations : [ ] } ;
}
const packageGroup = packageGroups [ packageName ] ;
packageGroup . breakingChanges . push ( ...commit . notes ) ;
// Collect all notes of the commit. Either breaking change or deprecation notes.
commit . notes . forEach ( n => {
if ( n . type === CommitNote . Deprecation ) {
packageGroup . deprecations . push ( n ) ;
} else if ( n . type === CommitNote . BreakingChange ) {
packageGroup . breakingChanges . push ( n ) ;
} else {
throw Error ( `Found commit note that is not known: ${ JSON . stringify ( n , null , 2 ) } ` ) ;
}
} ) ;
packageGroup . commits . push ( { ...commit , type} ) ;
} ) ;
} ) ;
@@ -159,6 +189,7 @@ function createChangelogWriterOptions(changelogPath: string) {
title : pkgName ,
commits : packageGroup . commits . sort ( commitSortFunction ) ,
breakingChanges : packageGroup . breakingChanges ,
deprecations : packageGroup . deprecations ,
} ;
} ) ;