From c813d1fdc85e14f08db68f6b7837cf5b36877b24 Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Tue, 14 Apr 2020 15:46:21 +0200 Subject: [PATCH 01/33] A single commit can provide "fake" commits for inserting a few entries in the changelog. --- .../release-tools/utils/getnewreleasetype.js | 13 +++ .../transform-commit-utils.js | 4 +- .../transformcommitforsubrepositoryfactory.js | 99 ++++++++++++++++++- 3 files changed, 112 insertions(+), 4 deletions(-) diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/getnewreleasetype.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/getnewreleasetype.js index db67ecc85..f01475f85 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/utils/getnewreleasetype.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/utils/getnewreleasetype.js @@ -5,14 +5,18 @@ 'use strict'; +const through = require( 'through2' ); const conventionalCommitsParser = require( 'conventional-commits-parser' ); const conventionalCommitsFilter = require( 'conventional-commits-filter' ); const gitRawCommits = require( 'git-raw-commits' ); const concat = require( 'concat-stream' ); +const { stream } = require( '@ckeditor/ckeditor5-dev-utils' ); const parserOptions = require( './transform-commit/parser-options' ); const { availableCommitTypes } = require( './transform-commit/transform-commit-utils' ); const getPackageJson = require( './getpackagejson' ); +const REGEXP = /(?:Feature|Other|Fix) \([\w\-, ]+?\):/g; + /** * Returns a type (major, minor, patch) of the next release based on commits. * @@ -54,6 +58,15 @@ module.exports = function getNewReleaseType( transformCommit, options = {} ) { .pipe( concat( data => { const commits = conventionalCommitsFilter( data ) .map( commit => transformCommit( commit, context ) ) + .reduce( ( allCommits, commit ) => { + if ( Array.isArray( commit ) ) { + allCommits.push( ...commit ); + } else { + allCommits.push( commit ); + } + + return allCommits; + }, [] ) .filter( commit => commit ); return resolve( { diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transform-commit-utils.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transform-commit-utils.js index 888080a97..a458bfed2 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transform-commit-utils.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transform-commit-utils.js @@ -14,8 +14,8 @@ const transformCommitUtils = { */ availableCommitTypes: new Map( [ [ 'Fix', true ], - [ 'Fixes', true ], - [ 'Fixed', true ], + [ 'Fixes', true ], // TODO: Remove. + [ 'Fixed', true ], // TODO: Remove. [ 'Feature', true ], [ 'Other', true ], [ 'Code style', false ], diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transformcommitforsubrepositoryfactory.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transformcommitforsubrepositoryfactory.js index 42f0b1592..3d9d32483 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transformcommitforsubrepositoryfactory.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transformcommitforsubrepositoryfactory.js @@ -7,6 +7,8 @@ const utils = require( './transform-commit-utils' ); +const MULTI_ENTRIES_COMMIT_REGEXP = /(?:Feature|Other|Fix)(?: \([\w\-, ]+?\))?:/g; + /** * Factory function. * @@ -30,8 +32,21 @@ const utils = require( './transform-commit-utils' ); */ module.exports = function transformCommitForSubRepositoryFactory( options = {} ) { /** + * If returned an instance of the Array, it means that single commit contains more than one entry for the changelog. + * + * E.g. for the commit below: + * + * Feature: Introduced the `Editor` component. See #123. + * + * Additional description. + * + * Fix: The commit also fixes... + * + * the function will return an array with two commits. The first one is the real commit, the second one is a fake commit + * but its description will be inserted to the changelog. + * * @param {Commit} rawCommit - * @returns {Commit|undefined} + * @returns {Commit|Array.|undefined} */ return function transformCommitForSubRepository( rawCommit ) { // Let's clone the commit. We don't want to modify the reference. @@ -41,6 +56,11 @@ module.exports = function transformCommitForSubRepositoryFactory( options = {} ) notes: rawCommit.notes.map( note => Object.assign( {}, note ) ) } ); + const parsedType = getTypeAndScope( commit.rawType ); + + commit.rawType = parsedType.rawType; + commit.scope = parsedType.scope; + // Whether the commit will be printed in the changelog. const isCommitIncluded = utils.availableCommitTypes.get( commit.rawType ); @@ -126,7 +146,56 @@ module.exports = function transformCommitForSubRepositoryFactory( options = {} ) commit.repositoryUrl = utils.getRepositoryUrl(); - return commit; + if ( !commit.body ) { + return commit; + } + + const commitEntries = commit.body.match( MULTI_ENTRIES_COMMIT_REGEXP ); + + if ( !commitEntries.length ) { + return commit; + } + + // Single commit contains a few entries that should be inserted to the changelog. + // All of those entries are defined in the array. + // Additional commits/entries will be called as "fake commits". + const separatedCommit = [ commit ]; + + // Descriptions of additional entries. + const parts = commit.body.split( MULTI_ENTRIES_COMMIT_REGEXP ); + + // If the descriptions array contains more entries than fake commit entries, + // it means that the first element in descriptions array describes the main (real) commit. + if ( parts.length > commitEntries.length ) { + commit.body = escapeNewLines( parts.shift() ); + } else { + commit.body = null; + } + + // For each fake commit, copy hash and repository of the parent. + for ( let i = 0; i < parts.length; ++i ) { + const newCommit = { + hash: commit.hash, + repositoryUrl: commit.repositoryUrl, + notes: [] + }; + + const details = getTypeAndScope( commitEntries[ i ].replace( /:$/, '' ) ); + + newCommit.rawType = details.rawType; + newCommit.scope = details.scope; + newCommit.type = utils.getCommitType( newCommit.rawType ); + + const commitDescription = parts[ i ]; + const subject = commitDescription.match( /^(.*)$/m )[ 0 ]; + + newCommit.subject = subject.trim(); + newCommit.body = escapeNewLines( commitDescription.replace( subject, '' ) ); + + separatedCommit.push( newCommit ); + } + + return separatedCommit; }; function makeLinks( comment ) { @@ -187,6 +256,32 @@ module.exports = function transformCommitForSubRepositoryFactory( options = {} ) return 0; } ); } + + function getTypeAndScope( type ) { + if ( !type ) { + return {}; + } + + const parts = type.split( ' (' ); + const data = { + rawType: parts[ 0 ], + scope: null + }; + + if ( parts[ 1 ] ) { + data.scope = parts[ 1 ].replace( /^\(|\)$/g, '' ) + .split( ',' ) + .map( p => p.trim() ) + .filter( p => p ); + } + + return data; + } + + function escapeNewLines( message ) { + // Accept spaces before a sentence because they are ready to be rendered in the changelog template. + return message.replace(/^\n+|\s+$/g, ''); + } }; /** From c419305e50ba088d7adcd28a4a971f8a4e892961 Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Sun, 10 May 2020 14:57:42 +0200 Subject: [PATCH 02/33] Breakpoint. --- .../generatechangelogforsubrepositories.js | 382 ++++++++++++------ .../lib/release-tools/templates/commit.hbs | 8 +- .../lib/release-tools/utils/cli.js | 4 +- .../lib/release-tools/utils/displaycommits.js | 3 +- .../lib/release-tools/utils/getcommits.js | 69 ++++ .../getchangedfilesforcommit.js | 5 +- .../utils/transform-commit/parser-options.js | 2 +- .../transformcommitforsubrepositoryfactory.js | 114 +++--- 8 files changed, 398 insertions(+), 189 deletions(-) create mode 100644 packages/ckeditor5-dev-env/lib/release-tools/utils/getcommits.js diff --git a/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogforsubrepositories.js b/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogforsubrepositories.js index 027589e20..876756124 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogforsubrepositories.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogforsubrepositories.js @@ -5,7 +5,11 @@ 'use strict'; -const { logger } = require( '@ckeditor/ckeditor5-dev-utils' ); +const path = require( 'path' ); +const fs = require( 'fs' ); +const { Readable } = require( 'stream' ); + +const { stream, logger } = require( '@ckeditor/ckeditor5-dev-utils' ); const chalk = require( 'chalk' ); const semver = require( 'semver' ); const cli = require( '../utils/cli' ); @@ -20,29 +24,49 @@ const getSubRepositoriesPaths = require( '../utils/getsubrepositoriespaths' ); const transformCommitForSubRepositoryFactory = require( '../utils/transform-commit/transformcommitforsubrepositoryfactory' ); const versionUtils = require( '../utils/versions' ); +const getCommits = require( '../utils/getcommits' ); + +const { typesOrder } = require( '../utils/transform-commit/transform-commit-utils' ); +const conventionalChangelogWriter = require( 'conventional-changelog-writer' ); + /** - * Generates the changelog for packages located in multi repositories. + * Generates the changelog for the mono repository. * * @param {Object} options * @param {String} options.cwd Current working directory (packages) from which all paths will be resolved. * @param {String} options.packages Where to look for other packages. - * @param {String} [options.scope] Package names have to match to specified glob pattern. + * @param {Function} options.transformScope A function that returns a URL to a package from a scope of a commit. + * @param {String} [options.scope] Package names have to match to specified glob pattern in order to be processed. * @param {Array.} [options.skipPackages=[]] Name of packages which won't be touched. - * @param {Boolean} [options.skipMainRepository=false] If set on true, package found in "cwd" will be skipped. + * @param {String} [options.from] A commit or tag name that will be the first param of the range of commits to collect. * @returns {Promise.} */ module.exports = function generateChangelogForSubRepositories( options ) { const log = logger(); const cwd = process.cwd(); + const pkgJson = getPackageJson(); + + const transformCommit = transformCommitForSubRepositoryFactory( { + useExplicitBreakingChangeGroups: true + } ); const pathsCollection = getSubRepositoriesPaths( { cwd: options.cwd, packages: options.packages, scope: options.scope || null, skipPackages: options.skipPackages || [], - skipMainRepository: options.skipMainRepository + skipMainRepository: true } ); + // The main repository should be at the end of the list. + pathsCollection.skipped.delete( options.cwd ); + pathsCollection.matched.add( options.cwd ); + + logProcess( 'Collecting all commits since the last release...' ); + + // Collection of all entries (real commits + additional "fake" commits extracted from descriptions). + let allCommits; + // Whether the next release will be bumped as "major" release. // It depends on commits. If there is any of them that contains a "MAJOR BREAKING CHANGES" note, // all packages must be released as a major change. @@ -51,90 +75,130 @@ module.exports = function generateChangelogForSubRepositories( options ) { // If the next release will be the major bump, this variable will contain next version for all packages. let nextVersion = null; - const generatedChangelogsMap = new Map(); + // Packages which during typing the new versions, the user proposed "skip" version. const skippedChangelogs = new Set(); - return collectPackagesCommits() - .then( packagesCommit => confirmMajorVersionBump( packagesCommit ) ) + // A map: packages and their new versions. + const packagesVersion = new Map(); + + const commitOptions = { + from: options.from ? options.from : 'v' + pkgJson.version + }; + + return getCommits( transformCommit, commitOptions ) + .then( commits => { + allCommits = commits; + + logInfo( `Found ${ commits.length } entries to parse.`, { indentLevel: 1 } ); + } ) + .then( () => confirmMajorVersionBump() ) .then( () => typeNewProposalVersionForAllPackages() ) - .then( () => generateChangelogs() ) - .then( () => generateInternalChangelogs() ) + .then( () => confirmVersionForPackages() ) + .then( () => findPackagesWithInternalBumps() ) .then( () => { - logProcess( 'Summary' ); + logProcess( 'Generating the changelog' ); - process.chdir( cwd ); + const commitStream = new Readable( { + objectMode: true + } ); + commitStream._read = function() {}; - // An empty line increases the readability. - console.log( '' ); + const version = packagesVersion.get( pkgJson.name ); - displaySkippedPackages( new Set( [ - ...pathsCollection.skipped, - ...skippedChangelogs - ].sort() ) ); + const writerContext = { + version, + repoUrl: pkgJson.repository.url.replace( /\.git$/, '' ), + currentTag: 'v' + version, + previousTag: 'v' + pkgJson.version, + isPatch: semver.diff( version, pkgJson.version ) === 'patch', + commit: 'commit' + }; - // An empty line between two lists increases the readability. - console.log( '' ); + const writerOptions = { + groupBy: 'type', + commitGroupsSort( a, b ) { + return typesOrder[ a.title ] - typesOrder[ b.title ]; + }, + commitsSort: [ 'scope' ], + noteGroupsSort( a, b ) { + return typesOrder[ a.title ] - typesOrder[ b.title ]; + }, + notesSort: require( 'compare-func' ), + mainTemplate: getTemplateFile( 'template.hbs' ), + headerPartial: getTemplateFile( 'header.hbs' ), + commitPartial: getTemplateFile( 'commit.hbs' ), + footerPartial: getTemplateFile( 'footer.hbs' ), + transform: { + // We do not allow modifying the hash value by the generator itself. + hash: hash => hash + } + }; - displayGeneratedChangelogs( generatedChangelogsMap ); + const publicCommits = [ ...allCommits ].filter( commit => commit.isPublicCommit ) + .map( commit => { + commit.scope = commit.scope.map( name => { + return `[${ name }](${ options.transformScope( name ) })`; + } ); - return { - wasMajorRelease: willBeMajorBump, - version: nextVersion - }; - } ); + return commit; + } ); - /** - * Creates a collection where: - * - keys are names of the packages, - * - their values are collections of the commits. - * - * @returns {Promise.>>} - */ - function collectPackagesCommits() { - logProcess( 'Collecting commits for packages since the last release...' ); + for ( const commit of publicCommits ) { + commitStream.push( commit ); + } - const packagesCommit = new Map(); - const transformCommitFunction = transformCommitForSubRepositoryFactory( { - useExplicitBreakingChangeGroups: true - } ); + commitStream.push( null ); - return executeOnPackages( pathsCollection.matched, repositoryPath => { - process.chdir( repositoryPath ); + return new Promise( ( resolve, reject ) => { + commitStream + .pipe( conventionalChangelogWriter( writerContext, writerOptions ) ) + .pipe( stream.noop( changes => { + console.log( changes.toString() ); - const packageJson = getPackageJson(); + resolve(); + } ) ) + .on( 'error', reject ); + } ); + } ) + .then( () => { + logProcess( 'Summary' ); - let tagName = versionUtils.getLastFromChangelog(); + process.chdir( cwd ); - if ( tagName ) { - tagName = 'v' + tagName; - } + // An empty line increases the readability. + log.info( '' ); - return getNewReleaseType( transformCommitFunction, { tagName } ) - .then( result => { - packagesCommit.set( packageJson.name, new Set( result.commits ) ); - } ); - } ).then( () => packagesCommit ); - } + // displaySkippedPackages( new Set( [ + // ...pathsCollection.skipped, + // ...skippedChangelogs + // ].sort() ) ); + + // An empty line between two lists increases the readability. + log.info( '' ); + + displayGeneratedChangelogs( packagesVersion ); + } ) + .catch( err => { + console.log( err ); + } ); /** * Asks the user whether found "MAJOR BREAKING CHANGES" commits are true. * - * @returns {Promise.} + * @returns {Promise} */ - function confirmMajorVersionBump( packagesCommit ) { + function confirmMajorVersionBump() { logProcess( 'Looking for "MAJOR BREAKING CHANGES" commits...' ); let hasMajorBreakingChanges = false; - for ( const [ packageName, commits ] of packagesCommit ) { - const majorBreakingChangesCommits = filterMajorBreakingChangesCommits( commits ); + const majorBreakingChangesCommits = filterMajorBreakingChangesCommits( allCommits ); - if ( majorBreakingChangesCommits.size ) { - hasMajorBreakingChanges = true; + if ( majorBreakingChangesCommits.size ) { + hasMajorBreakingChanges = true; - log.info( `\n${ ' '.repeat( cli.INDENT_SIZE ) }${ chalk.bold( `Commits in "${ chalk.underline( packageName ) }"...` ) }` ); - displayCommits( majorBreakingChangesCommits, { attachLinkToCommit: true, indentLevel: 2 } ); - } + log.info( `\n${ ' '.repeat( cli.INDENT_SIZE ) }Found ${ chalk.bold( 'MAJOR BREAKING CHANGES') }:` ); + displayCommits( majorBreakingChangesCommits, { attachLinkToCommit: true, indentLevel: 2 } ); } if ( !hasMajorBreakingChanges ) { @@ -152,9 +216,9 @@ module.exports = function generateChangelogForSubRepositories( options ) { /** * If the next release will be the major release, the user needs to provide the version which will be used - * a the proposal version for all packages. + * as the proposal version for all packages. * - * @returns {Promise.} + * @returns {Promise} */ function typeNewProposalVersionForAllPackages() { if ( !willBeMajorBump ) { @@ -174,9 +238,6 @@ module.exports = function generateChangelogForSubRepositories( options ) { return currentHighest; }, [ null, '0.0.0' ] ); - // An empty line increases the readability. - console.log( '' ); - return cli.provideNewMajorReleaseVersion( highestVersion, packageHighestVersion, { indentLevel: 1 } ) .then( version => { nextVersion = version; @@ -184,103 +245,96 @@ module.exports = function generateChangelogForSubRepositories( options ) { } /** - * Generates changelogs for packages. + * Asks the user about new versions for all packages. * * @returns {Promise} */ - function generateChangelogs() { - logProcess( 'Generating changelogs for packages...' ); + function confirmVersionForPackages() { + logProcess( 'Preparing new version for all packages...' ); - return executeOnPackages( pathsCollection.matched, repositoryPath => { - process.chdir( repositoryPath ); + let promise = Promise.resolve(); - const changelogOptions = { - newVersion: nextVersion, - disableMajorBump: !willBeMajorBump, - indentLevel: 1, - useExplicitBreakingChangeGroups: true - }; + for ( const packagePath of pathsCollection.matched ) { + promise = promise.then( () => { + const pkgJson = getPackageJson( packagePath ); - return generateChangelogForSinglePackage( changelogOptions ) - .then( newVersionInChangelog => { - if ( newVersionInChangelog ) { - generatedChangelogsMap.set( getPackageJson( repositoryPath ).name, newVersionInChangelog ); - } else { - skippedChangelogs.add( repositoryPath ); - } - } ) - .catch( err => { - log.error( err ); - } ); - } ); + logInfo( `Processing "${ chalk.underline( pkgJson.name ) }"...`, { indentLevel: 1, startWithNewLine: true } ); + + const packageCommits = filterCommitsByPath( packagePath ); + const releaseTypeOrVersion = willBeMajorBump ? nextVersion : getNewVersionType( packageCommits ); + + displayCommits( packageCommits, { indentLevel: 2 } ); + + return cli.provideVersion( pkgJson.version, releaseTypeOrVersion, { indentLevel: 2 } ) + .then( version => { + if ( version === 'skip' ) { + console.log( 'Skipping', packagePath ); + skippedChangelogs.add( packagePath ); + + return Promise.resolve(); + } + + // If the user provided "internal" as a new version, we treat it as a "patch" bump. + if ( version === 'internal' ) { + version = semver.inc( pkgJson.version, 'patch' ); + } + + packagesVersion.set( pkgJson.name, version ); + } ); + } ); + } + + return promise; } /** - * Generates changelogs for packages that were skipped or didn't have any committed changes. + * Finds packages that were skipped or didn't have any committed changes. * - * For such packages we are generating "internal" release that increases the "patch" version. + * For such packages we want to bump the "patch" version. * Unless, there should be a major bump. * * @returns {Promise} */ - function generateInternalChangelogs() { + function findPackagesWithInternalBumps() { logProcess( 'Checking whether dependencies of skipped packages have changed...' ); - const internalChangelogsPaths = new Map(); - const newVersion = willBeMajorBump ? nextVersion : 'patch'; let clearRun = false; while ( !clearRun ) { clearRun = true; for ( const packagePath of skippedChangelogs ) { - const packageJson = getPackageJson( packagePath ); + const pkgJson = getPackageJson( packagePath ); // Check whether the dependencies of the current processing package will be released. - const willUpdateDependencies = Object.keys( packageJson.dependencies || {} ) - .some( dependencyName => { - return generatedChangelogsMap.has( dependencyName ) || internalChangelogsPaths.has( dependencyName ); - } ); + const willUpdateDependencies = Object.keys( pkgJson.dependencies || {} ) + .some( dependencyName => packagesVersion.has( dependencyName ) ); // If so, bump the version for current package and release it too. // The bump can be specified as `major` or `patch`. It depends whether we had the "MAJOR BREAKING CHANGES" commit. if ( willUpdateDependencies ) { - internalChangelogsPaths.set( packageJson.name, packagePath ); + const version = willBeMajorBump ? nextVersion : semver.inc( pkgJson.version, 'patch' ); + + packagesVersion.set( pkgJson.name, version ); skippedChangelogs.delete( packagePath ); clearRun = false; } } } - - return executeOnPackages( internalChangelogsPaths.values(), repositoryPath => { - process.chdir( repositoryPath ); - - const changelogOptions = { - newVersion, - isInternalRelease: true, - indentLevel: 1, - useExplicitBreakingChangeGroups: true - }; - - return generateChangelogForSinglePackage( changelogOptions ) - .then( newVersion => { - generatedChangelogsMap.set( getPackageJson( repositoryPath ).name, newVersion ); - } ) - .catch( err => { - log.error( err ); - } ); - } ); } /** * Finds commits that contain a "MAJOR BREAKING CHANGES" note. * - * @param {Set.} commits * @returns {Set.} */ - function filterMajorBreakingChangesCommits( commits ) { - const breakingChangesCommits = [ ...commits ] + function filterMajorBreakingChangesCommits() { + const breakingChangesCommits = allCommits .filter( commit => { + if ( !commit.isPublicCommit ) { + return false; + } + for ( const note of commit.notes ) { if ( note.title === 'MAJOR BREAKING CHANGES' ) { return true; @@ -293,9 +347,93 @@ module.exports = function generateChangelogForSubRepositories( options ) { return new Set( breakingChangesCommits ); } + /** + * Finds commits that touched the package under `packagePath` directory. + * + * @param {String} packagePath + * @returns {Array.} + */ + function filterCommitsByPath( packagePath ) { + const shortPackagePath = packagePath.replace( options.cwd, '' ) + .replace( new RegExp( `^\\${ path.sep }` ), '' ); + + return allCommits.filter( commit => { + return commit.files.some( file => { + // The main repository. + if ( shortPackagePath === '' ) { + return !file.startsWith( 'packages' ); + } + + return file.startsWith( shortPackagePath ); + } ); + } ); + } + + /** + * Proposes new version based on commits. + * + * @param {Array.} commits + * @returns {String} + */ + function getNewVersionType( commits ) { + // Repository does not have new changes. + if ( !commits.length ) { + return 'skip'; + } + + const publicCommits = commits.filter( commit => commit.isPublicCommit ); + + if ( !publicCommits.length ) { + return 'internal'; + } + + let newFeatures = false; + let minorBreakingChanges = false; + + for ( const commit of publicCommits ) { + for ( const note of commit.notes ) { + if ( note.title === 'MAJOR BREAKING CHANGES' ) { + return 'major'; + } + + if ( note.title === 'MINOR BREAKING CHANGES' ) { + minorBreakingChanges = true; + } + } + + if ( commit.rawType === 'Feature' ) { + newFeatures = true; + } + } + + // Repository has new features or minor breaking changes. + if ( minorBreakingChanges || newFeatures ) { + return 'minor'; + } + + return 'patch'; + } + + /** + * @param {String} file + * @returns {String} + */ + function getTemplateFile( file ) { + return fs.readFileSync( + require.resolve( '@ckeditor/ckeditor5-dev-env/lib/release-tools/templates/' + file ), 'utf-8' + ); + } + function logProcess( message ) { log.info( '\n📍 ' + chalk.cyan( message ) ); } + + function logInfo( message, options = {} ) { + const indentLevel = options.indentLevel || 0; + const startWithNewLine = options.startWithNewLine || false; + + log.info( `${ startWithNewLine ? '\n' : '' }${ ' '.repeat( indentLevel * cli.INDENT_SIZE ) }` + message ); + } }; /** diff --git a/packages/ckeditor5-dev-env/lib/release-tools/templates/commit.hbs b/packages/ckeditor5-dev-env/lib/release-tools/templates/commit.hbs index 6546751e3..680cabc6f 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/templates/commit.hbs +++ b/packages/ckeditor5-dev-env/lib/release-tools/templates/commit.hbs @@ -1,12 +1,8 @@ -* {{#if subject}} - {{~subject}} -{{~else}} - {{~title}} -{{~/if}} +* {{#if scope}}**{{~scope.[0]}}**: {{/if}}{{subject}} {{~#unless @root.skipCommitsLink}} {{~!-- commit link --}} {{#if @root.linkReferences~}} - ([{{hash}}]( + ([commit]( {{~#if @root.repository}} {{~#if @root.host}} {{~@root.host}}/ diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/cli.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/cli.js index 4ec3d8c6d..0cab8b02d 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/utils/cli.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/utils/cli.js @@ -292,7 +292,7 @@ const cli = { }, /** - * Asks a user for a confirmation for removing archives created by `npm pack` command. + * Asks a user for a confirmation for major breaking release. * * @param {Boolean} haveMajorBreakingChangeCommits Whether the answer for the question should be "Yes". * @param {Object} [options={}] @@ -304,7 +304,7 @@ const cli = { const confirmQuestion = { message: [ 'If at least one of those changes is really a major breaking change, this will be a major release.', - 'Should this be a major release?' + 'Should it be the major release?' ].join( ' ' ), type: 'confirm', name: 'confirm', diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/displaycommits.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/displaycommits.js index f601550b0..ece56013a 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/utils/displaycommits.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/utils/displaycommits.js @@ -32,8 +32,9 @@ module.exports = function displayCommits( commits, options = {} ) { for ( const singleCommit of commits ) { const hasCorrectType = utils.availableCommitTypes.has( singleCommit.rawType ); const isCommitIncluded = utils.availableCommitTypes.get( singleCommit.rawType ); + const hash = singleCommit.hash.substring( 0, 7 ); - let logMessage = `${ listIndent }* ${ chalk.yellow( singleCommit.hash ) } "${ utils.truncate( singleCommit.header, 100 ) }" `; + let logMessage = `${ listIndent }* ${ chalk.yellow( hash ) } "${ utils.truncate( singleCommit.header, 100 ) }" `; if ( hasCorrectType && isCommitIncluded ) { logMessage += chalk.green( 'INCLUDED' ); diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/getcommits.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/getcommits.js new file mode 100644 index 000000000..6a8b7a4b2 --- /dev/null +++ b/packages/ckeditor5-dev-env/lib/release-tools/utils/getcommits.js @@ -0,0 +1,69 @@ +/** + * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md. + */ + +'use strict'; + +const conventionalCommitsParser = require( 'conventional-commits-parser' ); +const conventionalCommitsFilter = require( 'conventional-commits-filter' ); +const gitRawCommits = require( 'git-raw-commits' ); +const concat = require( 'concat-stream' ); +const parserOptions = require( './transform-commit/parser-options' ); +const getPackageJson = require( './getpackagejson' ); + +/** + * Returns a promise that resolves an array of commits since the last tag specified as `options.from`. + * + * @param {Function} transformCommit + * @param {Object} options + * @param {String} [options.from] A commit or tag name that will be the first param of the range of commits to collect. + * @returns {Promise.>} + */ +module.exports = function getCommits( transformCommit, options = {} ) { + const gitRawCommitsOpts = { + format: '%B%n-hash-%n%H', + from: options.from, + merges: undefined, + firstParent: true + }; + + const context = { + packageData: getPackageJson() + }; + + return new Promise( ( resolve, reject ) => { + const stream = gitRawCommits( gitRawCommitsOpts ) + .on( 'error', err => { + if ( err.message.match( /'HEAD': unknown/ ) ) { + reject( new Error( 'Given repository is empty.' ) ); + } else if ( err.message.match( new RegExp( `'${ options.tagName }\\.\\.HEAD': unknown` ) ) ) { + reject( new Error( + `Cannot find tag "${ options.tagName }" (the latest version from the changelog) in given repository.` + ) ); + } else { + reject( err ); + } + } ); + + stream.pipe( conventionalCommitsParser( parserOptions ) ) + .pipe( concat( data => { + const commits = conventionalCommitsFilter( data ) + .map( commit => transformCommit( commit, context ) ) + .reduce( ( allCommits, commit ) => { + if ( Array.isArray( commit ) ) { + allCommits.push( ...commit ); + } else { + allCommits.push( commit ); + } + + return allCommits; + }, [] ) + .filter( commit => commit ); + + stream.destroy(); + + return resolve( commits ); + } ) ); + } ); +}; diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/getchangedfilesforcommit.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/getchangedfilesforcommit.js index d64d8f516..81ddb0c99 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/getchangedfilesforcommit.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/getchangedfilesforcommit.js @@ -26,5 +26,8 @@ module.exports = function getChangedFilesForCommit( commitId ) { // other-file2 <-- files from last commit before merge // We need to filter out files from commit before merge. - return changedFiles.split( '\n\n' )[ 0 ].split( '\n' ); + return changedFiles.split( '\n\n' )[ 0 ] + .split( '\n' ) + .map( file => file.trim() ) + .filter( item => item ); }; diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/parser-options.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/parser-options.js index bc13cfc6f..5fef9b122 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/parser-options.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/parser-options.js @@ -19,7 +19,7 @@ module.exports = { 'MINOR BREAKING CHANGE', 'BREAKING CHANGES', // It will be treated as "MAJOR BREAKING CHANGES" 'BREAKING CHANGE', // An alias for "BREAKING CHANGES". - 'NOTE' + 'NOTE' // TODO: Remove. ], revertPattern: /^Revert:\s([\s\S]*?)\s*This reverts commit (\w*)\./, revertCorrespondence: [ 'header', 'hash' ], diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transformcommitforsubrepositoryfactory.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transformcommitforsubrepositoryfactory.js index 3d9d32483..33574c28f 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transformcommitforsubrepositoryfactory.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transformcommitforsubrepositoryfactory.js @@ -6,6 +6,7 @@ 'use strict'; const utils = require( './transform-commit-utils' ); +const getChangedFilesForCommit = require( './getchangedfilesforcommit' ); const MULTI_ENTRIES_COMMIT_REGEXP = /(?:Feature|Other|Fix)(?: \([\w\-, ]+?\))?:/g; @@ -58,11 +59,12 @@ module.exports = function transformCommitForSubRepositoryFactory( options = {} ) const parsedType = getTypeAndScope( commit.rawType ); + commit.files = []; commit.rawType = parsedType.rawType; commit.scope = parsedType.scope; // Whether the commit will be printed in the changelog. - const isCommitIncluded = utils.availableCommitTypes.get( commit.rawType ); + commit.isPublicCommit = utils.availableCommitTypes.get( commit.rawType ) || false; // Our merge commit always contains two lines: // Merge ... @@ -81,70 +83,64 @@ module.exports = function transformCommitForSubRepositoryFactory( options = {} ) return; } - if ( typeof commit.hash === 'string' ) { - commit.hash = commit.hash.substring( 0, 7 ); - } - - // It's used only for displaying the commit. Changelog generator will filter out the invalid entries. - if ( !isCommitIncluded ) { - return options.returnInvalidCommit ? commit : undefined; - } - - // Remove [skip ci] from the commit subject. - commit.subject = commit.subject.replace( /\[skip ci\]/, '' ).trim(); + commit.files = getChangedFilesForCommit( commit.hash ) || []; + commit.repositoryUrl = utils.getRepositoryUrl(); - // If a dot is missing at the end of the subject... - if ( !commit.subject.endsWith( '.' ) ) { - // ...let's add it. - commit.subject += '.'; - } + if ( commit.isPublicCommit ) { + // Remove [skip ci] from the commit subject. + commit.subject = commit.subject.replace( /\[skip ci\]/, '' ).trim(); - // The `type` below will be key for grouping commits. - commit.type = utils.getCommitType( commit.rawType ); + // If a dot is missing at the end of the subject... + if ( !commit.subject.endsWith( '.' ) ) { + // ...let's add it. + commit.subject += '.'; + } - if ( typeof commit.subject === 'string' ) { - commit.subject = makeLinks( commit.subject ); - } + // The `type` below will be key for grouping commits. + commit.type = utils.getCommitType( commit.rawType ); - // Remove additional notes from the commit's footer. - // Additional notes are added to the footer. In order to avoid duplication, they should be removed. - if ( commit.footer && commit.notes.length ) { - commit.footer = commit.footer.split( '\n' ) - .filter( footerLine => { - // For each footer line checks whether the line starts with note prefix ("NOTE": ...). - // If so, this footer line should be removed. - return !commit.notes.some( note => footerLine.startsWith( note.title ) ); - } ) - .join( '\n' ) - .trim(); - } + if ( typeof commit.subject === 'string' ) { + commit.subject = makeLinks( commit.subject ); + } - // If `body` of the commit is empty but the `footer` isn't, let's swap those. - if ( commit.footer && !commit.body ) { - commit.body = commit.footer; - commit.footer = null; - } + // Remove additional notes from the commit's footer. + // Additional notes are added to the footer. In order to avoid duplication, they should be removed. + if ( commit.footer && commit.notes.length ) { + commit.footer = commit.footer.split( '\n' ) + .filter( footerLine => { + // For each footer line checks whether the line starts with note prefix ("NOTE": ...). + // If so, this footer line should be removed. + return !commit.notes.some( note => footerLine.startsWith( note.title ) ); + } ) + .join( '\n' ) + .trim(); + } - if ( typeof commit.body === 'string' ) { - commit.body = commit.body.split( '\n' ) - .map( line => { - if ( !line.length ) { - return ''; - } + // If `body` of the commit is empty but the `footer` isn't, let's swap those. + if ( commit.footer && !commit.body ) { + commit.body = commit.footer; + commit.footer = null; + } - return ' ' + line; - } ) - .join( '\n' ); + if ( typeof commit.body === 'string' ) { + commit.body = commit.body.split( '\n' ) + .map( line => { + if ( !line.length ) { + return ''; + } - commit.body = makeLinks( commit.body ); - } + return ' ' + line; + } ) + .join( '\n' ); - normalizeNotes( commit ); + commit.body = makeLinks( commit.body ); + } - // Clear the references array - we don't want to hoist the issues. - delete commit.references; + normalizeNotes( commit ); - commit.repositoryUrl = utils.getRepositoryUrl(); + // Clear the references array - we don't want to hoist the issues. + delete commit.references; + } if ( !commit.body ) { return commit; @@ -152,7 +148,7 @@ module.exports = function transformCommitForSubRepositoryFactory( options = {} ) const commitEntries = commit.body.match( MULTI_ENTRIES_COMMIT_REGEXP ); - if ( !commitEntries.length ) { + if ( !commitEntries || !commitEntries.length ) { return commit; } @@ -176,6 +172,7 @@ module.exports = function transformCommitForSubRepositoryFactory( options = {} ) for ( let i = 0; i < parts.length; ++i ) { const newCommit = { hash: commit.hash, + files: commit.files, repositoryUrl: commit.repositoryUrl, notes: [] }; @@ -272,7 +269,8 @@ module.exports = function transformCommitForSubRepositoryFactory( options = {} ) data.scope = parts[ 1 ].replace( /^\(|\)$/g, '' ) .split( ',' ) .map( p => p.trim() ) - .filter( p => p ); + .filter( p => p ) + .sort(); } return data; @@ -287,10 +285,14 @@ module.exports = function transformCommitForSubRepositoryFactory( options = {} ) /** * @typedef {Object} Commit * + * @property {Boolean} isPublicCommit Whether the commit should be added in the changelog. + * * @property {String} rawType Type of the commit without any modifications. * * @property {String} type Type of the commit (it can be modified). * + * @property {Array.|null} scope Scope of the changes. + * * @property {String} hash The commit SHA-1 id. * * @property {String} repositoryUrl The URL to the repository where the parsed commit has been done. From af3fd269488914de494f7f48217ddf3f118f0b44 Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Wed, 13 May 2020 08:46:13 +0200 Subject: [PATCH 03/33] Breakpoint v2. --- .../generatechangelogforsubrepositories.js | 539 ++++++++++++------ .../lib/release-tools/templates/footer.hbs | 2 +- .../lib/release-tools/templates/template.hbs | 12 + .../lib/release-tools/utils/displaycommits.js | 6 +- .../release-tools/utils/getnewreleasetype.js | 5 - .../release-tools/utils/getnewversiontype.js | 52 ++ .../transform-commit/getwriteroptions.js | 3 +- .../utils/transform-commit/parser-options.js | 3 +- .../transform-commit-utils.js | 18 +- .../transformcommitforsubrepositoryfactory.js | 114 ++-- packages/ckeditor5-dev-env/package.json | 1 + 11 files changed, 531 insertions(+), 224 deletions(-) create mode 100644 packages/ckeditor5-dev-env/lib/release-tools/utils/getnewversiontype.js diff --git a/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogforsubrepositories.js b/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogforsubrepositories.js index 876756124..917318e9a 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogforsubrepositories.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogforsubrepositories.js @@ -6,48 +6,50 @@ 'use strict'; const path = require( 'path' ); -const fs = require( 'fs' ); const { Readable } = require( 'stream' ); - -const { stream, logger } = require( '@ckeditor/ckeditor5-dev-utils' ); +const compareFunc = require( 'compare-func' ); +const { tools, stream, logger } = require( '@ckeditor/ckeditor5-dev-utils' ); +const conventionalChangelogWriter = require( 'conventional-changelog-writer' ); const chalk = require( 'chalk' ); +const minimatch = require( 'minimatch' ); const semver = require( 'semver' ); +const changelogUtils = require( '../utils/changelog' ); const cli = require( '../utils/cli' ); const displayCommits = require( '../utils/displaycommits' ); -const displayGeneratedChangelogs = require( '../utils/displaygeneratedchangelogs' ); const displaySkippedPackages = require( '../utils/displayskippedpackages' ); -const executeOnPackages = require( '../utils/executeonpackages' ); -const generateChangelogForSinglePackage = require( './generatechangelogforsinglepackage' ); -const getNewReleaseType = require( '../utils/getnewreleasetype' ); const getPackageJson = require( '../utils/getpackagejson' ); +const getNewVersionType = require( '../utils/getnewversiontype' ); const getSubRepositoriesPaths = require( '../utils/getsubrepositoriespaths' ); -const transformCommitForSubRepositoryFactory = require( '../utils/transform-commit/transformcommitforsubrepositoryfactory' ); -const versionUtils = require( '../utils/versions' ); - const getCommits = require( '../utils/getcommits' ); +const getWriterOptions = require( '../utils/transform-commit/getwriteroptions' ); +const { getRepositoryUrl } = require( '../utils/transform-commit/transform-commit-utils' ); +const transformCommitForSubRepositoryFactory = require( '../utils/transform-commit/transformcommitforsubrepositoryfactory' ); -const { typesOrder } = require( '../utils/transform-commit/transform-commit-utils' ); -const conventionalChangelogWriter = require( 'conventional-changelog-writer' ); +const VERSIONING_POLICY_URL = 'https://ckeditor.com/docs/ckeditor5/latest/framework/guides/support/versioning-policy.html'; +const noteInfo = `[ℹ️](${ VERSIONING_POLICY_URL }#major-and-minor-breaking-changes)`; /** * Generates the changelog for the mono repository. * * @param {Object} options * @param {String} options.cwd Current working directory (packages) from which all paths will be resolved. - * @param {String} options.packages Where to look for other packages. + * @param {String} options.packages Where to look for packages. * @param {Function} options.transformScope A function that returns a URL to a package from a scope of a commit. * @param {String} [options.scope] Package names have to match to specified glob pattern in order to be processed. * @param {Array.} [options.skipPackages=[]] Name of packages which won't be touched. * @param {String} [options.from] A commit or tag name that will be the first param of the range of commits to collect. - * @returns {Promise.} + * @param {Boolean} [options.highlightsPlaceholder=false] Whether to add a note about release highlights. + * @param {Boolean} [options.collaborationFeatures=false] Whether to add a note about collaboration features. + * @returns {Promise} */ module.exports = function generateChangelogForSubRepositories( options ) { const log = logger(); const cwd = process.cwd(); - const pkgJson = getPackageJson(); + const pkgJson = getPackageJson( options.cwd ); const transformCommit = transformCommitForSubRepositoryFactory( { - useExplicitBreakingChangeGroups: true + useExplicitBreakingChangeGroups: true, + returnInvalidCommit: true } ); const pathsCollection = getSubRepositoriesPaths( { @@ -67,6 +69,9 @@ module.exports = function generateChangelogForSubRepositories( options ) { // Collection of all entries (real commits + additional "fake" commits extracted from descriptions). let allCommits; + // Collection of public entries that will be inserted in the changelog. + let publicCommits; + // Whether the next release will be bumped as "major" release. // It depends on commits. If there is any of them that contains a "MAJOR BREAKING CHANGES" note, // all packages must be released as a major change. @@ -78,9 +83,15 @@ module.exports = function generateChangelogForSubRepositories( options ) { // Packages which during typing the new versions, the user proposed "skip" version. const skippedChangelogs = new Set(); - // A map: packages and their new versions. + // A map contains packages and their new versions. const packagesVersion = new Map(); + // A map contains packages and their current versions. + const currentPackagesVersion = new Map(); + + // A map contains packages and their paths (where they are located) + const packagesPaths = new Map(); + const commitOptions = { from: options.from ? options.from : 'v' + pkgJson.version }; @@ -95,88 +106,27 @@ module.exports = function generateChangelogForSubRepositories( options ) { .then( () => typeNewProposalVersionForAllPackages() ) .then( () => confirmVersionForPackages() ) .then( () => findPackagesWithInternalBumps() ) - .then( () => { - logProcess( 'Generating the changelog' ); - - const commitStream = new Readable( { - objectMode: true - } ); - commitStream._read = function() {}; - - const version = packagesVersion.get( pkgJson.name ); - - const writerContext = { - version, - repoUrl: pkgJson.repository.url.replace( /\.git$/, '' ), - currentTag: 'v' + version, - previousTag: 'v' + pkgJson.version, - isPatch: semver.diff( version, pkgJson.version ) === 'patch', - commit: 'commit' - }; - - const writerOptions = { - groupBy: 'type', - commitGroupsSort( a, b ) { - return typesOrder[ a.title ] - typesOrder[ b.title ]; - }, - commitsSort: [ 'scope' ], - noteGroupsSort( a, b ) { - return typesOrder[ a.title ] - typesOrder[ b.title ]; - }, - notesSort: require( 'compare-func' ), - mainTemplate: getTemplateFile( 'template.hbs' ), - headerPartial: getTemplateFile( 'header.hbs' ), - commitPartial: getTemplateFile( 'commit.hbs' ), - footerPartial: getTemplateFile( 'footer.hbs' ), - transform: { - // We do not allow modifying the hash value by the generator itself. - hash: hash => hash - } - }; - - const publicCommits = [ ...allCommits ].filter( commit => commit.isPublicCommit ) - .map( commit => { - commit.scope = commit.scope.map( name => { - return `[${ name }](${ options.transformScope( name ) })`; - } ); - - return commit; - } ); - - for ( const commit of publicCommits ) { - commitStream.push( commit ); - } - - commitStream.push( null ); - - return new Promise( ( resolve, reject ) => { - commitStream - .pipe( conventionalChangelogWriter( writerContext, writerOptions ) ) - .pipe( stream.noop( changes => { - console.log( changes.toString() ); - - resolve(); - } ) ) - .on( 'error', reject ); - } ); - } ) + .then( () => generateChangelogFromCommits() ) + .then( changesFromCommits => saveChangelog( changesFromCommits ) ) .then( () => { logProcess( 'Summary' ); - process.chdir( cwd ); - - // An empty line increases the readability. - log.info( '' ); + displaySkippedPackages( new Set( [ + ...pathsCollection.skipped, + ...skippedChangelogs + ].sort() ) ); - // displaySkippedPackages( new Set( [ - // ...pathsCollection.skipped, - // ...skippedChangelogs - // ].sort() ) ); + // Make a commit from the repository where we started. + process.chdir( options.cwd ); + tools.shExec( `git add ${ changelogUtils.changelogFile }`, { verbosity: 'error' } ); + tools.shExec( 'git commit -m "Docs: Changelog. [skip ci]"', { verbosity: 'error' } ); - // An empty line between two lists increases the readability. - log.info( '' ); + logInfo( + `Changelog for "${ chalk.underline( pkgJson.name ) }" (v${ packagesVersion.get( pkgJson.name ) }) has been generated.`, + { indentLevel: 1 } + ); - displayGeneratedChangelogs( packagesVersion ); + process.chdir( cwd ); } ) .catch( err => { console.log( err ); @@ -190,22 +140,16 @@ module.exports = function generateChangelogForSubRepositories( options ) { function confirmMajorVersionBump() { logProcess( 'Looking for "MAJOR BREAKING CHANGES" commits...' ); - let hasMajorBreakingChanges = false; - - const majorBreakingChangesCommits = filterMajorBreakingChangesCommits( allCommits ); + const majorBreakingChangesCommits = filterCommitsByNoteTitle( allCommits, 'MAJOR BREAKING CHANGES' ); + const hasMajorBreakingChanges = majorBreakingChangesCommits.length > 0; - if ( majorBreakingChangesCommits.size ) { - hasMajorBreakingChanges = true; - - log.info( `\n${ ' '.repeat( cli.INDENT_SIZE ) }Found ${ chalk.bold( 'MAJOR BREAKING CHANGES') }:` ); + if ( hasMajorBreakingChanges ) { + logInfo( `Found ${ chalk.bold( 'MAJOR BREAKING CHANGES' ) }:`, { indentLevel: 1 } ); displayCommits( majorBreakingChangesCommits, { attachLinkToCommit: true, indentLevel: 2 } ); - } - - if ( !hasMajorBreakingChanges ) { - console.log( chalk.italic( - ' '.repeat( cli.INDENT_SIZE ) + + } else { + logInfo( chalk.italic( 'Not found any "MAJOR BREAKING CHANGES" commit but you can decide whether a next release should be treated as a major.' - ) ); + ), { indentLevel: 1 } ); } return cli.confirmMajorBreakingChangeRelease( hasMajorBreakingChanges, { indentLevel: 1 } ) @@ -214,6 +158,27 @@ module.exports = function generateChangelogForSubRepositories( options ) { } ); } + /** + * Finds commits that contain a note which matches to `titleNote`. + * + * @returns {Array.} + */ + function filterCommitsByNoteTitle( commits, titleNote ) { + return commits.filter( commit => { + if ( !commit.isPublicCommit ) { + return false; + } + + for ( const note of commit.notes ) { + if ( note.title.startsWith( titleNote ) ) { + return true; + } + } + + return false; + } ); + } + /** * If the next release will be the major release, the user needs to provide the version which will be used * as the proposal version for all packages. @@ -231,6 +196,8 @@ module.exports = function generateChangelogForSubRepositories( options ) { .reduce( ( currentHighest, repositoryPath ) => { const packageJson = getPackageJson( repositoryPath ); + currentPackagesVersion.set( packageJson.name, packageJson.version ); + if ( semver.gt( packageJson.version, currentHighest[ 1 ] ) ) { return [ packageJson.name, packageJson.version ]; } @@ -258,9 +225,12 @@ module.exports = function generateChangelogForSubRepositories( options ) { promise = promise.then( () => { const pkgJson = getPackageJson( packagePath ); + packagesPaths.set( pkgJson.name, packagePath ); + currentPackagesVersion.set( pkgJson.name, pkgJson.version ); + logInfo( `Processing "${ chalk.underline( pkgJson.name ) }"...`, { indentLevel: 1, startWithNewLine: true } ); - const packageCommits = filterCommitsByPath( packagePath ); + const packageCommits = filterCommitsByPath( allCommits, packagePath ); const releaseTypeOrVersion = willBeMajorBump ? nextVersion : getNewVersionType( packageCommits ); displayCommits( packageCommits, { indentLevel: 2 } ); @@ -268,7 +238,6 @@ module.exports = function generateChangelogForSubRepositories( options ) { return cli.provideVersion( pkgJson.version, releaseTypeOrVersion, { indentLevel: 2 } ) .then( version => { if ( version === 'skip' ) { - console.log( 'Skipping', packagePath ); skippedChangelogs.add( packagePath ); return Promise.resolve(); @@ -287,6 +256,29 @@ module.exports = function generateChangelogForSubRepositories( options ) { return promise; } + /** + * Finds commits that touched the package under `packagePath` directory. + * + * @param {Array.} commits + * @param {String} packagePath + * @returns {Array.} + */ + function filterCommitsByPath( commits, packagePath ) { + const shortPackagePath = packagePath.replace( options.cwd, '' ) + .replace( new RegExp( `^\\${ path.sep }` ), '' ); + + return commits.filter( commit => { + return commit.files.some( file => { + // The main repository. + if ( shortPackagePath === '' ) { + return !file.startsWith( 'packages' ); + } + + return file.startsWith( shortPackagePath ); + } ); + } ); + } + /** * Finds packages that were skipped or didn't have any committed changes. * @@ -324,110 +316,321 @@ module.exports = function generateChangelogForSubRepositories( options ) { } /** - * Finds commits that contain a "MAJOR BREAKING CHANGES" note. + * Generates a list of changes based on the commits in the main repository. * - * @returns {Set.} + * @returns {Promise.} */ - function filterMajorBreakingChangesCommits() { - const breakingChangesCommits = allCommits - .filter( commit => { - if ( !commit.isPublicCommit ) { - return false; + function generateChangelogFromCommits() { + logProcess( 'Generating the changelog...' ); + + const commitStream = new Readable( { objectMode: true } ); + commitStream._read = function() {}; + + const version = packagesVersion.get( pkgJson.name ); + + const writerContext = { + version, + commit: 'commit', + repoUrl: getRepositoryUrl( options.cwd ), + currentTag: 'v' + version, + previousTag: 'v' + pkgJson.version, + isPatch: semver.diff( version, pkgJson.version ) === 'patch', + highlightsPlaceholder: options.highlightsPlaceholder || false, + collaborationFeatures: options.collaborationFeatures || false + }; + + const writerOptions = getWriterOptions( { + // We do not allow modifying the commit hash value by the generator itself. + hash: hash => hash + } ); + + const sortFunction = compareFunc( item => { + if ( Array.isArray( item.rawScope ) ) { + // A hack that allows moving all scoped commits from the main repository/package at the beginning of the list. + if ( item.rawScope[ 0 ] === pkgJson.name ) { + return 'a'.repeat( 15 ); } - for ( const note of commit.notes ) { - if ( note.title === 'MAJOR BREAKING CHANGES' ) { - return true; - } + return item.rawScope[ 0 ]; + } + + // A hack that allows moving all non-scoped commits or breaking changes notes at the end of the list. + return 'z'.repeat( 15 ); + } ); + + writerOptions.commitsSort = sortFunction; + writerOptions.notesSort = sortFunction; + + publicCommits = [ ...allCommits ] + .filter( commit => commit.isPublicCommit ) + .map( commit => { + commit.rawScope = commit.scope; + + // Transforms a scope to markdown link. + if ( Array.isArray( commit.scope ) ) { + commit.scope = commit.scope.map( scopeToLink ); } - return false; + // Attaches an icon to notes. + commit.notes = commit.notes.map( note => { + note.title += ' ' + noteInfo; + note.rawScope = note.scope; + + // Transforms a scope to markdown link. + if ( Array.isArray( note.scope ) ) { + note.scope = note.scope.map( scopeToLink ); + } + + return note; + } ); + + return commit; } ); - return new Set( breakingChangesCommits ); + for ( const commit of publicCommits ) { + commitStream.push( commit ); + } + + commitStream.push( null ); + + return new Promise( ( resolve, reject ) => { + commitStream + .pipe( conventionalChangelogWriter( writerContext, writerOptions ) ) + .pipe( stream.noop( changes => { + logInfo( 'Changes based on commits have been generated.', { indentLevel: 1 } ); + resolve( changes.toString() ); + } ) ) + .on( 'error', reject ); + } ); + + function scopeToLink( name ) { + return `[${ name }](${ options.transformScope( name ) })`; + } } /** - * Finds commits that touched the package under `packagePath` directory. + * Combines the generated changes based on commits and summary of version changes in packages. + * Appends those changes at the beginning of the changelog file. * - * @param {String} packagePath - * @returns {Array.} + * @param {String} changesFromCommits Generated entries based on commits. */ - function filterCommitsByPath( packagePath ) { - const shortPackagePath = packagePath.replace( options.cwd, '' ) - .replace( new RegExp( `^\\${ path.sep }` ), '' ); + function saveChangelog( changesFromCommits ) { + logProcess( 'Saving changelog...' ); - return allCommits.filter( commit => { - return commit.files.some( file => { - // The main repository. - if ( shortPackagePath === '' ) { - return !file.startsWith( 'packages' ); - } + logInfo( 'Preparing a summary of version changes in packages.', { indentLevel: 1 } ); - return file.startsWith( shortPackagePath ); - } ); - } ); + const dependenciesSummary = generateSummaryOfChangesInPackages(); + + let currentChangelog = changelogUtils.getChangelog(); + + // Remove header from current changelog. + currentChangelog = currentChangelog.replace( changelogUtils.changelogHeader, '' ).trim(); + + // Concat header, new entries and old changelog to single string. + let newChangelog = changelogUtils.changelogHeader + + changesFromCommits.trim() + + '\n\n' + + dependenciesSummary + + '\n\n\n' + + currentChangelog; + + newChangelog = newChangelog.trim() + '\n'; + + // Save the changelog. + changelogUtils.saveChangelog( newChangelog ); + + logInfo( 'Saved.', { indentLevel: 1 } ); } /** - * Proposes new version based on commits. + * Prepares a summary that describes what has changed in all dependencies. * - * @param {Array.} commits * @returns {String} */ - function getNewVersionType( commits ) { - // Repository does not have new changes. - if ( !commits.length ) { - return 'skip'; + function generateSummaryOfChangesInPackages() { + const dependencies = new Map(); + + for ( const [ packageName, nextVersion ] of packagesVersion ) { + // Skip the package hosted in the main repository. + if ( packageName === pkgJson.name ) { + continue; + } + + dependencies.set( packageName, { + next: nextVersion, + current: currentPackagesVersion.get( packageName ) + } ); } - const publicCommits = commits.filter( commit => commit.isPublicCommit ); + const newPackages = getNewPackages( dependencies ); + const majorBreakingChangesPackages = getPackagesMatchedToScopesFromNotes( dependencies, 'MAJOR BREAKING CHANGES' ); + const minorBreakingChangesPackages = getPackagesMatchedToScopesFromNotes( dependencies, 'MINOR BREAKING CHANGES' ); + const newFeaturesPackages = getPackagesWithNewFeatures( dependencies ); + + const entries = [ + '### Released packages\n', + `Check out the [Versioning policy](${ VERSIONING_POLICY_URL }) guide for more information.\n`, + '
Released packages (summary)' + ]; - if ( !publicCommits.length ) { - return 'internal'; + if ( newPackages.size ) { + entries.push( 'New packages:\n' ); + + for ( const [ packageName, version ] of [ ...newPackages ].sort( sortByPackageName ) ) { + entries.push( formatChangelogEntry( packageName, version.next ) ); + } + + entries.push( '' ); } - let newFeatures = false; - let minorBreakingChanges = false; + if ( majorBreakingChangesPackages.size ) { + entries.push( 'Major releases (contain major breaking changes):\n' ); - for ( const commit of publicCommits ) { - for ( const note of commit.notes ) { - if ( note.title === 'MAJOR BREAKING CHANGES' ) { - return 'major'; - } + for ( const [ packageName, version ] of [ ...majorBreakingChangesPackages ].sort( sortByPackageName ) ) { + entries.push( formatChangelogEntry( packageName, version.next, version.current ) ); + } + + entries.push( '' ); + } + + if ( minorBreakingChangesPackages.size ) { + entries.push( 'Minor releases (contain minor breaking changes):\n' ); + + for ( const [ packageName, version ] of [ ...minorBreakingChangesPackages ].sort( sortByPackageName ) ) { + entries.push( formatChangelogEntry( packageName, version.next, version.current ) ); + } + + entries.push( '' ); + } + + if ( newFeaturesPackages.size ) { + entries.push( 'Releases containing new features:\n' ); - if ( note.title === 'MINOR BREAKING CHANGES' ) { - minorBreakingChanges = true; + for ( const [ packageName, version ] of [ ...newFeaturesPackages ].sort( sortByPackageName ) ) { + entries.push( formatChangelogEntry( packageName, version.next, version.current ) ); + } + + entries.push( '' ); + } + + if ( dependencies.size ) { + entries.push( 'Other releases:\n' ); + + for ( const [ packageName, version ] of [ ...dependencies ].sort( sortByPackageName ) ) { + entries.push( formatChangelogEntry( packageName, version.next, version.current ) ); + } + } + + entries.push( '
' ); + + return entries.join( '\n' ).trim(); + + function sortByPackageName( a, b ) { + return a[ 0 ] > b[ 0 ] ? 1 : -1; + } + } + + /** + * @param {Map.} dependencies + * @returns {Map.} + */ + function getNewPackages( dependencies ) { + const packages = new Map(); + + for ( const [ packageName, version ] of dependencies ) { + if ( semver.eq( version.current, '0.0.1' ) ) { + packages.set( packageName, version ); + dependencies.delete( packageName ); + } + } + + return packages; + } + + /** + * Returns packages where scope of changes described in the commits' notes match to packages' names. + * + * @param {Map.} dependencies + * @param {String} noteTitle + * @returns {Map.} + */ + function getPackagesMatchedToScopesFromNotes( dependencies, noteTitle ) { + const packages = new Map(); + const scopes = new Set(); + + for ( const commit of filterCommitsByNoteTitle( publicCommits, noteTitle ) ) { + for ( const note of commit.notes ) { + if ( Array.isArray( note.rawScope ) ) { + scopes.add( note.rawScope[ 0 ] ); } } + } + + for ( const [ packageName, version ] of dependencies ) { + const packageWithoutScope = packageName.replace( /^@ckeditor\//, '' ); - if ( commit.rawType === 'Feature' ) { - newFeatures = true; + for ( const singleScope of scopes ) { + if ( minimatch( packageWithoutScope, '*' + singleScope ) ) { + packages.set( packageName, version ); + dependencies.delete( packageName ); + } } } - // Repository has new features or minor breaking changes. - if ( minorBreakingChanges || newFeatures ) { - return 'minor'; + return packages; + } + + /** + * Returns packages that contain new features. + * + * @param {Map.} dependencies + * @returns {Map.} + */ + function getPackagesWithNewFeatures( dependencies ) { + const packages = new Map(); + + for ( const [ packageName, version ] of dependencies ) { + const packagePath = packagesPaths.get( packageName ); + const commits = filterCommitsByPath( publicCommits, packagePath ); + const hasFeatures = commits.some( commit => commit.rawType === 'Feature' ); + + if ( hasFeatures ) { + packages.set( packageName, version ); + dependencies.delete( packageName ); + } } - return 'patch'; + return packages; } /** - * @param {String} file + * Returns a formatted entry (string) for the changelog. + * + * @param {String} packageName + * @param {String} nextVersion + * @param {String} currentVersion * @returns {String} */ - function getTemplateFile( file ) { - return fs.readFileSync( - require.resolve( '@ckeditor/ckeditor5-dev-env/lib/release-tools/templates/' + file ), 'utf-8' - ); + function formatChangelogEntry( packageName, nextVersion, currentVersion = null ) { + const npmUrl = `https://www.npmjs.com/package/${ packageName }`; + + if ( currentVersion ) { + return `* [${ packageName }](${ npmUrl }): v${ currentVersion } => v${ nextVersion }`; + } + + return `* [${ packageName }](${ npmUrl }): v${ nextVersion }`; } function logProcess( message ) { log.info( '\n📍 ' + chalk.cyan( message ) ); } + /** + * @param {String} message + * @param {Object} [options={}] + * @param {Number} [options.indentLevel=0] + * @param {Boolean} [options.startWithNewLine=false] Whether to append a new line before the message. + */ function logInfo( message, options = {} ) { const indentLevel = options.indentLevel || 0; const startWithNewLine = options.startWithNewLine || false; @@ -437,9 +640,9 @@ module.exports = function generateChangelogForSubRepositories( options ) { }; /** - * @typedef {Object} SummaryChangelogResponse + * @typedef {Object} Version * - * @property {Boolean} wasMajorRelease Determines whether generated changelogs were generated as a major breaking release. + * @param {Boolean} current The current version defined in the `package.json` file. * - * @property {String|null} version If `wasMajorRelease` is `true`, `version` contains a proposed version by a user. + * @param {Boolean} next The next version defined during generating the changelog file. */ diff --git a/packages/ckeditor5-dev-env/lib/release-tools/templates/footer.hbs b/packages/ckeditor5-dev-env/lib/release-tools/templates/footer.hbs index 15c9852d6..2492c731d 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/templates/footer.hbs +++ b/packages/ckeditor5-dev-env/lib/release-tools/templates/footer.hbs @@ -3,7 +3,7 @@ ### {{title}} {{#each notes}} -* {{text}} +* {{#if scope}}**{{~scope.[0]}}**: {{/if}}{{text}} {{/each}} {{/each}} diff --git a/packages/ckeditor5-dev-env/lib/release-tools/templates/template.hbs b/packages/ckeditor5-dev-env/lib/release-tools/templates/template.hbs index 6608d3767..1a4084a55 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/templates/template.hbs +++ b/packages/ckeditor5-dev-env/lib/release-tools/templates/template.hbs @@ -5,6 +5,18 @@ Internal changes only (updated dependencies, documentation, etc.). {{else}} +{{#if highlightsPlaceholder}} +### Release highlights + +TODO: Add a link to the blog post. + +{{/if}} +{{#if collaborationFeatures}} +### Collaboration features + +The CKEditor 5 Collaboration features changelog can be found here: https://ckeditor.com/collaboration/changelog. + +{{/if}} {{> footer}} {{#each commitGroups}} ### {{title}} diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/displaycommits.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/displaycommits.js index ece56013a..16d795ad1 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/utils/displaycommits.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/utils/displaycommits.js @@ -50,11 +50,9 @@ module.exports = function displayCommits( commits, options = {} ) { } for ( const note of singleCommit.notes ) { - if ( note.title.match( /^(MAJOR|MINOR)/ ) ) { - const limit = 100 - note.title.length; + const limit = 100 - note.title.length; - logMessage += `\n${ listEntriesIndent }${ note.title }: ${ utils.truncate( note.text, limit ) } `; - } + logMessage += `\n${ listEntriesIndent }${ note.title }: ${ utils.truncate( note.text, limit ) } `; } if ( attachLinkToCommit ) { diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/getnewreleasetype.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/getnewreleasetype.js index f01475f85..f43bfeeef 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/utils/getnewreleasetype.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/utils/getnewreleasetype.js @@ -5,18 +5,14 @@ 'use strict'; -const through = require( 'through2' ); const conventionalCommitsParser = require( 'conventional-commits-parser' ); const conventionalCommitsFilter = require( 'conventional-commits-filter' ); const gitRawCommits = require( 'git-raw-commits' ); const concat = require( 'concat-stream' ); -const { stream } = require( '@ckeditor/ckeditor5-dev-utils' ); const parserOptions = require( './transform-commit/parser-options' ); const { availableCommitTypes } = require( './transform-commit/transform-commit-utils' ); const getPackageJson = require( './getpackagejson' ); -const REGEXP = /(?:Feature|Other|Fix) \([\w\-, ]+?\):/g; - /** * Returns a type (major, minor, patch) of the next release based on commits. * @@ -79,7 +75,6 @@ module.exports = function getNewReleaseType( transformCommit, options = {} ) { // Returns a type of version for a release based on the commits. // // @param {Array.} commits - // @param {Object} options // @returns {String} function getNewVersionType( commits ) { // Repository does not have new changes. diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/getnewversiontype.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/getnewversiontype.js new file mode 100644 index 000000000..32655e328 --- /dev/null +++ b/packages/ckeditor5-dev-env/lib/release-tools/utils/getnewversiontype.js @@ -0,0 +1,52 @@ +/** + * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md. + */ + +'use strict'; + +/** + * Proposes new version based on commits. + * + * @param {Array.} commits + * @returns {String} + */ +module.exports = function getNewVersionType( commits ) { + // No commits = no changes. + if ( !commits.length ) { + return 'skip'; + } + + const publicCommits = commits.filter( commit => commit.isPublicCommit ); + + // No public commits = internal changes. + if ( !publicCommits.length ) { + return 'internal'; + } + + let newFeatures = false; + let minorBreakingChanges = false; + + for ( const commit of publicCommits ) { + for ( const note of commit.notes ) { + if ( note.title === 'MAJOR BREAKING CHANGES' ) { + return 'major'; + } + + if ( note.title === 'MINOR BREAKING CHANGES' ) { + minorBreakingChanges = true; + } + } + + if ( commit.rawType === 'Feature' ) { + newFeatures = true; + } + } + + // Repository has new features or minor breaking changes. + if ( minorBreakingChanges || newFeatures ) { + return 'minor'; + } + + return 'patch'; +}; diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/getwriteroptions.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/getwriteroptions.js index 8f6af1964..9be8670a5 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/getwriteroptions.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/getwriteroptions.js @@ -11,7 +11,7 @@ const templatePath = path.join( __dirname, '..', '..', 'templates' ); const { typesOrder } = require( './transform-commit-utils' ); /** - * @param {Function} transform + * @param {Function|Object} transform * @returns {Object} */ module.exports = function getWriterOptions( transform ) { @@ -25,7 +25,6 @@ module.exports = function getWriterOptions( transform ) { noteGroupsSort( a, b ) { return typesOrder[ a.title ] - typesOrder[ b.title ]; }, - notesSort: require( 'compare-func' ), mainTemplate: fs.readFileSync( path.join( templatePath, 'template.hbs' ), 'utf-8' ), headerPartial: fs.readFileSync( path.join( templatePath, 'header.hbs' ), 'utf-8' ), commitPartial: fs.readFileSync( path.join( templatePath, 'commit.hbs' ), 'utf-8' ), diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/parser-options.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/parser-options.js index 5fef9b122..a204bccd6 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/parser-options.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/parser-options.js @@ -18,8 +18,7 @@ module.exports = { 'MINOR BREAKING CHANGES', 'MINOR BREAKING CHANGE', 'BREAKING CHANGES', // It will be treated as "MAJOR BREAKING CHANGES" - 'BREAKING CHANGE', // An alias for "BREAKING CHANGES". - 'NOTE' // TODO: Remove. + 'BREAKING CHANGE' // An alias for "BREAKING CHANGES". ], revertPattern: /^Revert:\s([\s\S]*?)\s*This reverts commit (\w*)\./, revertCorrespondence: [ 'header', 'hash' ], diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transform-commit-utils.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transform-commit-utils.js index a458bfed2..01367b477 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transform-commit-utils.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transform-commit-utils.js @@ -8,17 +8,20 @@ const getPackageJson = require( '../getpackagejson' ); const transformCommitUtils = { + /** + * A regexp for extracting additional changelog entries from the single commit. + * Prefixes of the commit must be synchronized the `getCommitType()` util. + */ + MULTI_ENTRIES_COMMIT_REGEXP: /(?:Feature|Other|Fix)(?: \([\w\-, ]+?\))?:/g, + /** * Map of available types of the commits. * Types marked as `false` will be ignored during generating the changelog. */ availableCommitTypes: new Map( [ [ 'Fix', true ], - [ 'Fixes', true ], // TODO: Remove. - [ 'Fixed', true ], // TODO: Remove. [ 'Feature', true ], [ 'Other', true ], - [ 'Code style', false ], [ 'Docs', false ], [ 'Internal', false ], [ 'Tests', false ], @@ -34,8 +37,9 @@ const transformCommitUtils = { 'Bug fixes': 2, 'Other changes': 3, - 'BREAKING CHANGES': 1, - 'NOTE': 2 + 'MAJOR BREAKING CHANGES': 1, + 'MINOR BREAKING CHANGES': 2, + 'BREAKING CHANGES': 3 }, /** @@ -86,6 +90,8 @@ const transformCommitUtils = { /** * Changes a singular type of commit to plural which will be displayed in a changelog. * + * The switch cases must be synchronized with the `MULTI_ENTRIES_COMMIT_REGEXP` regexp. + * * @param {String} commitType * @returns {String} */ @@ -95,8 +101,6 @@ const transformCommitUtils = { return 'Features'; case 'Fix': - case 'Fixes': - case 'Fixed': return 'Bug fixes'; case 'Other': diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transformcommitforsubrepositoryfactory.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transformcommitforsubrepositoryfactory.js index 33574c28f..4f937be2b 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transformcommitforsubrepositoryfactory.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transformcommitforsubrepositoryfactory.js @@ -8,8 +8,6 @@ const utils = require( './transform-commit-utils' ); const getChangedFilesForCommit = require( './getchangedfilesforcommit' ); -const MULTI_ENTRIES_COMMIT_REGEXP = /(?:Feature|Other|Fix)(?: \([\w\-, ]+?\))?:/g; - /** * Factory function. * @@ -26,6 +24,7 @@ const MULTI_ENTRIES_COMMIT_REGEXP = /(?:Feature|Other|Fix)(?: \([\w\-, ]+?\))?:/ * with "MINOR BREAKING CHANGES". This behaviour is being disabled automatically if `options.useExplicitBreakingChangeGroups` is * set on `false` because all commits will be treated as "BREAKING CHANGES". * @param {Boolean} [options.returnInvalidCommit=false] Whether an invalid commit should be returned. + * TODO: Consider removing the option after rewriting "generateSingleChangelog()". * @param {Boolean} [options.useExplicitBreakingChangeGroups] If set on `true`, notes from parsed commits will be grouped as * "MINOR BREAKING CHANGES" and "MAJOR BREAKING CHANGES'. If set on `false` (by default), all breaking changes notes will be treated * as "BREAKING CHANGES". @@ -57,7 +56,7 @@ module.exports = function transformCommitForSubRepositoryFactory( options = {} ) notes: rawCommit.notes.map( note => Object.assign( {}, note ) ) } ); - const parsedType = getTypeAndScope( commit.rawType ); + const parsedType = extractScopeFromPrefix( commit.rawType ); commit.files = []; commit.rawType = parsedType.rawType; @@ -143,22 +142,23 @@ module.exports = function transformCommitForSubRepositoryFactory( options = {} ) } if ( !commit.body ) { - return commit; + // It's used only for displaying the commit. Changelog generator will filter out the invalid entries. + return options.returnInvalidCommit ? commit : undefined; } - const commitEntries = commit.body.match( MULTI_ENTRIES_COMMIT_REGEXP ); + const commitEntries = commit.body.match( utils.MULTI_ENTRIES_COMMIT_REGEXP ); if ( !commitEntries || !commitEntries.length ) { - return commit; + return options.returnInvalidCommit ? commit : undefined; } // Single commit contains a few entries that should be inserted to the changelog. // All of those entries are defined in the array. // Additional commits/entries will be called as "fake commits". - const separatedCommit = [ commit ]; + const separatedCommits = [ commit ]; // Descriptions of additional entries. - const parts = commit.body.split( MULTI_ENTRIES_COMMIT_REGEXP ); + const parts = commit.body.split( utils.MULTI_ENTRIES_COMMIT_REGEXP ); // If the descriptions array contains more entries than fake commit entries, // it means that the first element in descriptions array describes the main (real) commit. @@ -171,28 +171,34 @@ module.exports = function transformCommitForSubRepositoryFactory( options = {} ) // For each fake commit, copy hash and repository of the parent. for ( let i = 0; i < parts.length; ++i ) { const newCommit = { + revert: null, + merge: null, + footer: null, hash: commit.hash, files: commit.files, repositoryUrl: commit.repositoryUrl, - notes: [] + notes: [], + mentions: [] }; - const details = getTypeAndScope( commitEntries[ i ].replace( /:$/, '' ) ); + const details = extractScopeFromPrefix( commitEntries[ i ].replace( /:$/, '' ) ); newCommit.rawType = details.rawType; newCommit.scope = details.scope; newCommit.type = utils.getCommitType( newCommit.rawType ); + newCommit.isPublicCommit = utils.availableCommitTypes.get( commit.rawType ); const commitDescription = parts[ i ]; const subject = commitDescription.match( /^(.*)$/m )[ 0 ]; newCommit.subject = subject.trim(); + newCommit.header = commitEntries[ i ] + subject.trim(); newCommit.body = escapeNewLines( commitDescription.replace( subject, '' ) ); - separatedCommit.push( newCommit ); + separatedCommits.push( newCommit ); } - return separatedCommit; + return separatedCommits; }; function makeLinks( comment ) { @@ -204,6 +210,11 @@ module.exports = function transformCommitForSubRepositoryFactory( options = {} ) function normalizeNotes( commit ) { for ( const note of commit.notes ) { + const details = extractScopeFromNote( note.text ); + + note.text = details.text; + note.scope = details.scope; + // "BREAKING CHANGE" => "BREAKING CHANGES" if ( note.title === 'BREAKING CHANGE' ) { note.title = 'BREAKING CHANGES'; @@ -229,32 +240,28 @@ module.exports = function transformCommitForSubRepositoryFactory( options = {} ) note.title = 'MINOR BREAKING CHANGES'; } - // If explicit breaking changes groups option is disabled, let's remove MINOR/MAJOR prefix from the title. + // If explicit breaking changes groups option is disabled, remove MINOR/MAJOR prefix from the title. if ( !options.useExplicitBreakingChangeGroups ) { note.title = note.title.replace( /^(MINOR|MAJOR) /, '' ); } note.text = makeLinks( note.text ); } - - // Place all "NOTE" at the end. - commit.notes.sort( ( a, b ) => { - // Do not swap two notes. Their weight is equal to each other. - if ( a.title === 'NOTE' && b.title === 'NOTE' ) { - return 0; - } - - if ( a.title === 'NOTE' ) { - return 1; - } else if ( b.title === 'NOTE' ) { - return -1; - } - - return 0; - } ); } - function getTypeAndScope( type ) { + /** + * Extracts the prefix and scope from the `Commit#subject`. + * + * E.g.: + * - input: `Fix (engine): Fixed... + * - output: { rawType: 'Fix', scope: [ 'engine'] } + * + * For commits with no scope, `null` will be returned instead of the array (as `scope`). + * + * @param {String} type First line from the commit message. + * @returns {Object} + */ + function extractScopeFromPrefix( type ) { if ( !type ) { return {}; } @@ -276,9 +283,43 @@ module.exports = function transformCommitForSubRepositoryFactory( options = {} ) return data; } + /** + * Extracts the prefix and scope from the `CommitNote#text`. + * + * E.g.: + * - input: `(engine): Removed... + * - output: { text: 'Removed...', scope: [ 'engine'] } + * + * For notes with no scope, `null` will be returned instead of the array (as `scope`). + * + * @param {String} text A text that describes a note. + * @returns {Object} + */ + function extractScopeFromNote( text ) { + const scopeAsText = text.match( /\(([^)]+)\):/ ); + + if ( !scopeAsText ) { + return { + text, + scope: null + }; + } + + const scope = scopeAsText[ 1 ] + .split( ',' ) + .map( p => p.trim() ) + .filter( p => p ) + .sort(); + + return { + text: text.replace( scopeAsText[ 0 ], '' ).trim(), + scope + }; + } + function escapeNewLines( message ) { // Accept spaces before a sentence because they are ready to be rendered in the changelog template. - return message.replace(/^\n+|\s+$/g, ''); + return message.replace( /^\n+|\s+$/g, '' ); } }; @@ -291,22 +332,23 @@ module.exports = function transformCommitForSubRepositoryFactory( options = {} ) * * @property {String} type Type of the commit (it can be modified). * + * @property {String} header First line of the commit message. + * * @property {Array.|null} scope Scope of the changes. * - * @property {String} hash The commit SHA-1 id. + * @property {Array.} files A list of files tha the commit modified. + * + * @property {String} hash The full commit SHA-1 id. * * @property {String} repositoryUrl The URL to the repository where the parsed commit has been done. * * @property {String} [subject] Subject of the commit. * - * @property {String} [header] First line of the commit message. - * * @property {String|null} [body] Body of the commit message. * * @property {String|null} [footer] Footer of the commit message. * * @property {Array.} [notes] Notes for the commit. - * */ /** @@ -315,4 +357,6 @@ module.exports = function transformCommitForSubRepositoryFactory( options = {} ) * @property {String} title Type of the note. * * @property {String} text Text of the note. + * + * @property {Array.} scope Scope of the note. */ diff --git a/packages/ckeditor5-dev-env/package.json b/packages/ckeditor5-dev-env/package.json index 3124a8c07..2a5500163 100644 --- a/packages/ckeditor5-dev-env/package.json +++ b/packages/ckeditor5-dev-env/package.json @@ -11,6 +11,7 @@ "compare-func": "^1.3.2", "concat-stream": "^2.0.0", "conventional-changelog": "^3.1.8", + "conventional-changelog-writer": "^4.0.16", "conventional-commits-filter": "^2.0.0", "conventional-commits-parser": "^3.0.0", "del": "^5.0.0", From d5f1d5f3ce77ce15e5ae8179b299642c0419deca Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Wed, 13 May 2020 09:09:55 +0200 Subject: [PATCH 04/33] Removed "generateChangelogForSubRepositories()" and "generateSummaryChangelog()" functions. Added "generateChangelogForMonoRepository()". --- packages/ckeditor5-dev-env/lib/index.js | 8 +- ... => generatechangelogformonorepository.js} | 2 +- .../tasks/generatesummarychangelog.js | 624 ---------- packages/ckeditor5-dev-env/tests/index.js | 84 +- .../tasks/generatesummarychangelog.js | 1086 ----------------- 5 files changed, 29 insertions(+), 1775 deletions(-) rename packages/ckeditor5-dev-env/lib/release-tools/tasks/{generatechangelogforsubrepositories.js => generatechangelogformonorepository.js} (99%) delete mode 100644 packages/ckeditor5-dev-env/lib/release-tools/tasks/generatesummarychangelog.js delete mode 100644 packages/ckeditor5-dev-env/tests/release-tools/tasks/generatesummarychangelog.js diff --git a/packages/ckeditor5-dev-env/lib/index.js b/packages/ckeditor5-dev-env/lib/index.js index afaf1d863..64605b17f 100644 --- a/packages/ckeditor5-dev-env/lib/index.js +++ b/packages/ckeditor5-dev-env/lib/index.js @@ -22,12 +22,8 @@ const tasks = { return require( './release-tools/tasks/generatechangelogforsubpackages' )( ...args ); }, - generateChangelogForSubRepositories( ...args ) { - return require( './release-tools/tasks/generatechangelogforsubrepositories' )( ...args ); - }, - - generateSummaryChangelog( ...args ) { - return require( './release-tools/tasks/generatesummarychangelog' )( ...args ); + generateChangelogForMonoRepository( ...args ) { + return require( './release-tools/tasks/generatechangelogformonorepository' )( ...args ); }, /** diff --git a/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogforsubrepositories.js b/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogformonorepository.js similarity index 99% rename from packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogforsubrepositories.js rename to packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogformonorepository.js index 917318e9a..618356ad9 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogforsubrepositories.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogformonorepository.js @@ -42,7 +42,7 @@ const noteInfo = `[ℹ️](${ VERSIONING_POLICY_URL }#major-and-minor-breaking-c * @param {Boolean} [options.collaborationFeatures=false] Whether to add a note about collaboration features. * @returns {Promise} */ -module.exports = function generateChangelogForSubRepositories( options ) { +module.exports = function generateChangelogForMonoRepository( options ) { const log = logger(); const cwd = process.cwd(); const pkgJson = getPackageJson( options.cwd ); diff --git a/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatesummarychangelog.js b/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatesummarychangelog.js deleted file mode 100644 index 1ec324c2a..000000000 --- a/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatesummarychangelog.js +++ /dev/null @@ -1,624 +0,0 @@ -/** - * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. - * For licensing, see LICENSE.md. - */ - -'use strict'; - -const fs = require( 'fs' ); -const path = require( 'path' ); -const semver = require( 'semver' ); -const chalk = require( 'chalk' ); -const moment = require( 'moment' ); -const { tools, logger } = require( '@ckeditor/ckeditor5-dev-utils' ); -const changelogUtils = require( '../utils/changelog' ); -const cliUtils = require( '../utils/cli' ); -const displayCommits = require( '../utils/displaycommits' ); -const displayGeneratedChangelogs = require( '../utils/displaygeneratedchangelogs' ); -const executeOnPackages = require( '../utils/executeonpackages' ); -const generateChangelogFromCommits = require( '../utils/generatechangelogfromcommits' ); -const getPackageJson = require( '../utils/getpackagejson' ); -const getNewReleaseType = require( '../utils/getnewreleasetype' ); -const getSubRepositoriesPaths = require( '../utils/getsubrepositoriespaths' ); -const transformCommitFunctionFactory = require( '../utils/transform-commit/transformcommitforsubrepositoryfactory' ); -const versionUtils = require( '../utils/versions' ); - -const bumpTypesPriority = { - prerelease: 7, - major: 6, - premajor: 5, - minor: 4, - preminor: 3, - patch: 2, - prepatch: 1, - skip: 0 -}; - -/** - * Generates a summary changelog for the builds repositories and for the main CKEditor 5 repository. - * - * @param {Object} options - * @param {String} options.cwd Current working directory (packages) from which all paths will be resolved. - * @param {String} options.packages Where to look for other packages. - * @param {Array.} [options.skipPackages=[]] Name of packages which won't be touched. - * @param {Boolean} [options.skipMainRepository=false] Whether to skip the main repository. - * @param {String} [options.scope=null] Package names have to match to specified glob pattern. - * @param {String|null} [options.version=null] If specified, this version will be used as proposed - * during generating a changelog for a package. - */ -module.exports = function generateSummaryChangelog( options ) { - const log = logger(); - const cwd = process.cwd(); - - const indent = ' '.repeat( cliUtils.INDENT_SIZE ); - const pathsCollection = getSubRepositoriesPaths( { - cwd: options.cwd, - packages: options.packages, - scope: options.scope || null, - skipPackages: options.skipPackages || [], - skipMainRepository: true - } ); - - // The main repository must be at the end because its changelog is a summary of all changes that have been done. - if ( !options.skipMainRepository ) { - pathsCollection.skipped.delete( options.cwd ); - pathsCollection.matched.add( options.cwd ); - } - - const generatedChangelogMap = new Map(); - - logProcess( 'Generating summary changelogs...' ); - - return executeOnPackages( pathsCollection.matched, generateSummaryChangelogForSingleRepository ) - .then( () => { - logProcess( 'Summary' ); - - // An empty line increases the readability. - console.log( '' ); - displayGeneratedChangelogs( generatedChangelogMap ); - } ); - - // Generates the summary changelog for specified repository. - // - // @param {String} repositoryPath - // @returns {Promise} - function generateSummaryChangelogForSingleRepository( repositoryPath ) { - process.chdir( repositoryPath ); - - const packageJson = getPackageJson( repositoryPath ); - - log.info( '\n' + indent + chalk.bold( `Generating changelog for "${ chalk.underline( packageJson.name ) }"...` ) ); - - const dependencies = getMapWithDependenciesVersions( - getAllDependenciesForRepository( repositoryPath ) - ); - - let tagName = versionUtils.getLastFromChangelog( repositoryPath ); - let suggestedBumpFromCommits; - - if ( tagName ) { - tagName = 'v' + tagName; - } - - const transformCommitFunction = transformCommitFunctionFactory( { - returnInvalidCommit: true - } ); - - return getNewReleaseType( transformCommitFunction, { tagName } ) - .then( result => { - suggestedBumpFromCommits = result.releaseType === 'internal' ? 'skip' : result.releaseType; - - displayCommits( result.commits, { indentLevel: 2 } ); - - const suggestedBumpFromDependencies = getSuggestedBumpVersionType( dependencies ); - const commitsWeight = bumpTypesPriority[ suggestedBumpFromCommits ]; - const packagesWeight = bumpTypesPriority[ suggestedBumpFromDependencies ]; - - let newReleaseType; - - if ( options.version ) { - newReleaseType = options.version; - } else if ( !packagesWeight || commitsWeight > packagesWeight ) { - newReleaseType = suggestedBumpFromCommits; - } else { - newReleaseType = suggestedBumpFromDependencies; - } - - return cliUtils.provideVersion( packageJson.version, newReleaseType, { disableInternalVersion: true } ); - } ) - .then( version => { - if ( version === 'skip' ) { - return Promise.resolve(); - } - - let promise = Promise.resolve(); - - // Generate the changelog entries based on dependencies. - let changelogEntries = getChangelogFromDependencies( { - dependencies, - newVersion: version, - currentVersion: packageJson.version, - repositoryUrl: packageJson.repository.url.replace( /\.git$/, '' ) - } ); - - // Additional notes for changelog generated from commits should be added if any dependency has been added or changed. - const additionalNotes = changelogEntries.trim().split( '\n' ).length !== 1; - - if ( suggestedBumpFromCommits !== 'skip' ) { - promise = generateChangelogFromCommits( { - version, - additionalNotes, - currentTag: 'v' + version, - previousTag: tagName, - transformCommit: transformCommitFunctionFactory(), - isInternalRelease: false, - doNotSave: true - } ); - } - - return promise.then( changesBasedOnCommits => { - // Part of the changelog generated from commits should be attached to changelog entries. - if ( changesBasedOnCommits ) { - changelogEntries = changesBasedOnCommits.trim() + '\n\n' + - changelogEntries.split( '\n' ) - .slice( 1 ) // First line contains a header which is already generated. - .join( '\n' ) - .trim(); - } - - if ( !fs.existsSync( changelogUtils.changelogFile ) ) { - log.warning( indent + 'Changelog file does not exist. Creating...' ); - - changelogUtils.saveChangelog( changelogUtils.changelogHeader ); - } - - let currentChangelog = changelogUtils.getChangelog( repositoryPath ); - - // Remove header from current changelog. - currentChangelog = currentChangelog.replace( changelogUtils.changelogHeader, '' ); - - // Concat header, new and current changelog. - let newChangelog = changelogUtils.changelogHeader + changelogEntries + '\n\n\n' + currentChangelog.trim(); - newChangelog = newChangelog.trim() + '\n'; - - // Save the changelog. - changelogUtils.saveChangelog( newChangelog, repositoryPath ); - - log.info( - indent + - chalk.green( `Changelog for "${ chalk.underline( packageJson.name ) }" (v${ version }) has been generated.` ) - ); - - // Commit the new changelog. - tools.shExec( `git add ${ changelogUtils.changelogFile }`, { verbosity: 'error' } ); - tools.shExec( 'git commit -m "Docs: Changelog. [skip ci]"', { verbosity: 'error' } ); - - generatedChangelogMap.set( packageJson.name, version ); - } ); - } ) - .then( () => { - process.chdir( cwd ); - } ) - .catch( err => { - log.error( err.stack ); - } ); - } - - // Returns a list which contains all dependencies. It means – not only these specified in `package.json` - // but also dependency of the dependencies. - // - // @param {String} repositoryPath Path to the parsed repository. - // @returns {Set} List of all dependencies. - function getAllDependenciesForRepository( repositoryPath ) { - const packageJson = getPackageJson( repositoryPath ); - const packagesToCheck = Object.keys( packageJson.dependencies || packageJson.devDependencies ) - .filter( isValidDependency ); - - const allDependencies = new Set(); - const checkedPackages = new Set(); - - while ( packagesToCheck.length ) { - const packageName = packagesToCheck.shift(); - - // Does not check the same package more than once. - if ( checkedPackages.has( packageName ) ) { - continue; - } - - checkedPackages.add( packageName ); - - const currentPackagePath = getPathToRepository( packageName ); - - // Package cannot be dependency for itself. - if ( currentPackagePath === repositoryPath ) { - continue; - } - - // If package is not installed locally, we aren't able to get the changelog entries. - if ( !pathsCollection.skipped.has( currentPackagePath ) && !pathsCollection.matched.has( currentPackagePath ) ) { - continue; - } - - const currentDependencyPackageJson = getPackageJson( currentPackagePath ); - - packagesToCheck.push( - ...Object.keys( currentDependencyPackageJson.dependencies || {} ) - .filter( isValidDependency ) - ); - - allDependencies.add( packageName ); - } - - return allDependencies; - } - - // Checks whether specified package name matches to `@ckeditor/ckeditor5-*` schema. - // Dev package (`@ckeditor/ckeditor5-dev-*`) is not valid. - // - // @param {String} packageName - // @returns {Boolean} - function isValidDependency( packageName ) { - if ( !packageName.match( /^@ckeditor/ ) ) { - return false; - } - - if ( packageName.match( /-dev-/ ) ) { - return false; - } - - return true; - } - - // Returns a path to the repository for specified package. - // - // @param {String} packageName - // @returns {String} - function getPathToRepository( packageName ) { - return packageName.replace( '@ckeditor', path.join( options.cwd, options.packages ) ); - } - - // Builds a map which contains current and future versions of specified packages. - // - // @params {Set} dependencies - // @returns {Map} - function getMapWithDependenciesVersions( dependencies ) { - const dependenciesVersions = new Map(); - - for ( const packageName of [ ...dependencies ].sort() ) { - const repositoryPath = getPathToRepository( packageName ); - const nextVersion = versionUtils.getLastFromChangelog( repositoryPath ); - const currentVersion = versionUtils.getCurrent( repositoryPath ); - - // If "nextVersion" is null, the changelog for the package hasn't been generated. - if ( !nextVersion ) { - continue; - } - - // Changelog contains a version for the future release. - // Version specified in `package.json` is bumping during the release process, - // we can assume that the versions are different. - if ( nextVersion !== currentVersion ) { - dependenciesVersions.set( packageName, { currentVersion, nextVersion, repositoryPath } ); - } - } - - return dependenciesVersions; - } - - // Returns a new type of the release for current package. - // - // @params {String} version - // @params {Map} dependencies - // @returns {String} - function getSuggestedBumpVersionType( dependencies ) { - let currentBumpType = null; - - for ( const [ , { currentVersion, nextVersion } ] of dependencies ) { - if ( !nextVersion ) { - continue; - } - - const diffType = semver.diff( currentVersion, nextVersion ); - - if ( shouldOverwriteReleaseType( currentBumpType, diffType ) ) { - currentBumpType = diffType; - } - - // When the suggested bump is equal to "major", we can stop analyzing next versions. - if ( currentBumpType === 'major' ) { - break; - } - } - - return currentBumpType; - } - - // Checks whether specified `currentBumpType` bump for release can be overwrite. - // - // It returns true when: - // - "currentBumpType" is null (it's not set yet) or - // - returned diff has higher priority than the current suggested bump. - // - // @params {String} currentBumpType - // @params {String} diffType - // @returns {Boolean} - function shouldOverwriteReleaseType( currentBumpType, diffType ) { - if ( !bumpTypesPriority[ diffType ] ) { - return false; - } - - if ( !currentBumpType ) { - return true; - } - - return bumpTypesPriority[ diffType ] > bumpTypesPriority[ currentBumpType ]; - } - - // Generates new changelog entry. - // - // @params {Object} options - // @params {String} options.repositoryURL - // @params {String} options.newVersion - // @params {String} options.currentVersion - // @params {Map} options.dependencies - // @returns {String} - function getChangelogFromDependencies( options ) { - const date = moment().format( 'YYYY-MM-DD' ); - - const entries = [ - // eslint-disable-next-line max-len - `## [${ options.newVersion }](${ options.repositoryUrl }/compare/v${ options.currentVersion }...v${ options.newVersion }) (${ date })`, - '' - ]; - - const allowBreakingChangeInMinor = areBreakingChangesAcceptableInVersion( options.newVersion ); - const newPackages = getNewPackages( options.dependencies ); - - // We need to remove new packages from the whole collection because we don't want to have duplicated (as minor or major) releases. - removeDependencies( newPackages, options.dependencies ); - - const majorReleasePackages = getMajorReleasePackages( options.dependencies ); - const majorBreakingChangesReleasePackages = getMajorBreakingChangesReleasePackages( majorReleasePackages ); - let majorReleaseWithMinorChanges = new Set(); - - // For major releases, we would like to display in a separately category packages that have "MINOR BREAKING CHANGES". - if ( majorReleasePackages.size ) { - majorReleaseWithMinorChanges = getMinorBreakingChangesReleasePackages( options.dependencies ); - } - - const minorReleasePackages = getMinorReleasePackages( options.dependencies ); - const minorBreakingChangesReleasePackages = getMinorBreakingChangesReleasePackages( minorReleasePackages ); - - const patchReleasePackages = getPatchReleasePackages( options.dependencies ); - - // `major|minorBreakingChangesReleasePackages` are duplicated in `major|minorReleasePackages` collections. - // Because we don't want to duplicate them, let's clean it before starting generating changelog entries. - removeDependencies( majorReleaseWithMinorChanges, majorReleasePackages ); - removeDependencies( majorBreakingChangesReleasePackages, majorReleasePackages ); - removeDependencies( minorBreakingChangesReleasePackages, minorReleasePackages ); - - const hasChangesInAnyOfPackages = [ - newPackages.size, - majorReleasePackages.size, - majorBreakingChangesReleasePackages.size, - minorReleasePackages.size, - minorBreakingChangesReleasePackages.size, - patchReleasePackages.size - ].some( number => number > 0 ); - - // Push the "Dependencies" header to entries list if any package has been added or changed. - if ( hasChangesInAnyOfPackages ) { - entries.push( '### Dependencies' ); - entries.push( '' ); - } - - if ( newPackages.size ) { - entries.push( 'New packages:\n' ); - - for ( const [ packageName, { nextVersion } ] of newPackages ) { - entries.push( formatChangelogEntry( packageName, nextVersion ) ); - } - - entries.push( '' ); - } - - if ( majorBreakingChangesReleasePackages.size ) { - entries.push( 'Major releases (contain major breaking changes):\n' ); - - for ( const [ packageName, { currentVersion, nextVersion } ] of majorBreakingChangesReleasePackages ) { - entries.push( formatChangelogEntry( packageName, nextVersion, currentVersion ) ); - } - - entries.push( '' ); - } - - if ( majorReleaseWithMinorChanges.size ) { - entries.push( 'Major releases (contain minor breaking changes):\n' ); - - for ( const [ packageName, { currentVersion, nextVersion } ] of majorReleaseWithMinorChanges ) { - entries.push( formatChangelogEntry( packageName, nextVersion, currentVersion ) ); - } - - entries.push( '' ); - } - - if ( majorReleasePackages.size ) { - entries.push( 'Major releases (dependencies of those packages have breaking changes):\n' ); - - for ( const [ packageName, { currentVersion, nextVersion } ] of majorReleasePackages ) { - entries.push( formatChangelogEntry( packageName, nextVersion, currentVersion ) ); - } - - entries.push( '' ); - } - - if ( minorBreakingChangesReleasePackages.size ) { - if ( allowBreakingChangeInMinor ) { - entries.push( 'Minor releases (containing major/minor breaking changes):\n' ); - } else { - entries.push( 'Minor releases (containing minor breaking changes):\n' ); - } - - for ( const [ packageName, { currentVersion, nextVersion } ] of minorBreakingChangesReleasePackages ) { - entries.push( formatChangelogEntry( packageName, nextVersion, currentVersion ) ); - } - - entries.push( '' ); - } - - if ( minorReleasePackages.size ) { - entries.push( 'Minor releases (new features, no breaking changes):\n' ); - - for ( const [ packageName, { currentVersion, nextVersion } ] of minorReleasePackages ) { - entries.push( formatChangelogEntry( packageName, nextVersion, currentVersion ) ); - } - - entries.push( '' ); - } - - if ( patchReleasePackages.size ) { - entries.push( 'Patch releases (bug fixes, internal changes):\n' ); - - for ( const [ packageName, { currentVersion, nextVersion } ] of patchReleasePackages ) { - entries.push( formatChangelogEntry( packageName, nextVersion, currentVersion ) ); - } - - entries.push( '' ); - } - - return entries.join( '\n' ).trim(); - } - - // Filters out packages which were not introduced in the current milestone. - // - // @params {Map} dependencies - // @returns {Map} - function getNewPackages( dependencies ) { - return filterPackages( dependencies, ( packageName, { currentVersion } ) => { - return semver.eq( currentVersion, '0.0.1' ); - } ); - } - - // Returns a collection of packages which the future release is marked as "major" and contain "MAJOR BREAKING CHANGES" - // entries in their changelogs. - // - // @params {Map} dependencies - // @returns {Map} - function getMajorBreakingChangesReleasePackages( dependencies ) { - return filterPackages( dependencies, ( packageName, { nextVersion, repositoryPath } ) => { - return changelogUtils.hasMajorBreakingChanges( nextVersion, repositoryPath ); - } ); - } - - // Returns a collection of packages which the future release is marked as "major". - // - // @params {Map} dependencies - // @returns {Map} - function getMajorReleasePackages( dependencies ) { - return filterPackages( dependencies, ( packageName, { currentVersion, nextVersion } ) => { - const versionDiff = semver.diff( currentVersion, nextVersion ); - - return versionDiff === 'major' || versionDiff === 'premajor' || versionDiff === 'prerelease'; - } ); - } - - // Returns a collection of packages which the future release is marked as "minor" and contain "MINOR BREAKING CHANGES" - // entries in their changelogs. - // - // @params {Map} dependencies - // @returns {Map} - function getMinorBreakingChangesReleasePackages( dependencies ) { - return filterPackages( dependencies, ( packageName, { nextVersion, repositoryPath } ) => { - return changelogUtils.hasMinorBreakingChanges( nextVersion, repositoryPath ); - } ); - } - - // Returns a collection of packages which the future release is marked as "minor". - // - // @params {Map} dependencies - // @returns {Map} - function getMinorReleasePackages( dependencies ) { - return filterPackages( dependencies, ( packageName, { currentVersion, nextVersion } ) => { - const versionDiff = semver.diff( currentVersion, nextVersion ); - - return versionDiff === 'minor' || versionDiff === 'preminor'; - } ); - } - - // Returns a collection of packages which the future release is marked as "patch". - // - // @params {Map} dependencies - // @returns {Map} - function getPatchReleasePackages( dependencies ) { - return filterPackages( dependencies, ( packageName, { currentVersion, nextVersion } ) => { - const versionDiff = semver.diff( currentVersion, nextVersion ); - - return versionDiff === 'patch' || versionDiff === 'prepatch'; - } ); - } - - // Executes specified callback for each item on passed dependencies collection. - // - // @params {Map} dependencies - // @params {Function} callback A function which accepts three parameters: `String` packageName, `String` currentVersion - // and `String` nextVersion. The function must return `Boolean` value. - // @returns {Map} - function filterPackages( dependencies, callback ) { - const packages = new Map(); - - for ( const [ packageName, options ] of dependencies ) { - if ( callback( packageName, options ) ) { - packages.set( packageName, Object.assign( {}, options ) ); - } - } - - return packages; - } - - // Removes packages from the collection (`removeFrom`) based on items in the `dependenciesToRemove` collection. - // - // @params {Map} dependenciesToRemove - // @params {Map} removeFrom - function removeDependencies( dependenciesToRemove, removeFrom ) { - for ( const [ packageName ] of dependenciesToRemove ) { - removeFrom.delete( packageName ); - } - } - - // Returns a formatted string for changelog. - // - // @params {String} packageName - // @params {String} nextVersion - // @params {String|null} [currentVersion=null] - // @returns {String} - function formatChangelogEntry( packageName, nextVersion, currentVersion = null ) { - const packageJson = getPackageJson( getPathToRepository( packageName ) ); - const repositoryUrl = packageJson.repository.url.replace( /\.git$/, '' ); - const githubUrl = `${ repositoryUrl }/releases/tag/v${ nextVersion }`; - const npmUrl = `https://www.npmjs.com/package/${ packageName }`; - - if ( currentVersion ) { - return `* [${ packageName }](${ npmUrl }): v${ currentVersion } => [v${ nextVersion }](${ githubUrl })`; - } - - return `* [${ packageName }](${ npmUrl }): [v${ nextVersion }](${ githubUrl })`; - } - - // Checks whether breaking changes are acceptable for specified version. - // - // @params {String} version - // @returns {Boolean} - function areBreakingChangesAcceptableInVersion( version ) { - // For any version above the `1.0.0`, breaking changes mean that "major" version will be bumped. - if ( !semver.gt( '1.0.0', version ) ) { - return false; - } - - // "prerelease" below `1.0.0` should be parsed as "major" release. - return semver.diff( version, '1.0.0' ) !== 'prerelease'; - } - - function logProcess( message ) { - log.info( '\n📍 ' + chalk.cyan( message ) ); - } -}; diff --git a/packages/ckeditor5-dev-env/tests/index.js b/packages/ckeditor5-dev-env/tests/index.js index e9834f4b7..f8262ce0c 100644 --- a/packages/ckeditor5-dev-env/tests/index.js +++ b/packages/ckeditor5-dev-env/tests/index.js @@ -34,13 +34,11 @@ describe( 'dev-env/index', () => { createPotFiles: sandbox.spy(), getToken: sandbox.stub() }, - releaseTools: { - releaseRepository: sandbox.stub(), + release: { releaseSubRepositories: sandbox.stub(), generateChangelogForSinglePackage: sandbox.stub(), generateChangelogForSubPackages: sandbox.stub(), - generateChangelogForSubRepositories: sandbox.stub(), - generateSummaryChangelog: sandbox.stub(), + generateChangelogForMonoRepository: sandbox.stub(), bumpVersions: sandbox.stub() } }; @@ -50,30 +48,13 @@ describe( 'dev-env/index', () => { mockery.registerMock( './translations/download', stubs.translations.download ); mockery.registerMock( './translations/createpotfiles', stubs.translations.createPotFiles ); - mockery.registerMock( - './release-tools/tasks/releasesubrepositories', - stubs.releaseTools.releaseSubRepositories - ); - mockery.registerMock( - './release-tools/tasks/generatechangelogforsinglepackage', - stubs.releaseTools.generateChangelogForSinglePackage - ); - mockery.registerMock( - './release-tools/tasks/generatechangelogforsubpackages', - stubs.releaseTools.generateChangelogForSubPackages - ); - mockery.registerMock( - './release-tools/tasks/generatechangelogforsubrepositories', - stubs.releaseTools.generateChangelogForSubRepositories - ); - mockery.registerMock( - './release-tools/tasks/generatesummarychangelog', - stubs.releaseTools.generateSummaryChangelog - ); - mockery.registerMock( - './release-tools/tasks/bumpversions', - stubs.releaseTools.bumpVersions - ); + const releaseTools = stubs.release; + + mockery.registerMock( './release-tools/tasks/bumpversions', releaseTools.bumpVersions ); + mockery.registerMock( './release-tools/tasks/generatechangelogforsinglepackage', releaseTools.generateChangelogForSinglePackage ); + mockery.registerMock( './release-tools/tasks/releasesubrepositories', releaseTools.releaseSubRepositories ); + mockery.registerMock( './release-tools/tasks/generatechangelogforsubpackages', releaseTools.generateChangelogForSubPackages ); + mockery.registerMock( './release-tools/tasks/generatechangelogformonorepository', releaseTools.generateChangelogForMonoRepository ); tasks = proxyquire( '../lib/index', { '@ckeditor/ckeditor5-dev-utils': { @@ -91,78 +72,65 @@ describe( 'dev-env/index', () => { describe( 'releaseSubRepositories()', () => { it( 'creates release for sub repositories', () => { - stubs.releaseTools.releaseSubRepositories.returns( Promise.resolve( { result: true } ) ); + stubs.release.releaseSubRepositories.returns( Promise.resolve( { result: true } ) ); return tasks.releaseSubRepositories( 'arg' ) .then( response => { expect( response.result ).to.equal( true ); - expect( stubs.releaseTools.releaseSubRepositories.calledOnce ).to.equal( true ); - expect( stubs.releaseTools.releaseSubRepositories.firstCall.args[ 0 ] ).to.equal( 'arg' ); + expect( stubs.release.releaseSubRepositories.calledOnce ).to.equal( true ); + expect( stubs.release.releaseSubRepositories.firstCall.args[ 0 ] ).to.equal( 'arg' ); } ); } ); } ); describe( 'generateChangelogForSinglePackage()', () => { it( 'generates a changelog for package', () => { - stubs.releaseTools.generateChangelogForSinglePackage.returns( Promise.resolve( { result: true } ) ); + stubs.release.generateChangelogForSinglePackage.returns( Promise.resolve( { result: true } ) ); return tasks.generateChangelogForSinglePackage( 'arg' ) .then( response => { expect( response.result ).to.equal( true ); - expect( stubs.releaseTools.generateChangelogForSinglePackage.calledOnce ).to.equal( true ); - expect( stubs.releaseTools.generateChangelogForSinglePackage.firstCall.args[ 0 ] ).to.equal( 'arg' ); + expect( stubs.release.generateChangelogForSinglePackage.calledOnce ).to.equal( true ); + expect( stubs.release.generateChangelogForSinglePackage.firstCall.args[ 0 ] ).to.equal( 'arg' ); } ); } ); } ); describe( 'generateChangelogForSubPackages()', () => { it( 'generates a changelog for sub packages', () => { - stubs.releaseTools.generateChangelogForSubPackages.returns( Promise.resolve( { result: true } ) ); + stubs.release.generateChangelogForSubPackages.returns( Promise.resolve( { result: true } ) ); return tasks.generateChangelogForSubPackages( 'arg' ) .then( response => { expect( response.result ).to.equal( true ); - expect( stubs.releaseTools.generateChangelogForSubPackages.calledOnce ).to.equal( true ); - expect( stubs.releaseTools.generateChangelogForSubPackages.firstCall.args[ 0 ] ).to.equal( 'arg' ); + expect( stubs.release.generateChangelogForSubPackages.calledOnce ).to.equal( true ); + expect( stubs.release.generateChangelogForSubPackages.firstCall.args[ 0 ] ).to.equal( 'arg' ); } ); } ); } ); - describe( 'generateChangelogForSubRepositories()', () => { + describe( 'generateChangelogForMonoRepository()', () => { it( 'generates a changelog for sub repositories', () => { - stubs.releaseTools.generateChangelogForSubRepositories.returns( Promise.resolve( { result: true } ) ); - - return tasks.generateChangelogForSubRepositories( 123 ) - .then( response => { - expect( response.result ).to.equal( true ); - expect( stubs.releaseTools.generateChangelogForSubRepositories.calledOnce ).to.equal( true ); - expect( stubs.releaseTools.generateChangelogForSubRepositories.firstCall.args[ 0 ] ).to.equal( 123 ); - } ); - } ); - } ); - - describe( 'generateSummaryChangelog()', () => { - it( 'generates a changelog', () => { - stubs.releaseTools.generateSummaryChangelog.returns( Promise.resolve( { result: true } ) ); + stubs.release.generateChangelogForMonoRepository.returns( Promise.resolve( { result: true } ) ); - return tasks.generateSummaryChangelog( 123 ) + return tasks.generateChangelogForMonoRepository( 123 ) .then( response => { expect( response.result ).to.equal( true ); - expect( stubs.releaseTools.generateSummaryChangelog.calledOnce ).to.equal( true ); - expect( stubs.releaseTools.generateSummaryChangelog.firstCall.args[ 0 ] ).to.equal( 123 ); + expect( stubs.release.generateChangelogForMonoRepository.calledOnce ).to.equal( true ); + expect( stubs.release.generateChangelogForMonoRepository.firstCall.args[ 0 ] ).to.equal( 123 ); } ); } ); } ); describe( 'bumpVersions()', () => { it( 'updates version of dependencies', () => { - stubs.releaseTools.bumpVersions.returns( Promise.resolve( { result: true } ) ); + stubs.release.bumpVersions.returns( Promise.resolve( { result: true } ) ); return tasks.bumpVersions( 123 ) .then( response => { expect( response.result ).to.equal( true ); - expect( stubs.releaseTools.bumpVersions.calledOnce ).to.equal( true ); - expect( stubs.releaseTools.bumpVersions.firstCall.args[ 0 ] ).to.equal( 123 ); + expect( stubs.release.bumpVersions.calledOnce ).to.equal( true ); + expect( stubs.release.bumpVersions.firstCall.args[ 0 ] ).to.equal( 123 ); } ); } ); } ); diff --git a/packages/ckeditor5-dev-env/tests/release-tools/tasks/generatesummarychangelog.js b/packages/ckeditor5-dev-env/tests/release-tools/tasks/generatesummarychangelog.js deleted file mode 100644 index e12b6c15b..000000000 --- a/packages/ckeditor5-dev-env/tests/release-tools/tasks/generatesummarychangelog.js +++ /dev/null @@ -1,1086 +0,0 @@ -/** - * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. - * For licensing, see LICENSE.md. - */ - -'use strict'; - -const path = require( 'path' ); -const sinon = require( 'sinon' ); -const expect = require( 'chai' ).expect; -const proxyquire = require( 'proxyquire' ); -const mockery = require( 'mockery' ); -const executeOnPackages = require( '../../../lib/release-tools/utils/executeonpackages' ); - -const mainPackagePath = path.join( __dirname, 'stubs', 'releasesubrepositories' ); -const packagesPaths = { - alpha: path.join( mainPackagePath, 'packages', 'alpha' ), - beta: path.join( mainPackagePath, 'packages', 'beta' ), - gamma: path.join( mainPackagePath, 'packages', 'gamma' ), - delta: path.join( mainPackagePath, 'packages', 'delta' ), - epsilon: path.join( mainPackagePath, 'packages', 'epsilon' ), - omega: path.join( mainPackagePath, 'packages', 'omega' ), - devKappa: path.join( mainPackagePath, 'packages', 'dev-kappa' ) -}; - -const testCwd = process.cwd(); - -// Tests below use real files (as mocks). See: "/packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories". -// `console.log` calls are mocked (See L85) because the task at the end prints an empty line which breaks the test logs. -describe( 'dev-env/release-tools/tasks', () => { - let generateSummaryChangelog, sandbox, stubs; - - beforeEach( () => { - sandbox = sinon.createSandbox(); - - mockery.enable( { - useCleanCache: true, - warnOnReplace: false, - warnOnUnregistered: false - } ); - - stubs = { - shExec: sandbox.stub(), - logger: { - info: sandbox.spy(), - warning: sandbox.spy(), - error: sandbox.spy() - }, - versionUtils: { - getLastFromChangelog: sandbox.stub(), - getCurrent: sandbox.stub() - }, - cliUtils: { - provideVersion: sandbox.stub() - }, - changelogUtils: { - getChangelog: sandbox.stub(), - saveChangelog: sandbox.stub(), - hasMajorBreakingChanges: sandbox.stub(), - hasMinorBreakingChanges: sandbox.stub(), - changelogHeader: '' - }, - displayGeneratedChangelogs: sandbox.stub(), - getSubRepositoriesPaths: sandbox.stub(), - transformCommitFunctionFactory: sandbox.stub(), - transformCommit: [ - sandbox.stub(), - sandbox.stub() - ], - generateChangelogFromCommits: sandbox.stub(), - getNewReleaseType: sandbox.stub(), - displayCommits: sandbox.stub(), - executeOnPackages: sandbox.stub(), - moment: { - format: sandbox.stub() - }, - fs: { - existsSync: sandbox.stub() - } - }; - - stubs.transformCommitFunctionFactory.onFirstCall().returns( stubs.transformCommit[ 0 ] ); - stubs.transformCommitFunctionFactory.onSecondCall().returns( stubs.transformCommit[ 1 ] ); - - sandbox.stub( console, 'log' ); - - mockery.registerMock( 'moment', () => stubs.moment ); - mockery.registerMock( '../utils/displaygeneratedchangelogs', stubs.displayGeneratedChangelogs ); - mockery.registerMock( '../utils/transform-commit/transformcommitforsubrepositoryfactory', stubs.transformCommitFunctionFactory ); - mockery.registerMock( '../utils/generatechangelogfromcommits', stubs.generateChangelogFromCommits ); - mockery.registerMock( '../utils/executeonpackages', stubs.executeOnPackages ); - mockery.registerMock( '../utils/getnewreleasetype', stubs.getNewReleaseType ); - mockery.registerMock( '../utils/displaycommits', stubs.displayCommits ); - mockery.registerMock( '../utils/versions', stubs.versionUtils ); - mockery.registerMock( '../utils/cli', stubs.cliUtils ); - - sandbox.stub( path, 'join' ).callsFake( ( ...chunks ) => chunks.join( '/' ) ); - - generateSummaryChangelog = proxyquire( '../../../lib/release-tools/tasks/generatesummarychangelog', { - fs: stubs.fs, - '@ckeditor/ckeditor5-dev-utils': { - tools: { - shExec: stubs.shExec - }, - logger() { - return stubs.logger; - } - }, - '../utils/changelog': stubs.changelogUtils, - '../utils/getsubrepositoriespaths': stubs.getSubRepositoriesPaths - } ); - } ); - - afterEach( () => { - sandbox.restore(); - mockery.disable(); - } ); - - describe( 'generateSummaryChangelog()', () => { - it( 'generates a summary changelog for single package', () => { - const commits = [ {}, {} ]; - - stubs.getSubRepositoriesPaths.returns( { - matched: new Set( [ - packagesPaths.alpha - ] ), - skipped: new Set( [ - packagesPaths.beta, - packagesPaths.gamma, - packagesPaths.delta, - packagesPaths.epsilon - ] ) - } ); - - stubs.executeOnPackages.callsFake( executeOnPackages ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.beta ).returns( '0.2.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.beta ).returns( '0.2.1' ); - - // Minor release (no minor breaking changes). - stubs.versionUtils.getCurrent.withArgs( packagesPaths.gamma ).returns( '0.3.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.gamma ).returns( '0.4.0' ); - stubs.changelogUtils.hasMinorBreakingChanges.withArgs( '0.4.0', packagesPaths.gamma ).returns( false ); - - // Major release (no major breaking changes). - stubs.versionUtils.getCurrent.withArgs( packagesPaths.epsilon ).returns( '0.5.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.epsilon ).returns( '1.0.0' ); - stubs.changelogUtils.hasMajorBreakingChanges.withArgs( '1.0.0', packagesPaths.epsilon ).returns( false ); - - stubs.getNewReleaseType.resolves( { commits, releaseType: 'skip' } ); - - stubs.cliUtils.provideVersion.resolves( '1.0.0' ); - - stubs.moment.format.returns( '2017-10-09' ); - - stubs.fs.existsSync.returns( true ); - - stubs.changelogUtils.getChangelog.returns( '' ); - - const processChidirStub = sandbox.stub( process, 'chdir' ); - - const options = { - cwd: mainPackagePath, - packages: 'packages', - skipMainRepository: true - }; - - return generateSummaryChangelog( options ) - .then( () => { - /* eslint-disable max-len */ - const expectedNewChangelog = `## [1.0.0](https://github.com/ckeditor/alpha/compare/v0.0.1...v1.0.0) (2017-10-09) - -### Dependencies - -Major releases (dependencies of those packages have breaking changes): - -* [@ckeditor/epsilon](https://www.npmjs.com/package/@ckeditor/epsilon): v0.5.0 => [v1.0.0](https://github.com/ckeditor/epsilon/releases/tag/v1.0.0) - -Minor releases (new features, no breaking changes): - -* [@ckeditor/gamma](https://www.npmjs.com/package/@ckeditor/gamma): v0.3.0 => [v0.4.0](https://github.com/ckeditor/gamma/releases/tag/v0.4.0) - -Patch releases (bug fixes, internal changes): - -* [@ckeditor/beta](https://www.npmjs.com/package/@ckeditor/beta): v0.2.0 => [v0.2.1](https://github.com/ckeditor/beta/releases/tag/v0.2.1) -`; - expect( stubs.transformCommitFunctionFactory.calledOnce ).to.equal( true ); - expect( stubs.transformCommitFunctionFactory.firstCall.args[ 0 ] ).to.deep.equal( { - returnInvalidCommit: true - } ); - - /* eslint-enable max-len */ - expect( stubs.getNewReleaseType.calledOnce ).to.equal( true ); - expect( stubs.getNewReleaseType.firstCall.args[ 0 ] ).to.equal( stubs.transformCommit[ 0 ] ); - expect( stubs.getNewReleaseType.firstCall.args[ 1 ] ).to.deep.equal( { tagName: undefined } ); - - expect( stubs.changelogUtils.saveChangelog.calledOnce ).to.equal( true ); - expect( stubs.changelogUtils.saveChangelog.firstCall.args[ 0 ] ).to.equal( expectedNewChangelog ); - expect( stubs.changelogUtils.saveChangelog.firstCall.args[ 1 ] ).to.equal( packagesPaths.alpha ); - - expect( stubs.cliUtils.provideVersion.firstCall.args[ 0 ] ).to.equal( '0.0.1' ); - - // Major bump was suggested because of packages changes. - expect( stubs.cliUtils.provideVersion.firstCall.args[ 1 ] ).to.equal( 'major' ); - expect( stubs.cliUtils.provideVersion.firstCall.args[ 2 ] ).to.deep.equal( { - disableInternalVersion: true - } ); - - expect( processChidirStub.callCount ).to.equal( 2 ); - expect( processChidirStub.firstCall.args[ 0 ] ).to.equal( packagesPaths.alpha ); - expect( processChidirStub.secondCall.args[ 0 ] ).to.equal( testCwd ); - - expect( stubs.displayGeneratedChangelogs.calledOnce ).to.equal( true ); - - const genetatedChangelogMap = stubs.displayGeneratedChangelogs.firstCall.args[ 0 ]; - - expect( genetatedChangelogMap.has( '@ckeditor/alpha' ) ).to.equal( true ); - expect( stubs.displayCommits.calledOnce ).to.equal( true ); - expect( stubs.displayCommits.firstCall.args[ 0 ] ).to.deep.equal( commits ); - } ); - } ); - - it( 'uses specified version as proposed when asking about it', () => { - const commits = [ {}, {} ]; - - stubs.getSubRepositoriesPaths.returns( { - matched: new Set( [ - packagesPaths.alpha - ] ), - skipped: new Set( [ - packagesPaths.beta, - packagesPaths.gamma, - packagesPaths.delta, - packagesPaths.epsilon - ] ) - } ); - - stubs.executeOnPackages.callsFake( executeOnPackages ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.beta ).returns( '0.2.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.beta ).returns( '0.2.1' ); - - // Minor release (no minor breaking changes). - stubs.versionUtils.getCurrent.withArgs( packagesPaths.gamma ).returns( '0.3.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.gamma ).returns( '0.4.0' ); - stubs.changelogUtils.hasMinorBreakingChanges.withArgs( '0.4.0', packagesPaths.gamma ).returns( false ); - - // Major release (no major breaking changes). - stubs.versionUtils.getCurrent.withArgs( packagesPaths.epsilon ).returns( '0.5.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.epsilon ).returns( '1.0.0' ); - stubs.changelogUtils.hasMajorBreakingChanges.withArgs( '1.0.0', packagesPaths.epsilon ).returns( false ); - - stubs.getNewReleaseType.resolves( { commits, releaseType: 'skip' } ); - - stubs.cliUtils.provideVersion.resolves( '1.0.0' ); - - stubs.moment.format.returns( '2017-10-09' ); - - stubs.fs.existsSync.returns( true ); - - stubs.changelogUtils.getChangelog.returns( '' ); - - const processChidirStub = sandbox.stub( process, 'chdir' ); - - const options = { - cwd: mainPackagePath, - packages: 'packages', - skipMainRepository: true, - version: '1.0.0' - }; - - return generateSummaryChangelog( options ) - .then( () => { - // '1.0.0' bump was suggested because of `options.version`. - expect( stubs.cliUtils.provideVersion.firstCall.args[ 1 ] ).to.equal( '1.0.0' ); - expect( stubs.cliUtils.provideVersion.firstCall.args[ 2 ] ).to.deep.equal( { - disableInternalVersion: true - } ); - - expect( processChidirStub.callCount ).to.equal( 2 ); - } ); - } ); - - it( 'attaches notes from commits in the package', () => { - stubs.getSubRepositoriesPaths.returns( { - matched: new Set( [ - packagesPaths.alpha - ] ), - skipped: new Set( [ - packagesPaths.beta, - packagesPaths.gamma, - packagesPaths.delta, - packagesPaths.epsilon - ] ) - } ); - - stubs.executeOnPackages.callsFake( executeOnPackages ); - - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.alpha ).returns( '0.0.1' ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.beta ).returns( '0.2.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.beta ).returns( '0.2.1' ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.gamma ).returns( '0.3.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.gamma ).returns( '0.3.1' ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.epsilon ).returns( '0.5.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.epsilon ).returns( '0.5.1' ); - - stubs.getNewReleaseType.resolves( { releaseType: 'minor' } ); - - stubs.generateChangelogFromCommits.resolves( - '## [0.1.0](https://github.com/ckeditor/alpha/compare/v0.0.1...v0.1.0) (2017-10-09)\n\n' + - 'Changelog entries generated from commits.\n\n' - ); - - stubs.cliUtils.provideVersion.resolves( '0.1.0' ); - - stubs.moment.format.returns( '2017-10-09' ); - - stubs.fs.existsSync.returns( true ); - - stubs.changelogUtils.getChangelog.returns( '' ); - - const processChidirStub = sandbox.stub( process, 'chdir' ); - - const options = { - cwd: mainPackagePath, - packages: 'packages', - skipMainRepository: true - }; - - return generateSummaryChangelog( options ) - .then( () => { - /* eslint-disable max-len */ - const expectedNewChangelog = `## [0.1.0](https://github.com/ckeditor/alpha/compare/v0.0.1...v0.1.0) (2017-10-09) - -Changelog entries generated from commits. - -### Dependencies - -Patch releases (bug fixes, internal changes): - -* [@ckeditor/beta](https://www.npmjs.com/package/@ckeditor/beta): v0.2.0 => [v0.2.1](https://github.com/ckeditor/beta/releases/tag/v0.2.1) -* [@ckeditor/epsilon](https://www.npmjs.com/package/@ckeditor/epsilon): v0.5.0 => [v0.5.1](https://github.com/ckeditor/epsilon/releases/tag/v0.5.1) -* [@ckeditor/gamma](https://www.npmjs.com/package/@ckeditor/gamma): v0.3.0 => [v0.3.1](https://github.com/ckeditor/gamma/releases/tag/v0.3.1) -`; - /* eslint-enable max-len */ - - expect( stubs.transformCommitFunctionFactory.calledTwice ).to.equal( true ); - expect( stubs.transformCommitFunctionFactory.firstCall.args[ 0 ] ).to.deep.equal( { - returnInvalidCommit: true - } ); - expect( stubs.transformCommitFunctionFactory.secondCall.args ).to.deep.equal( [] ); - - expect( stubs.getNewReleaseType.calledOnce ).to.equal( true ); - expect( stubs.getNewReleaseType.firstCall.args[ 0 ] ).to.equal( stubs.transformCommit[ 0 ] ); - expect( stubs.getNewReleaseType.firstCall.args[ 1 ] ).to.deep.equal( { tagName: 'v0.0.1' } ); - - expect( stubs.changelogUtils.saveChangelog.calledOnce ).to.equal( true ); - expect( stubs.changelogUtils.saveChangelog.firstCall.args[ 0 ] ).to.equal( expectedNewChangelog ); - expect( stubs.changelogUtils.saveChangelog.firstCall.args[ 1 ] ).to.equal( packagesPaths.alpha ); - - expect( stubs.cliUtils.provideVersion.firstCall.args[ 0 ] ).to.equal( '0.0.1' ); - // Minor bump was suggested because of commits. - expect( stubs.cliUtils.provideVersion.firstCall.args[ 1 ] ).to.equal( 'minor' ); - expect( stubs.cliUtils.provideVersion.firstCall.args[ 2 ] ).to.deep.equal( { - disableInternalVersion: true - } ); - - expect( stubs.generateChangelogFromCommits.firstCall.args[ 0 ] ).to.deep.equal( { - version: '0.1.0', - currentTag: 'v0.1.0', - previousTag: 'v0.0.1', - transformCommit: stubs.transformCommit[ 1 ], - isInternalRelease: false, - additionalNotes: true, - doNotSave: true - } ); - - expect( processChidirStub.callCount ).to.equal( 2 ); - expect( processChidirStub.firstCall.args[ 0 ] ).to.equal( packagesPaths.alpha ); - expect( processChidirStub.secondCall.args[ 0 ] ).to.equal( testCwd ); - - expect( stubs.displayGeneratedChangelogs.calledOnce ).to.equal( true ); - - const genetatedChangelogMap = stubs.displayGeneratedChangelogs.firstCall.args[ 0 ]; - - expect( genetatedChangelogMap.has( '@ckeditor/alpha' ) ).to.equal( true ); - } ); - } ); - - it( 'splits major releases as "MAJOR BREAKING CHANGES" and major dependencies update', () => { - stubs.getSubRepositoriesPaths.returns( { - matched: new Set( [ - packagesPaths.omega - ] ), - skipped: new Set( [ - packagesPaths.beta, - packagesPaths.gamma, - packagesPaths.delta, - packagesPaths.epsilon - ] ) - } ); - - stubs.executeOnPackages.callsFake( executeOnPackages ); - - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.omega ).returns( '1.0.0' ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.beta ).returns( '0.2.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.beta ).returns( '1.0.0' ); - stubs.changelogUtils.hasMajorBreakingChanges.withArgs( '1.0.0', packagesPaths.beta ).returns( false ); - stubs.changelogUtils.hasMinorBreakingChanges.withArgs( '1.0.0', packagesPaths.epsilon ).returns( false ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.gamma ).returns( '0.3.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.gamma ).returns( '1.0.0' ); - stubs.changelogUtils.hasMajorBreakingChanges.withArgs( '1.0.0', packagesPaths.gamma ).returns( true ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.epsilon ).returns( '0.5.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.epsilon ).returns( '1.0.0' ); - stubs.changelogUtils.hasMajorBreakingChanges.withArgs( '1.0.0', packagesPaths.epsilon ).returns( false ); - stubs.changelogUtils.hasMinorBreakingChanges.withArgs( '1.0.0', packagesPaths.epsilon ).returns( true ); - - stubs.getNewReleaseType.resolves( { releaseType: 'major' } ); - - stubs.generateChangelogFromCommits.resolves( - '## [2.0.0](https://github.com/ckeditor/omega/compare/v1.0.0...v2.0.0) (2017-10-09)\n\n' + - 'Changelog entries generated from commits.\n\n' - ); - - stubs.cliUtils.provideVersion.resolves( '2.0.0' ); - - stubs.moment.format.returns( '2017-10-09' ); - - stubs.fs.existsSync.returns( true ); - - stubs.changelogUtils.getChangelog.returns( '' ); - - const processChidirStub = sandbox.stub( process, 'chdir' ); - - const options = { - cwd: mainPackagePath, - packages: 'packages', - skipMainRepository: true - }; - - return generateSummaryChangelog( options ) - .then( () => { - /* eslint-disable max-len */ - const expectedNewChangelog = `## [2.0.0](https://github.com/ckeditor/omega/compare/v1.0.0...v2.0.0) (2017-10-09) - -Changelog entries generated from commits. - -### Dependencies - -Major releases (contain major breaking changes): - -* [@ckeditor/gamma](https://www.npmjs.com/package/@ckeditor/gamma): v0.3.0 => [v1.0.0](https://github.com/ckeditor/gamma/releases/tag/v1.0.0) - -Major releases (contain minor breaking changes): - -* [@ckeditor/epsilon](https://www.npmjs.com/package/@ckeditor/epsilon): v0.5.0 => [v1.0.0](https://github.com/ckeditor/epsilon/releases/tag/v1.0.0) - -Major releases (dependencies of those packages have breaking changes): - -* [@ckeditor/beta](https://www.npmjs.com/package/@ckeditor/beta): v0.2.0 => [v1.0.0](https://github.com/ckeditor/beta/releases/tag/v1.0.0) -`; - /* eslint-enable max-len */ - expect( stubs.transformCommitFunctionFactory.calledTwice ).to.equal( true ); - expect( stubs.transformCommitFunctionFactory.firstCall.args[ 0 ] ).to.deep.equal( { - returnInvalidCommit: true - } ); - expect( stubs.transformCommitFunctionFactory.secondCall.args ).to.deep.equal( [] ); - - expect( stubs.getNewReleaseType.calledOnce ).to.equal( true ); - expect( stubs.getNewReleaseType.firstCall.args[ 0 ] ).to.equal( stubs.transformCommit[ 0 ] ); - expect( stubs.getNewReleaseType.firstCall.args[ 1 ] ).to.deep.equal( { tagName: 'v1.0.0' } ); - - expect( stubs.changelogUtils.saveChangelog.calledOnce ).to.equal( true ); - expect( stubs.changelogUtils.saveChangelog.firstCall.args[ 0 ] ).to.equal( expectedNewChangelog ); - expect( stubs.changelogUtils.saveChangelog.firstCall.args[ 1 ] ).to.equal( packagesPaths.omega ); - - expect( stubs.cliUtils.provideVersion.firstCall.args[ 0 ] ).to.equal( '1.0.0' ); - // Minor bump was suggested because of commits. - expect( stubs.cliUtils.provideVersion.firstCall.args[ 1 ] ).to.equal( 'major' ); - expect( stubs.cliUtils.provideVersion.firstCall.args[ 2 ] ).to.deep.equal( { - disableInternalVersion: true - } ); - - expect( stubs.generateChangelogFromCommits.firstCall.args[ 0 ] ).to.deep.equal( { - version: '2.0.0', - currentTag: 'v2.0.0', - previousTag: 'v1.0.0', - transformCommit: stubs.transformCommit[ 1 ], - isInternalRelease: false, - additionalNotes: true, - doNotSave: true - } ); - - expect( processChidirStub.callCount ).to.equal( 2 ); - expect( processChidirStub.firstCall.args[ 0 ] ).to.equal( packagesPaths.omega ); - expect( processChidirStub.secondCall.args[ 0 ] ).to.equal( testCwd ); - - expect( stubs.displayGeneratedChangelogs.calledOnce ).to.equal( true ); - - const genetatedChangelogMap = stubs.displayGeneratedChangelogs.firstCall.args[ 0 ]; - - expect( genetatedChangelogMap.has( '@ckeditor/omega' ) ).to.equal( true ); - } ); - } ); - - it( 'splits minor releases as "MINOR BREAKING CHANGES" and new features', () => { - stubs.getSubRepositoriesPaths.returns( { - matched: new Set( [ - packagesPaths.omega - ] ), - skipped: new Set( [ - packagesPaths.beta, - packagesPaths.gamma, - packagesPaths.delta, - packagesPaths.epsilon - ] ) - } ); - - stubs.executeOnPackages.callsFake( executeOnPackages ); - - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.omega ).returns( '1.0.0' ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.beta ).returns( '0.2.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.beta ).returns( '0.3.0' ); - stubs.changelogUtils.hasMinorBreakingChanges.withArgs( '0.3.0', packagesPaths.beta ).returns( false ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.gamma ).returns( '0.3.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.gamma ).returns( '0.4.0' ); - stubs.changelogUtils.hasMinorBreakingChanges.withArgs( '0.4.0', packagesPaths.gamma ).returns( false ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.epsilon ).returns( '0.5.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.epsilon ).returns( '0.6.0' ); - stubs.changelogUtils.hasMinorBreakingChanges.withArgs( '0.6.0', packagesPaths.epsilon ).returns( true ); - - stubs.getNewReleaseType.resolves( { releaseType: 'minor' } ); - - stubs.generateChangelogFromCommits.resolves( - '## [1.1.0](https://github.com/ckeditor/omega/compare/v1.0.0...v1.1.0) (2017-10-09)\n\n' + - 'Changelog entries generated from commits.\n\n' - ); - - stubs.cliUtils.provideVersion.resolves( '1.1.0' ); - - stubs.moment.format.returns( '2017-10-09' ); - - stubs.fs.existsSync.returns( true ); - - stubs.changelogUtils.getChangelog.returns( '' ); - - const processChidirStub = sandbox.stub( process, 'chdir' ); - - const options = { - cwd: mainPackagePath, - packages: 'packages', - skipMainRepository: true - }; - - return generateSummaryChangelog( options ) - .then( () => { - /* eslint-disable max-len */ - const expectedNewChangelog = `## [1.1.0](https://github.com/ckeditor/omega/compare/v1.0.0...v1.1.0) (2017-10-09) - -Changelog entries generated from commits. - -### Dependencies - -Minor releases (containing minor breaking changes): - -* [@ckeditor/epsilon](https://www.npmjs.com/package/@ckeditor/epsilon): v0.5.0 => [v0.6.0](https://github.com/ckeditor/epsilon/releases/tag/v0.6.0) - -Minor releases (new features, no breaking changes): - -* [@ckeditor/beta](https://www.npmjs.com/package/@ckeditor/beta): v0.2.0 => [v0.3.0](https://github.com/ckeditor/beta/releases/tag/v0.3.0) -* [@ckeditor/gamma](https://www.npmjs.com/package/@ckeditor/gamma): v0.3.0 => [v0.4.0](https://github.com/ckeditor/gamma/releases/tag/v0.4.0) -`; - /* eslint-enable max-len */ - expect( stubs.transformCommitFunctionFactory.calledTwice ).to.equal( true ); - expect( stubs.transformCommitFunctionFactory.firstCall.args[ 0 ] ).to.deep.equal( { - returnInvalidCommit: true - } ); - expect( stubs.transformCommitFunctionFactory.secondCall.args ).to.deep.equal( [] ); - - expect( stubs.getNewReleaseType.calledOnce ).to.equal( true ); - expect( stubs.getNewReleaseType.firstCall.args[ 0 ] ).to.equal( stubs.transformCommit[ 0 ] ); - expect( stubs.getNewReleaseType.firstCall.args[ 1 ] ).to.deep.equal( { tagName: 'v1.0.0' } ); - - expect( stubs.changelogUtils.saveChangelog.calledOnce ).to.equal( true ); - expect( stubs.changelogUtils.saveChangelog.firstCall.args[ 0 ] ).to.equal( expectedNewChangelog ); - expect( stubs.changelogUtils.saveChangelog.firstCall.args[ 1 ] ).to.equal( packagesPaths.omega ); - - expect( stubs.cliUtils.provideVersion.firstCall.args[ 0 ] ).to.equal( '1.0.0' ); - // Minor bump was suggested because of commits. - expect( stubs.cliUtils.provideVersion.firstCall.args[ 1 ] ).to.equal( 'minor' ); - expect( stubs.cliUtils.provideVersion.firstCall.args[ 2 ] ).to.deep.equal( { - disableInternalVersion: true - } ); - - expect( stubs.generateChangelogFromCommits.firstCall.args[ 0 ] ).to.deep.equal( { - version: '1.1.0', - currentTag: 'v1.1.0', - previousTag: 'v1.0.0', - transformCommit: stubs.transformCommit[ 1 ], - isInternalRelease: false, - additionalNotes: true, - doNotSave: true - } ); - - expect( processChidirStub.callCount ).to.equal( 2 ); - expect( processChidirStub.firstCall.args[ 0 ] ).to.equal( packagesPaths.omega ); - expect( processChidirStub.secondCall.args[ 0 ] ).to.equal( testCwd ); - - expect( stubs.displayGeneratedChangelogs.calledOnce ).to.equal( true ); - - const genetatedChangelogMap = stubs.displayGeneratedChangelogs.firstCall.args[ 0 ]; - - expect( genetatedChangelogMap.has( '@ckeditor/omega' ) ).to.equal( true ); - } ); - } ); - - it( 'handles MAJOR/MINOR changes for initial release', () => { - stubs.getSubRepositoriesPaths.returns( { - matched: new Set( [ - packagesPaths.alpha - ] ), - skipped: new Set( [ - packagesPaths.beta, - packagesPaths.gamma, - packagesPaths.delta, - packagesPaths.epsilon - ] ) - } ); - - stubs.executeOnPackages.callsFake( executeOnPackages ); - - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.alpha ).returns( '0.0.1' ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.beta ).returns( '0.2.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.beta ).returns( '0.3.0' ); - stubs.changelogUtils.hasMinorBreakingChanges.withArgs( '0.3.0', packagesPaths.beta ).returns( true ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.gamma ).returns( '0.3.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.gamma ).returns( '0.4.0' ); - stubs.changelogUtils.hasMajorBreakingChanges.withArgs( '0.4.0', packagesPaths.gamma ).returns( false ); - stubs.changelogUtils.hasMinorBreakingChanges.withArgs( '0.4.0', packagesPaths.gamma ).returns( false ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.epsilon ).returns( '0.5.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.epsilon ).returns( '0.6.0' ); - stubs.changelogUtils.hasMajorBreakingChanges.withArgs( '0.6.0', packagesPaths.epsilon ).returns( false ); - stubs.changelogUtils.hasMinorBreakingChanges.withArgs( '0.6.0', packagesPaths.epsilon ).returns( true ); - - stubs.getNewReleaseType.resolves( { releaseType: 'minor' } ); - - stubs.generateChangelogFromCommits.resolves( - '## [0.1.0](https://github.com/ckeditor/alpha/compare/v0.0.1...v0.1.0) (2017-10-09)\n\n' + - 'Changelog entries generated from commits.\n\n' - ); - - stubs.cliUtils.provideVersion.resolves( '0.1.0' ); - - stubs.moment.format.returns( '2017-10-09' ); - - stubs.fs.existsSync.returns( true ); - - stubs.changelogUtils.getChangelog.returns( '' ); - - const processChidirStub = sandbox.stub( process, 'chdir' ); - - const options = { - cwd: mainPackagePath, - packages: 'packages', - skipMainRepository: true - }; - - return generateSummaryChangelog( options ) - .then( () => { - /* eslint-disable max-len */ - const expectedNewChangelog = `## [0.1.0](https://github.com/ckeditor/alpha/compare/v0.0.1...v0.1.0) (2017-10-09) - -Changelog entries generated from commits. - -### Dependencies - -Minor releases (containing major/minor breaking changes): - -* [@ckeditor/beta](https://www.npmjs.com/package/@ckeditor/beta): v0.2.0 => [v0.3.0](https://github.com/ckeditor/beta/releases/tag/v0.3.0) -* [@ckeditor/epsilon](https://www.npmjs.com/package/@ckeditor/epsilon): v0.5.0 => [v0.6.0](https://github.com/ckeditor/epsilon/releases/tag/v0.6.0) - -Minor releases (new features, no breaking changes): - -* [@ckeditor/gamma](https://www.npmjs.com/package/@ckeditor/gamma): v0.3.0 => [v0.4.0](https://github.com/ckeditor/gamma/releases/tag/v0.4.0) -`; - /* eslint-enable max-len */ - expect( stubs.transformCommitFunctionFactory.calledTwice ).to.equal( true ); - expect( stubs.transformCommitFunctionFactory.firstCall.args[ 0 ] ).to.deep.equal( { - returnInvalidCommit: true - } ); - expect( stubs.transformCommitFunctionFactory.secondCall.args ).to.deep.equal( [] ); - - // There is no "major" bump so the function should be never called. - expect( stubs.changelogUtils.hasMajorBreakingChanges.called ).to.equal( false ); - - expect( stubs.getNewReleaseType.calledOnce ).to.equal( true ); - expect( stubs.getNewReleaseType.firstCall.args[ 0 ] ).to.equal( stubs.transformCommit[ 0 ] ); - expect( stubs.getNewReleaseType.firstCall.args[ 1 ] ).to.deep.equal( { tagName: 'v0.0.1' } ); - - expect( stubs.changelogUtils.saveChangelog.calledOnce ).to.equal( true ); - expect( stubs.changelogUtils.saveChangelog.firstCall.args[ 0 ] ).to.equal( expectedNewChangelog ); - expect( stubs.changelogUtils.saveChangelog.firstCall.args[ 1 ] ).to.equal( packagesPaths.alpha ); - - expect( stubs.cliUtils.provideVersion.firstCall.args[ 0 ] ).to.equal( '0.0.1' ); - // Minor bump was suggested because of commits. - expect( stubs.cliUtils.provideVersion.firstCall.args[ 1 ] ).to.equal( 'minor' ); - expect( stubs.cliUtils.provideVersion.firstCall.args[ 2 ] ).to.deep.equal( { - disableInternalVersion: true - } ); - - expect( stubs.generateChangelogFromCommits.firstCall.args[ 0 ] ).to.deep.equal( { - version: '0.1.0', - currentTag: 'v0.1.0', - previousTag: 'v0.0.1', - transformCommit: stubs.transformCommit[ 1 ], - isInternalRelease: false, - additionalNotes: true, - doNotSave: true - } ); - - expect( processChidirStub.callCount ).to.equal( 2 ); - expect( processChidirStub.firstCall.args[ 0 ] ).to.equal( packagesPaths.alpha ); - expect( processChidirStub.secondCall.args[ 0 ] ).to.equal( testCwd ); - - expect( stubs.displayGeneratedChangelogs.calledOnce ).to.equal( true ); - - const genetatedChangelogMap = stubs.displayGeneratedChangelogs.firstCall.args[ 0 ]; - - expect( genetatedChangelogMap.has( '@ckeditor/alpha' ) ).to.equal( true ); - } ); - } ); - - it( 'allows generating changelog for main repository', () => { - const commits = [ {}, {} ]; - - stubs.getSubRepositoriesPaths.returns( { - matched: new Set(), - skipped: new Set( [ - packagesPaths.alpha, - packagesPaths.beta, - packagesPaths.gamma, - packagesPaths.delta, - packagesPaths.epsilon, - packagesPaths.devKappa - ] ) - } ); - - stubs.executeOnPackages.callsFake( executeOnPackages ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.alpha ).returns( '0.0.1' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.alpha ).returns( '0.1.0' ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.beta ).returns( '0.2.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.beta ).returns( '0.2.1' ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.gamma ).returns( '0.3.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.gamma ).returns( '0.3.1' ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.delta ).returns( '0.4.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.delta ).returns( '0.4.1' ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.epsilon ).returns( '0.5.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.epsilon ).returns( '0.5.1' ); - - stubs.getNewReleaseType.resolves( { commits, releaseType: 'minor' } ); - - stubs.generateChangelogFromCommits.resolves( - '## [0.2.0](https://github.com/ckeditor/foo-bar/compare/v0.1.0...v0.2.0) (2017-10-09)\n\n' + - 'Changelog entries generated from commits.\n\n' - ); - - stubs.cliUtils.provideVersion.resolves( '0.2.0' ); - - stubs.moment.format.returns( '2017-10-09' ); - - stubs.fs.existsSync.returns( true ); - - stubs.changelogUtils.getChangelog.returns( '' ); - - const processChidirStub = sandbox.stub( process, 'chdir' ); - - const options = { - cwd: mainPackagePath, - packages: 'packages' - }; - - return generateSummaryChangelog( options ) - .then( () => { - /* eslint-disable max-len */ - const expectedNewChangelog = `## [0.2.0](https://github.com/ckeditor/foo-bar/compare/v0.1.0...v0.2.0) (2017-10-09) - -Changelog entries generated from commits. - -### Dependencies - -New packages: - -* [@ckeditor/alpha](https://www.npmjs.com/package/@ckeditor/alpha): [v0.1.0](https://github.com/ckeditor/alpha/releases/tag/v0.1.0) - -Patch releases (bug fixes, internal changes): - -* [@ckeditor/beta](https://www.npmjs.com/package/@ckeditor/beta): v0.2.0 => [v0.2.1](https://github.com/ckeditor/beta/releases/tag/v0.2.1) -* [@ckeditor/delta](https://www.npmjs.com/package/@ckeditor/delta): v0.4.0 => [v0.4.1](https://github.com/ckeditor/delta/releases/tag/v0.4.1) -* [@ckeditor/epsilon](https://www.npmjs.com/package/@ckeditor/epsilon): v0.5.0 => [v0.5.1](https://github.com/ckeditor/epsilon/releases/tag/v0.5.1) -* [@ckeditor/gamma](https://www.npmjs.com/package/@ckeditor/gamma): v0.3.0 => [v0.3.1](https://github.com/ckeditor/gamma/releases/tag/v0.3.1) -`; - /* eslint-enable max-len */ - expect( stubs.transformCommitFunctionFactory.calledTwice ).to.equal( true ); - expect( stubs.transformCommitFunctionFactory.firstCall.args[ 0 ] ).to.deep.equal( { - returnInvalidCommit: true - } ); - expect( stubs.transformCommitFunctionFactory.secondCall.args ).to.deep.equal( [] ); - - expect( stubs.changelogUtils.saveChangelog.calledOnce ).to.equal( true ); - expect( stubs.changelogUtils.saveChangelog.firstCall.args[ 0 ] ).to.equal( expectedNewChangelog ); - expect( stubs.changelogUtils.saveChangelog.firstCall.args[ 1 ] ).to.equal( mainPackagePath ); - - expect( processChidirStub.callCount ).to.equal( 2 ); - - expect( processChidirStub.firstCall.args[ 0 ] ).to.equal( mainPackagePath ); - expect( processChidirStub.secondCall.args[ 0 ] ).to.equal( testCwd ); - - expect( stubs.displayCommits.calledOnce ).to.equal( true ); - expect( stubs.displayCommits.firstCall.args[ 0 ] ).to.deep.equal( commits ); - } ); - } ); - - it( 'allows restricting the packages scope', () => { - stubs.getSubRepositoriesPaths.returns( { - matched: new Set(), - skipped: new Set() - } ); - - stubs.executeOnPackages.resolves(); - - const skipPackages = [ 'some-pacakge' ]; - const scope = /some-regexp/; - - const options = { - cwd: mainPackagePath, - packages: 'packages', - skipPackages, - scope - }; - - return generateSummaryChangelog( options ) - .then( () => { - expect( stubs.getSubRepositoriesPaths.firstCall.args[ 0 ] ).to.deep.equal( { - cwd: options.cwd, - packages: options.packages, - skipMainRepository: true, - skipPackages, - scope - } ); - } ); - } ); - - it( 'does not generate the changelog if user provides "skip" as new version', () => { - stubs.getSubRepositoriesPaths.returns( { - matched: new Set( [ - packagesPaths.alpha - ] ), - skipped: new Set( [ - packagesPaths.beta, - packagesPaths.gamma, - packagesPaths.delta, - packagesPaths.epsilon - ] ) - } ); - - stubs.executeOnPackages.callsFake( executeOnPackages ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.beta ).returns( '0.2.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.beta ).returns( '0.2.1' ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.gamma ).returns( '0.3.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.gamma ).returns( '0.4.0' ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.epsilon ).returns( '0.5.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.epsilon ).returns( '0.1.0' ); - - stubs.getNewReleaseType.resolves( { releaseType: 'skip' } ); - - stubs.cliUtils.provideVersion.resolves( 'skip' ); - - const processChidirStub = sandbox.stub( process, 'chdir' ); - - const options = { - cwd: mainPackagePath, - packages: 'packages', - skipMainRepository: true - }; - - return generateSummaryChangelog( options ) - .then( () => { - expect( stubs.changelogUtils.saveChangelog.called ).to.equal( false ); - expect( processChidirStub.callCount ).to.equal( 2 ); - expect( processChidirStub.firstCall.args[ 0 ] ).to.equal( packagesPaths.alpha ); - expect( processChidirStub.secondCall.args[ 0 ] ).to.equal( testCwd ); - - expect( stubs.displayGeneratedChangelogs.called ).to.equal( true ); - expect( stubs.displayGeneratedChangelogs.firstCall.args[ 0 ].size ).to.equal( 0 ); - } ); - } ); - - it( 'does not attach the "Dependencies" header if any dependency has not been added or changed', () => { - stubs.getSubRepositoriesPaths.returns( { - matched: new Set( [ - packagesPaths.alpha - ] ), - skipped: new Set( [ - packagesPaths.beta, - packagesPaths.gamma, - packagesPaths.delta, - packagesPaths.epsilon - ] ) - } ); - - stubs.executeOnPackages.callsFake( executeOnPackages ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.beta ).returns( '0.2.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.beta ).returns( '0.2.0' ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.gamma ).returns( '0.3.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.gamma ).returns( '0.3.0' ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.epsilon ).returns( '0.5.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.epsilon ).returns( '0.5.0' ); - - stubs.getNewReleaseType.resolves( { releaseType: 'skip' } ); - - stubs.cliUtils.provideVersion.resolves( '1.0.0' ); - - stubs.moment.format.returns( '2017-10-09' ); - - stubs.fs.existsSync.returns( true ); - - stubs.changelogUtils.getChangelog.returns( '' ); - - sandbox.stub( process, 'chdir' ); - - const options = { - cwd: mainPackagePath, - packages: 'packages', - skipMainRepository: true - }; - - return generateSummaryChangelog( options ) - .then( () => { - const expectedNewChangelog = '## [1.0.0](https://github.com/ckeditor/alpha/compare/v0.0.1...v1.0.0) (2017-10-09)\n'; - - expect( stubs.changelogUtils.saveChangelog.calledOnce ).to.equal( true ); - expect( stubs.changelogUtils.saveChangelog.firstCall.args[ 0 ] ).to.equal( expectedNewChangelog ); - expect( stubs.changelogUtils.saveChangelog.firstCall.args[ 1 ] ).to.equal( packagesPaths.alpha ); - } ); - } ); - - describe( 'additional notes for group of commits', () => { - it( 'are visible when dependencies have been added or changed', () => { - stubs.getSubRepositoriesPaths.returns( { - matched: new Set(), - skipped: new Set( [ - packagesPaths.alpha, - packagesPaths.beta, - packagesPaths.gamma, - packagesPaths.delta, - packagesPaths.epsilon - ] ) - } ); - - stubs.executeOnPackages.callsFake( executeOnPackages ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.alpha ).returns( '0.0.1' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.alpha ).returns( '0.1.0' ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.beta ).returns( '0.2.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.beta ).returns( '0.2.1' ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.gamma ).returns( '0.3.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.gamma ).returns( '0.3.1' ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.delta ).returns( '0.4.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.delta ).returns( '0.4.1' ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.epsilon ).returns( '0.5.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.epsilon ).returns( '0.5.1' ); - - stubs.getNewReleaseType.resolves( { releaseType: 'minor' } ); - - stubs.generateChangelogFromCommits.resolves( - '## Changelog header (will be removed)\n\n' + - 'Changelog entries generated from commits.\n\n' - ); - - stubs.cliUtils.provideVersion.resolves( '0.2.0' ); - - stubs.moment.format.returns( '2017-10-09' ); - - stubs.fs.existsSync.returns( true ); - - stubs.changelogUtils.getChangelog.returns( '' ); - - sandbox.stub( process, 'chdir' ); - - const options = { - cwd: mainPackagePath, - packages: 'packages' - }; - - return generateSummaryChangelog( options ) - .then( () => { - expect( stubs.generateChangelogFromCommits.firstCall.args[ 0 ] ).to.have.property( 'additionalNotes', true ); - } ); - } ); - - it( 'are hidden when dependencies have not been added or changed', () => { - stubs.getSubRepositoriesPaths.returns( { - matched: new Set(), - skipped: new Set( [ - packagesPaths.alpha, - packagesPaths.beta, - packagesPaths.gamma, - packagesPaths.delta, - packagesPaths.epsilon - ] ) - } ); - - stubs.executeOnPackages.callsFake( executeOnPackages ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.alpha ).returns( '0.0.1' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.alpha ).returns( '0.0.1' ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.beta ).returns( '0.2.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.beta ).returns( '0.2.0' ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.gamma ).returns( '0.3.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.gamma ).returns( '0.3.0' ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.delta ).returns( '0.4.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.delta ).returns( '0.4.0' ); - - stubs.versionUtils.getCurrent.withArgs( packagesPaths.epsilon ).returns( '0.5.0' ); - stubs.versionUtils.getLastFromChangelog.withArgs( packagesPaths.epsilon ).returns( '0.5.0' ); - - stubs.getNewReleaseType.resolves( { releaseType: 'minor' } ); - - stubs.generateChangelogFromCommits.resolves( - '## Changelog header (will be removed)\n\n' + - 'Changelog entries generated from commits.\n\n' - ); - - stubs.cliUtils.provideVersion.resolves( '0.2.0' ); - - stubs.moment.format.returns( '2017-10-09' ); - - stubs.fs.existsSync.returns( true ); - - stubs.changelogUtils.getChangelog.returns( '' ); - - sandbox.stub( process, 'chdir' ); - - const options = { - cwd: mainPackagePath, - packages: 'packages' - }; - - return generateSummaryChangelog( options ) - .then( () => { - expect( stubs.generateChangelogFromCommits.firstCall.args[ 0 ] ).to.have.property( 'additionalNotes', false ); - } ); - } ); - } ); - } ); -} ); From 93a372288273d28315d85af052d8ad220e15d27b Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Wed, 13 May 2020 11:22:53 +0200 Subject: [PATCH 05/33] Rewritten the "generateChangelogForSinglePackage()" function. --- package.json | 2 +- .../generatechangelogformonorepository.js | 15 +- .../generatechangelogforsinglepackage.js | 226 +++++++++++------- .../lib/release-tools/utils/changelog.js | 34 --- .../lib/release-tools/utils/getcommits.js | 4 +- .../release-tools/utils/getnewreleasetype.js | 45 +--- .../release-tools/utils/getnewversiontype.js | 24 +- .../release-tools/utils/releaserepository.js | 81 ------- .../transformcommitforsubrepositoryfactory.js | 2 +- .../tests/release-tools/utils/changelog.js | 104 -------- .../release-tools/utils/releaserepository.js | 151 ------------ 11 files changed, 172 insertions(+), 516 deletions(-) delete mode 100644 packages/ckeditor5-dev-env/lib/release-tools/utils/releaserepository.js delete mode 100644 packages/ckeditor5-dev-env/tests/release-tools/utils/releaserepository.js diff --git a/package.json b/package.json index 4b4c32852..0b4f8323e 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "bugs": "https://github.com/ckeditor/ckeditor5-dev/issues", "homepage": "https://github.com/ckeditor/ckeditor5-dev#readme", "scripts": { - "test": "mocha packages/*/tests --recursive --timeout 5000", + "test": "mocha packages/ckeditor5-dev-env/tests --recursive --timeout 5000", "coverage": "istanbul cover _mocha packages/*/tests -- --recursive --timeout 5000", "changelog": "node ./scripts/changelog.js", "lint": "eslint --quiet '**/*.js'", diff --git a/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogformonorepository.js b/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogformonorepository.js index 618356ad9..f13d4802e 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogformonorepository.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogformonorepository.js @@ -7,8 +7,8 @@ const path = require( 'path' ); const { Readable } = require( 'stream' ); -const compareFunc = require( 'compare-func' ); const { tools, stream, logger } = require( '@ckeditor/ckeditor5-dev-utils' ); +const compareFunc = require( 'compare-func' ); const conventionalChangelogWriter = require( 'conventional-changelog-writer' ); const chalk = require( 'chalk' ); const minimatch = require( 'minimatch' ); @@ -32,14 +32,23 @@ const noteInfo = `[ℹ️](${ VERSIONING_POLICY_URL }#major-and-minor-breaking-c * Generates the changelog for the mono repository. * * @param {Object} options + * * @param {String} options.cwd Current working directory (packages) from which all paths will be resolved. + * * @param {String} options.packages Where to look for packages. + * * @param {Function} options.transformScope A function that returns a URL to a package from a scope of a commit. + * * @param {String} [options.scope] Package names have to match to specified glob pattern in order to be processed. + * * @param {Array.} [options.skipPackages=[]] Name of packages which won't be touched. + * * @param {String} [options.from] A commit or tag name that will be the first param of the range of commits to collect. + * * @param {Boolean} [options.highlightsPlaceholder=false] Whether to add a note about release highlights. + * * @param {Boolean} [options.collaborationFeatures=false] Whether to add a note about collaboration features. + * * @returns {Promise} */ module.exports = function generateChangelogForMonoRepository( options ) { @@ -231,7 +240,9 @@ module.exports = function generateChangelogForMonoRepository( options ) { logInfo( `Processing "${ chalk.underline( pkgJson.name ) }"...`, { indentLevel: 1, startWithNewLine: true } ); const packageCommits = filterCommitsByPath( allCommits, packagePath ); - const releaseTypeOrVersion = willBeMajorBump ? nextVersion : getNewVersionType( packageCommits ); + const releaseTypeOrVersion = willBeMajorBump ? nextVersion : getNewVersionType( packageCommits, { + useExplicitBreakingChangeGroups: true + } ); displayCommits( packageCommits, { indentLevel: 2 } ); diff --git a/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogforsinglepackage.js b/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogforsinglepackage.js index b67086c11..a931355ca 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogforsinglepackage.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogforsinglepackage.js @@ -5,138 +5,186 @@ 'use strict'; +const { Readable } = require( 'stream' ); +const { tools, stream, logger } = require( '@ckeditor/ckeditor5-dev-utils' ); const chalk = require( 'chalk' ); +const conventionalChangelogWriter = require( 'conventional-changelog-writer' ); const semver = require( 'semver' ); -const { tools, logger } = require( '@ckeditor/ckeditor5-dev-utils' ); const cli = require( '../utils/cli' ); -const versionUtils = require( '../utils/versions' ); const changelogUtils = require( '../utils/changelog' ); const displayCommits = require( '../utils/displaycommits' ); const getPackageJson = require( '../utils/getpackagejson' ); -const getNewReleaseType = require( '../utils/getnewreleasetype' ); -const generateChangelogFromCommits = require( '../utils/generatechangelogfromcommits' ); +const getNewVersionType = require( '../utils/getnewversiontype' ); +const getCommits = require( '../utils/getcommits' ); +const getWriterOptions = require( '../utils/transform-commit/getwriteroptions' ); +const { getRepositoryUrl } = require( '../utils/transform-commit/transform-commit-utils' ); const transformCommitForSubRepositoryFactory = require( '../utils/transform-commit/transformcommitforsubrepositoryfactory' ); -const VALID_SEMVER_INCREMENT_LEVEL = [ - 'major', - 'minor', - 'patch', - 'premajor', - 'preminor', - 'prepatch', - 'prerelease' -]; - /** - * Generates the release changelog based on commit messages in a package that is located under current work directory (cwd). - * - * A new version that should be printed in the changelog can be specified under `options.newVersion` option. - * It accepts the new version (e.g. "1.0.0") or a level that describes how to increase a current version of the package, - * e.g.: "major". It means that the tool will suggest a major version bump while asking about the new version. - * - * If the new version is not specified, the tool will print all commits and user must type the new version manually. + * Generates the changelog based on commit messages in a package that is located under current work directory (cwd). * * If the package does not have any commit, the user has to confirm whether the changelog should be generated. * * @param {Object} [options={}] Additional options. - * @param {String} [options.newVersion=null] A version or a type of increase level for the current version - * for which changelog will be generated. + * * @param {Boolean} [options.skipLinks=false] If set on true, links to release or commits will be omitted. - * @param {Boolean} [options.disableMajorBump=false] If set on true, detected breaking change won't bump the major version. - * @param {Boolean} [options.isInternalRelease=false] If set on true, the changelog will contain a note about internal release - * instead of data that comes from commits. - * @param {Number} [options.indentLevel=0] The indent level. This function could be used inside another (bigger) script. If we would like to - * display indents logs, we need to increase/decrease indent level manually. - * @param {Boolean} [options.useExplicitBreakingChangeGroups] If set on `true`, notes from parsed commits will be grouped as - * "MINOR BREAKING CHANGES" and "MAJOR BREAKING CHANGES'. If set on `false` (by default), all breaking changes notes will be treated - * as "BREAKING CHANGES". + * + * @param {String} [options.from] A commit or tag name that will be the first param of the range of commits to collect. + * + * @param {Boolean} [options.highlightsPlaceholder=false] Whether to add a note about release highlights. + * + * @param {Boolean} [options.collaborationFeatures=false] Whether to add a note about collaboration features. + * * @returns {Promise} */ module.exports = function generateChangelogForSinglePackage( options = {} ) { const log = logger(); const packageJson = getPackageJson(); - const indentLevel = options.indentLevel || 0; - const indent = ' '.repeat( indentLevel * cli.INDENT_SIZE ); - let tagName = versionUtils.getLastFromChangelog(); + logProcess( chalk.bold( `Generating changelog for "${ chalk.underline( packageJson.name ) }"...` ) ); + + const transformCommit = transformCommitForSubRepositoryFactory( { + returnInvalidCommit: true + } ); + + logProcess( 'Collecting all commits since the last release...' ); - if ( tagName ) { - tagName = 'v' + tagName; + const commitOptions = { + from: options.from ? options.from : 'v' + packageJson.version + }; + + // Initial release. + if ( semver.eq( packageJson.version, '0.0.1' ) ) { + commitOptions.from = null; } - let isInternalRelease = options.isInternalRelease || false; - const newVersion = options.newVersion || null; - - log.info( '\n' + indent + chalk.bold( `Generating changelog for "${ chalk.underline( packageJson.name ) }"...` ) ); - - let promise = Promise.resolve(); - - // For the internal release, the user does not have to confirm anything. The internal release is called automatically - // when changelogs of package's dependencies have been changed. We mark the package as "ready to release" - // in order to update versions of the dependencies. - if ( isInternalRelease ) { - if ( VALID_SEMVER_INCREMENT_LEVEL.includes( newVersion ) ) { - promise = promise.then( () => semver.inc( packageJson.version, newVersion ) ); - } else if ( semver.valid( newVersion ) ) { - promise = promise.then( () => newVersion ); - } else { - return Promise.reject( new Error( - `If "isInternalRelease" is set on true, "newVersion" must be a version or increment level. Given "${ newVersion }".` - ) ); - } - } else { - const transformCommitFunction = transformCommitForSubRepositoryFactory( { - treatMajorAsMinorBreakingChange: options.disableMajorBump, - returnInvalidCommit: true, - useExplicitBreakingChangeGroups: !!options.useExplicitBreakingChangeGroups - } ); + // Collection of all entries (real commits + additional "fake" commits extracted from descriptions). + let allCommits; - promise = promise - .then( () => getNewReleaseType( transformCommitFunction, { tagName } ) ) - .then( result => { - displayCommits( result.commits, { indentLevel: indentLevel + 1 } ); + // A new version inserted into the changelog. + let newVersion; - const releaseTypeOrVersion = semver.valid( newVersion ) ? newVersion : result.releaseType; + return getCommits( transformCommit, commitOptions ) + .then( commits => { + allCommits = commits; - return cli.provideVersion( packageJson.version, releaseTypeOrVersion, { indentLevel } ); - } ); - } + logInfo( `Found ${ commits.length } entries to parse.`, { indentLevel: 1 } ); + } ) + .then( () => { + logProcess( 'Preparing new version for the package...' ); + + const releaseType = getNewVersionType( allCommits ); - return promise + displayCommits( allCommits, { indentLevel: 1 } ); + + return cli.provideVersion( packageJson.version, releaseType, { indentLevel: 1 } ); + } ) .then( version => { if ( version === 'skip' ) { return Promise.resolve(); } - // If the user provided "internal" as a new version, we treat it as a "patch" bump. + const isInternalRelease = version === 'internal'; + if ( version === 'internal' ) { - isInternalRelease = true; version = semver.inc( packageJson.version, 'patch' ); } - const changelogOptions = { + newVersion = version; + + logProcess( 'Generating the changelog...' ); + + const commitStream = new Readable( { objectMode: true } ); + commitStream._read = function() {}; + + const previousTag = commitOptions.from ? 'v' + packageJson.version : null; + + const writerContext = { version, - tagName, + commit: 'commit', + repoUrl: getRepositoryUrl(), + currentTag: 'v' + version, + previousTag, + isPatch: semver.diff( version, packageJson.version ) === 'patch', isInternalRelease, - indentLevel, - newTagName: 'v' + version, - transformCommit: transformCommitForSubRepositoryFactory( { - treatMajorAsMinorBreakingChange: options.disableMajorBump, - useExplicitBreakingChangeGroups: !!options.useExplicitBreakingChangeGroups - } ), - skipLinks: !!options.skipLinks + highlightsPlaceholder: Boolean( options.highlightsPlaceholder ), + collaborationFeatures: Boolean( options.collaborationFeatures ), + skipCommitsLink: Boolean( options.skipLinks ), + skipCompareLink: Boolean( options.skipLinks ) }; - return generateChangelogFromCommits( changelogOptions ) - .then( () => { - tools.shExec( `git add ${ changelogUtils.changelogFile }`, { verbosity: 'error' } ); - tools.shExec( 'git commit -m "Docs: Changelog. [skip ci]"', { verbosity: 'error' } ); + const writerOptions = getWriterOptions( { + // We do not allow modifying the commit hash value by the generator itself. + hash: hash => hash + } ); - const message = `Changelog for "${ chalk.underline( packageJson.name ) }" (v${ version }) has been generated.`; + const publicCommits = [ ...allCommits ] + .filter( commit => commit.isPublicCommit ) + .map( commit => { + commit.scope = null; + commit.notes = commit.notes.map( note => { + note.scope = null; - log.info( chalk.green( indent + message ) ); + return note; + } ); - return Promise.resolve( version ); + return commit; } ); + + for ( const commit of publicCommits ) { + commitStream.push( commit ); + } + + commitStream.push( null ); + + return new Promise( ( resolve, reject ) => { + commitStream + .pipe( conventionalChangelogWriter( writerContext, writerOptions ) ) + .pipe( stream.noop( changes => { + logInfo( 'Changes based on commits have been generated.', { indentLevel: 1 } ); + resolve( changes.toString() ); + } ) ) + .on( 'error', reject ); + } ); + } ) + .then( changesFromCommits => { + logProcess( 'Saving changelog...' ); + + let currentChangelog = changelogUtils.getChangelog(); + + // Remove header from current changelog. + currentChangelog = currentChangelog.replace( changelogUtils.changelogHeader, '' ); + + // Concat header, new and current changelog. + let newChangelog = changelogUtils.changelogHeader + changesFromCommits + currentChangelog.trim(); + newChangelog = newChangelog.trim() + '\n'; + + // Save the changelog. + changelogUtils.saveChangelog( newChangelog ); + + tools.shExec( `git add ${ changelogUtils.changelogFile }`, { verbosity: 'error' } ); + tools.shExec( 'git commit -m "Docs: Changelog. [skip ci]"', { verbosity: 'error' } ); + + logInfo( 'Saved.', { indentLevel: 1 } ); + } ) + .then( () => { + logInfo( `Changelog for "${ chalk.underline( packageJson.name ) }" (v${ newVersion }) has been generated.` ); } ); + + function logProcess( message ) { + log.info( '\n📍 ' + chalk.cyan( message ) ); + } + + /** + * @param {String} message + * @param {Object} [options={}] + * @param {Number} [options.indentLevel=0] + * @param {Boolean} [options.startWithNewLine=false] Whether to append a new line before the message. + */ + function logInfo( message, options = {} ) { + const indentLevel = options.indentLevel || 0; + const startWithNewLine = options.startWithNewLine || false; + + log.info( `${ startWithNewLine ? '\n' : '' }${ ' '.repeat( indentLevel * cli.INDENT_SIZE ) }` + message ); + } }; diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/changelog.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/changelog.js index 3e0be7617..37973481b 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/utils/changelog.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/utils/changelog.js @@ -61,40 +61,6 @@ const utils = { const changelogFile = path.join( cwd, utils.changelogFile ); fs.writeFileSync( changelogFile, content, 'utf-8' ); - }, - - /** - * Checks whether specified `version` contains the "MAJOR BREAKING CHANGES" header. - * - * @param {String} version Version to check. - * @param {String} [cwd=process.cwd()] Where to look for the changelog file. - * @returns {Boolean} - */ - hasMajorBreakingChanges( version, cwd = process.cwd() ) { - const changes = utils.getChangesForVersion( version, cwd ); - - if ( !changes ) { - throw new Error( `Entries for specified version (${ version }) cannot be found.` ); - } - - return !!changes.match( /### MAJOR BREAKING CHANGES/ ); - }, - - /** - * Checks whether specified `version` contains the "MINOR BREAKING CHANGES" header. - * - * @param {String} version Version to check. - * @param {String} [cwd=process.cwd()] Where to look for the changelog file. - * @returns {Boolean} - */ - hasMinorBreakingChanges( version, cwd = process.cwd() ) { - const changes = utils.getChangesForVersion( version, cwd ); - - if ( !changes ) { - throw new Error( `Entries for specified version (${ version }) cannot be found.` ); - } - - return !!changes.match( /### MINOR BREAKING CHANGES/ ); } }; diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/getcommits.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/getcommits.js index 6a8b7a4b2..64445e1d1 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/utils/getcommits.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/utils/getcommits.js @@ -37,9 +37,9 @@ module.exports = function getCommits( transformCommit, options = {} ) { .on( 'error', err => { if ( err.message.match( /'HEAD': unknown/ ) ) { reject( new Error( 'Given repository is empty.' ) ); - } else if ( err.message.match( new RegExp( `'${ options.tagName }\\.\\.HEAD': unknown` ) ) ) { + } else if ( err.message.match( new RegExp( `'${ options.from }\\.\\.HEAD': unknown` ) ) ) { reject( new Error( - `Cannot find tag "${ options.tagName }" (the latest version from the changelog) in given repository.` + `Cannot find tag or commit "${ options.from }" in given repository.` ) ); } else { reject( err ); diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/getnewreleasetype.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/getnewreleasetype.js index f43bfeeef..6936fe237 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/utils/getnewreleasetype.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/utils/getnewreleasetype.js @@ -10,8 +10,8 @@ const conventionalCommitsFilter = require( 'conventional-commits-filter' ); const gitRawCommits = require( 'git-raw-commits' ); const concat = require( 'concat-stream' ); const parserOptions = require( './transform-commit/parser-options' ); -const { availableCommitTypes } = require( './transform-commit/transform-commit-utils' ); const getPackageJson = require( './getpackagejson' ); +const getNewVersionType = require( './getnewversiontype' ); /** * Returns a type (major, minor, patch) of the next release based on commits. @@ -71,47 +71,4 @@ module.exports = function getNewReleaseType( transformCommit, options = {} ) { } ); } ) ); } ); - - // Returns a type of version for a release based on the commits. - // - // @param {Array.} commits - // @returns {String} - function getNewVersionType( commits ) { - // Repository does not have new changes. - if ( !commits.length ) { - return 'skip'; - } - - const publicCommits = commits.filter( commit => availableCommitTypes.get( commit.rawType ) ); - - if ( !publicCommits.length ) { - return 'internal'; - } - - let newFeatures = false; - let minorBreakingChanges = false; - - for ( const commit of publicCommits ) { - for ( const note of commit.notes ) { - if ( note.title === 'MAJOR BREAKING CHANGES' ) { - return 'major'; - } - - if ( note.title === 'MINOR BREAKING CHANGES' ) { - minorBreakingChanges = true; - } - } - - if ( commit.rawType === 'Feature' ) { - newFeatures = true; - } - } - - // Repository has new features or minor breaking changes. - if ( minorBreakingChanges || newFeatures ) { - return 'minor'; - } - - return 'patch'; - } }; diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/getnewversiontype.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/getnewversiontype.js index 32655e328..d0b6a2b39 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/utils/getnewversiontype.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/utils/getnewversiontype.js @@ -9,9 +9,13 @@ * Proposes new version based on commits. * * @param {Array.} commits + * @param {Object} [options={}] + * @param {Boolean} [options.useExplicitBreakingChangeGroups] If set on `true`, notes from parsed commits will be grouped as + * "MINOR BREAKING CHANGES" and "MAJOR BREAKING CHANGES'. If set on `false` (by default), all breaking changes notes will be treated + * as "BREAKING CHANGES". * @returns {String} */ -module.exports = function getNewVersionType( commits ) { +module.exports = function getNewVersionType( commits, options = {} ) { // No commits = no changes. if ( !commits.length ) { return 'skip'; @@ -29,12 +33,18 @@ module.exports = function getNewVersionType( commits ) { for ( const commit of publicCommits ) { for ( const note of commit.notes ) { - if ( note.title === 'MAJOR BREAKING CHANGES' ) { - return 'major'; - } - - if ( note.title === 'MINOR BREAKING CHANGES' ) { - minorBreakingChanges = true; + if ( options.useExplicitBreakingChangeGroups ) { + if ( note.title === 'MAJOR BREAKING CHANGES' ) { + return 'major'; + } + + if ( note.title === 'MINOR BREAKING CHANGES' ) { + minorBreakingChanges = true; + } + } else { + if ( note.title === 'BREAKING CHANGES' ) { + return 'major'; + } } } diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/releaserepository.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/releaserepository.js deleted file mode 100644 index 855c95dac..000000000 --- a/packages/ckeditor5-dev-env/lib/release-tools/utils/releaserepository.js +++ /dev/null @@ -1,81 +0,0 @@ -/** - * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. - * For licensing, see LICENSE.md. - */ - -'use strict'; - -const chalk = require( 'chalk' ); -const parseGithubUrl = require( 'parse-github-url' ); -const { tools, logger } = require( '@ckeditor/ckeditor5-dev-utils' ); -const createGithubRelease = require( './creategithubrelease' ); -const getPackageJson = require( './getpackagejson' ); - -/** - * Releases the package defined in the current repository. - * - * This task bumps a version in package.json file and publish the changes on npm and/or GitHub. - * - * @param {Object} options - * @param {String} options.token GitHub token used to authenticate. - * @param {Boolean} options.skipGithub Whether to publish the package on Github. - * @param {Boolean} options.skipNpm Whether to publish the package on Npm. - * @param {String} options.version Version of the current release. - * @param {String} options.changes Changelog entries for the current release. - * @returns {Promise} - */ -module.exports = function releaseRepository( options ) { - const cwd = process.cwd(); - const log = logger(); - - const packageJson = getPackageJson( cwd ); - - log.info( '' ); - log.info( chalk.bold.blue( `Publishing the release of "${ packageJson.name }".` ) ); - - const promise = new Promise( ( resolve, reject ) => { - // Bump the version. - exec( `npm version ${ options.version } --message "Release: v${ options.version }."` ); - exec( `git push origin master v${ options.version }` ); - - if ( !options.skipNpm ) { - log.info( 'Publishing on NPM...' ); - exec( 'npm publish --access=public' ); - } - - if ( !options.skipGithub ) { - log.info( 'Creating a GitHub release...' ); - - const repositoryInfo = parseGithubUrl( - exec( 'git remote get-url origin --push' ).trim() - ); - - const releaseOptions = { - repositoryOwner: repositoryInfo.owner, - repositoryName: repositoryInfo.name, - version: `v${ options.version }`, - description: options.changes - }; - - return createGithubRelease( options.token, releaseOptions ) - .then( () => { - const url = `https://github.com/${ repositoryInfo.owner }/${ repositoryInfo.name }/releases/tag/v${ options.version }`; - log.info( `Created the release: ${ url }` ); - - resolve( options.version ); - } ) - .catch( reject ); - } - - resolve( options.version ); - } ); - - return promise - .then( version => { - log.info( chalk.green( `Release "v${ version }" has been created and published.\n` ) ); - } ); -}; - -function exec( command ) { - return tools.shExec( command, { verbosity: 'error' } ); -} diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transformcommitforsubrepositoryfactory.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transformcommitforsubrepositoryfactory.js index 4f937be2b..e2324fc20 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transformcommitforsubrepositoryfactory.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transformcommitforsubrepositoryfactory.js @@ -192,7 +192,7 @@ module.exports = function transformCommitForSubRepositoryFactory( options = {} ) const subject = commitDescription.match( /^(.*)$/m )[ 0 ]; newCommit.subject = subject.trim(); - newCommit.header = commitEntries[ i ] + subject.trim(); + newCommit.header = commitEntries[ i ].trim() + ' ' + subject.trim(); newCommit.body = escapeNewLines( commitDescription.replace( subject, '' ) ); separatedCommits.push( newCommit ); diff --git a/packages/ckeditor5-dev-env/tests/release-tools/utils/changelog.js b/packages/ckeditor5-dev-env/tests/release-tools/utils/changelog.js index 05e4e4605..f091b0fe4 100644 --- a/packages/ckeditor5-dev-env/tests/release-tools/utils/changelog.js +++ b/packages/ckeditor5-dev-env/tests/release-tools/utils/changelog.js @@ -211,109 +211,5 @@ Foo`; expect( writeFileStub.firstCall.args[ 1 ] ).to.equal( 'New content.' ); } ); } ); - - describe( 'hasMajorBreakingChanges()', () => { - it( 'passes proper data to "utils.getChangesForVersion()"', () => { - sandbox.stub( utils, 'getChangesForVersion' ).returns( 'Changelog' ); - - utils.hasMajorBreakingChanges( '1.0.0', 'path/to/package' ); - - expect( utils.getChangesForVersion.calledOnce ).to.equal( true ); - expect( utils.getChangesForVersion.firstCall.args[ 0 ] ).to.equal( '1.0.0' ); - expect( utils.getChangesForVersion.firstCall.args[ 1 ] ).to.equal( 'path/to/package' ); - } ); - - it( 'returns true if release notes for given version contain MAJOR BREAKING CHANGES', () => { - sandbox.stub( utils, 'getChangesForVersion' ).returns( ` -### MAJOR BREAKING CHANGES - -* Some breaking change. - -### Features - -* Another feature. Closes #2. (abc1234) -* Issues will not be hoisted. Closes #8. (abcd123) - - All details have been described in [#1](https://github.com/ckeditor/ckeditor5-test-package/issues/1). -`.trim() ); - - expect( utils.hasMajorBreakingChanges( '1.0.0', 'path/to/package' ) ).to.equal( true ); - } ); - - it( 'returns false if release notes for given version does not contain MAJOR BREAKING CHANGES', () => { - sandbox.stub( utils, 'getChangesForVersion' ).returns( ` -### MINOR BREAKING CHANGES - -* Some breaking change. - -### Features - -* Another feature. Closes #2. (abc1234) -* Issues will not be hoisted. Closes #8. (abcd123) - - All details have been described in [#1](https://github.com/ckeditor/ckeditor5-test-package/issues/1). -`.trim() ); - - expect( utils.hasMajorBreakingChanges( '1.0.0', 'path/to/package' ) ).to.equal( false ); - } ); - - it( 'throws an error if entries for given version cannot be found', () => { - sandbox.stub( utils, 'getChangesForVersion' ).returns( null ); - - expect( () => { - utils.hasMajorBreakingChanges( '1.0.0' ); - } ).to.throw( Error, 'Entries for specified version (1.0.0) cannot be found.' ); - } ); - } ); - - describe( 'hasMinorBreakingChanges()', () => { - it( 'passes proper data to "utils.getChangesForVersion()"', () => { - sandbox.stub( utils, 'getChangesForVersion' ).returns( 'Changelog' ); - - utils.hasMinorBreakingChanges( '1.0.0', 'path/to/package' ); - - expect( utils.getChangesForVersion.calledOnce ).to.equal( true ); - expect( utils.getChangesForVersion.firstCall.args[ 0 ] ).to.equal( '1.0.0' ); - expect( utils.getChangesForVersion.firstCall.args[ 1 ] ).to.equal( 'path/to/package' ); - } ); - - it( 'returns true if release notes for given version contain MINOR BREAKING CHANGES', () => { - sandbox.stub( utils, 'getChangesForVersion' ).returns( ` -### MINOR BREAKING CHANGES - -* Some breaking change. - -### Features - -* Another feature. Closes #2. (abc1234) -* Issues will not be hoisted. Closes #8. (abcd123) - - All details have been described in [#1](https://github.com/ckeditor/ckeditor5-test-package/issues/1). -`.trim() ); - - expect( utils.hasMinorBreakingChanges( '1.0.0', 'path/to/package' ) ).to.equal( true ); - } ); - - it( 'returns false if release notes for given version does not contain MINOR BREAKING CHANGES', () => { - sandbox.stub( utils, 'getChangesForVersion' ).returns( ` -### Features - -* Another feature. Closes #2. (abc1234) -* Issues will not be hoisted. Closes #8. (abcd123) - - All details have been described in [#1](https://github.com/ckeditor/ckeditor5-test-package/issues/1). -`.trim() ); - - expect( utils.hasMinorBreakingChanges( '1.0.0', 'path/to/package' ) ).to.equal( false ); - } ); - - it( 'throws an error if entries for given version cannot be found', () => { - sandbox.stub( utils, 'getChangesForVersion' ).returns( null ); - - expect( () => { - utils.hasMinorBreakingChanges( '1.0.0' ); - } ).to.throw( Error, 'Entries for specified version (1.0.0) cannot be found.' ); - } ); - } ); } ); } ); diff --git a/packages/ckeditor5-dev-env/tests/release-tools/utils/releaserepository.js b/packages/ckeditor5-dev-env/tests/release-tools/utils/releaserepository.js deleted file mode 100644 index 3ceaa4e71..000000000 --- a/packages/ckeditor5-dev-env/tests/release-tools/utils/releaserepository.js +++ /dev/null @@ -1,151 +0,0 @@ -/** - * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. - * For licensing, see LICENSE.md. - */ - -'use strict'; - -const expect = require( 'chai' ).expect; -const sinon = require( 'sinon' ); -const proxyquire = require( 'proxyquire' ); -const mockery = require( 'mockery' ); - -describe( 'dev-env/release-tools/tasks', () => { - describe( 'releaseRepository()', () => { - let releaseRepository, sandbox, stubs, options; - - beforeEach( () => { - sandbox = sinon.createSandbox(); - - mockery.enable( { - useCleanCache: true, - warnOnReplace: false, - warnOnUnregistered: false - } ); - - stubs = { - createGithubRelease: sandbox.stub(), - generateChangelogForSinglePackage: sandbox.stub(), - parseGithubUrl: sandbox.stub(), - getPackageJson: sandbox.stub(), - logger: { - info: sandbox.spy(), - warning: sandbox.spy(), - error: sandbox.spy() - }, - tools: { - shExec: sandbox.stub() - } - }; - - mockery.registerMock( './creategithubrelease', stubs.createGithubRelease ); - mockery.registerMock( './generatechangelogforsinglepackage', stubs.generateChangelogForSinglePackage ); - mockery.registerMock( 'parse-github-url', stubs.parseGithubUrl ); - - sandbox.stub( process, 'cwd' ).returns( '/cwd' ); - - releaseRepository = proxyquire( '../../../lib/release-tools/utils/releaserepository', { - './getpackagejson': stubs.getPackageJson, - '@ckeditor/ckeditor5-dev-utils': { - tools: stubs.tools, - - logger() { - return stubs.logger; - } - } - } ); - - options = { - token: 'github-secret-token', - skipNpm: true, - skipGithub: true, - version: '1.0.0', - changes: 'Changes.' - }; - } ); - - afterEach( () => { - sandbox.restore(); - mockery.disable(); - } ); - - it( 'release the package', () => { - stubs.getPackageJson.returns( { - name: '@ckeditor/ckeditor5-core' - } ); - - stubs.tools.shExec.returns( '' ); - - return releaseRepository( options ) - .then( () => { - expect( stubs.parseGithubUrl.calledOnce ).to.equal( false ); - expect( stubs.createGithubRelease.calledOnce ).to.equal( false ); - expect( stubs.tools.shExec.calledWith( 'npm publish --access=public' ) ).to.equal( false ); - - expect( stubs.tools.shExec.calledWith( 'npm version 1.0.0 --message "Release: v1.0.0."' ) ).to.equal( true ); - expect( stubs.tools.shExec.calledWith( 'git push origin master v1.0.0' ) ).to.equal( true ); - expect( stubs.logger.info.calledWithMatch( /Release "v1.0.0" has been created and published./ ) ) - .to.equal( true ); - } ); - } ); - - it( 'publish package on npm', () => { - options.skipNpm = false; - - stubs.getPackageJson.returns( { - name: '@ckeditor/ckeditor5-core' - } ); - - stubs.tools.shExec.returns( '' ); - stubs.parseGithubUrl.returns( { - owner: 'organization', - name: 'repository' - } ); - - return releaseRepository( options ) - .then( () => { - expect( stubs.parseGithubUrl.calledOnce ).to.equal( false ); - expect( stubs.createGithubRelease.calledOnce ).to.equal( false ); - expect( stubs.tools.shExec.calledWith( 'npm version 1.0.0 --message "Release: v1.0.0."' ) ).to.equal( true ); - expect( stubs.tools.shExec.calledWith( 'git push origin master v1.0.0' ) ).to.equal( true ); - expect( stubs.tools.shExec.calledWith( 'npm publish --access=public' ) ).to.equal( true ); - expect( stubs.logger.info.calledWithMatch( /Release "v1.0.0" has been created and published./ ) ) - .to.equal( true ); - } ); - } ); - - it( 'publish package on GitHub', () => { - options.skipGithub = false; - - stubs.getPackageJson.returns( { - name: '@ckeditor/ckeditor5-core' - } ); - - stubs.createGithubRelease.returns( Promise.resolve() ); - - stubs.tools.shExec.returns( '' ); - stubs.parseGithubUrl.returns( { - owner: 'organization', - name: 'repository' - } ); - - return releaseRepository( options ) - .then( () => { - expect( stubs.parseGithubUrl.calledOnce ).to.equal( true ); - expect( stubs.createGithubRelease.calledOnce ).to.equal( true ); - expect( stubs.tools.shExec.calledWith( 'npm publish --access=public' ) ).to.equal( false ); - - expect( stubs.logger.info.calledWithMatch( /Release "v1.0.0" has been created and published./ ) ) - .to.equal( true ); - - expect( stubs.createGithubRelease.firstCall.args[ 0 ] ).to.equal( options.token ); - expect( stubs.createGithubRelease.firstCall.args[ 1 ] ).to.deep.equal( { - repositoryOwner: 'organization', - repositoryName: 'repository', - version: 'v1.0.0', - description: 'Changes.' - } ); - } ); - } ); - } ); -} ); From d1385d61a519147fe525967f5d6c41b7e8338273 Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Fri, 15 May 2020 10:13:45 +0200 Subject: [PATCH 06/33] Removed unsued files. --- packages/ckeditor5-dev-env/lib/index.js | 4 - .../lib/release-tools/tasks/bumpversions.js | 4 +- .../generatechangelogformonorepository.js | 7 +- .../generatechangelogforsinglepackage.js | 29 +- .../tasks/generatechangelogforsubpackages.js | 130 ----- .../tasks/releasesubrepositories.js | 4 +- .../utils/displaygeneratedchangelogs.js | 31 -- .../release-tools/utils/getnewreleasetype.js | 74 --- ...positoriespaths.js => getpackagespaths.js} | 15 +- .../utils/getsubpackagespaths.js | 65 --- .../transformcommitforsubpackagefactory.js | 84 ---- packages/ckeditor5-dev-env/tests/index.js | 15 - .../generatechangelogforsinglepackage.js | 468 ------------------ .../tasks/generatechangelogforsubpackages.js | 348 ------------- .../stubs/releasesubrepositories/package.json | 15 - .../packages/alpha/package.json | 17 - .../packages/beta/package.json | 11 - .../packages/delta/package.json | 17 - .../packages/dev-kappa/package.json | 9 - .../packages/epsilon/package.json | 13 - .../packages/gamma/package.json | 10 - .../packages/omega/package.json | 17 - 22 files changed, 30 insertions(+), 1357 deletions(-) delete mode 100644 packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogforsubpackages.js delete mode 100644 packages/ckeditor5-dev-env/lib/release-tools/utils/displaygeneratedchangelogs.js delete mode 100644 packages/ckeditor5-dev-env/lib/release-tools/utils/getnewreleasetype.js rename packages/ckeditor5-dev-env/lib/release-tools/utils/{getsubrepositoriespaths.js => getpackagespaths.js} (82%) delete mode 100644 packages/ckeditor5-dev-env/lib/release-tools/utils/getsubpackagespaths.js delete mode 100644 packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transformcommitforsubpackagefactory.js delete mode 100644 packages/ckeditor5-dev-env/tests/release-tools/tasks/generatechangelogforsinglepackage.js delete mode 100644 packages/ckeditor5-dev-env/tests/release-tools/tasks/generatechangelogforsubpackages.js delete mode 100644 packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/package.json delete mode 100644 packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/alpha/package.json delete mode 100644 packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/beta/package.json delete mode 100644 packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/delta/package.json delete mode 100644 packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/dev-kappa/package.json delete mode 100644 packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/epsilon/package.json delete mode 100644 packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/gamma/package.json delete mode 100644 packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/omega/package.json diff --git a/packages/ckeditor5-dev-env/lib/index.js b/packages/ckeditor5-dev-env/lib/index.js index 64605b17f..9b8872942 100644 --- a/packages/ckeditor5-dev-env/lib/index.js +++ b/packages/ckeditor5-dev-env/lib/index.js @@ -18,10 +18,6 @@ const tasks = { return require( './release-tools/tasks/generatechangelogforsinglepackage' )( ...args ); }, - generateChangelogForSubPackages( ...args ) { - return require( './release-tools/tasks/generatechangelogforsubpackages' )( ...args ); - }, - generateChangelogForMonoRepository( ...args ) { return require( './release-tools/tasks/generatechangelogformonorepository' )( ...args ); }, diff --git a/packages/ckeditor5-dev-env/lib/release-tools/tasks/bumpversions.js b/packages/ckeditor5-dev-env/lib/release-tools/tasks/bumpversions.js index a6f3780a6..0d9ad82ef 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/tasks/bumpversions.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/tasks/bumpversions.js @@ -14,7 +14,7 @@ const executeOnPackages = require( '../utils/executeonpackages' ); const { getChangesForVersion } = require( '../utils/changelog' ); const getPackageJson = require( '../utils/getpackagejson' ); const getPackagesToRelease = require( '../utils/getpackagestorelease' ); -const getSubRepositoriesPaths = require( '../utils/getsubrepositoriespaths' ); +const getPackagesPaths = require( '../utils/getpackagespaths' ); const updateDependenciesVersions = require( '../utils/updatedependenciesversions' ); const validatePackageToRelease = require( '../utils/validatepackagetorelease' ); @@ -44,7 +44,7 @@ module.exports = function bumpVersions( options ) { const dryRun = Boolean( options.dryRun ); - const pathsCollection = getSubRepositoriesPaths( { + const pathsCollection = getPackagesPaths( { cwd: options.cwd, packages: options.packages, skipPackages: options.skipPackages || [], diff --git a/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogformonorepository.js b/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogformonorepository.js index f13d4802e..fcd1fc53f 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogformonorepository.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogformonorepository.js @@ -19,7 +19,7 @@ const displayCommits = require( '../utils/displaycommits' ); const displaySkippedPackages = require( '../utils/displayskippedpackages' ); const getPackageJson = require( '../utils/getpackagejson' ); const getNewVersionType = require( '../utils/getnewversiontype' ); -const getSubRepositoriesPaths = require( '../utils/getsubrepositoriespaths' ); +const getPackagesPaths = require( '../utils/getpackagespaths' ); const getCommits = require( '../utils/getcommits' ); const getWriterOptions = require( '../utils/transform-commit/getwriteroptions' ); const { getRepositoryUrl } = require( '../utils/transform-commit/transform-commit-utils' ); @@ -29,7 +29,8 @@ const VERSIONING_POLICY_URL = 'https://ckeditor.com/docs/ckeditor5/latest/framew const noteInfo = `[ℹ️](${ VERSIONING_POLICY_URL }#major-and-minor-breaking-changes)`; /** - * Generates the changelog for the mono repository. + * Generates the single changelog for the mono repository. It means that changes which have been done in all packages + * will be described in the changelog file located in the `options.cwd` directory. * * @param {Object} options * @@ -61,7 +62,7 @@ module.exports = function generateChangelogForMonoRepository( options ) { returnInvalidCommit: true } ); - const pathsCollection = getSubRepositoriesPaths( { + const pathsCollection = getPackagesPaths( { cwd: options.cwd, packages: options.packages, scope: options.scope || null, diff --git a/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogforsinglepackage.js b/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogforsinglepackage.js index a931355ca..658d350d7 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogforsinglepackage.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogforsinglepackage.js @@ -5,6 +5,7 @@ 'use strict'; +const fs = require( 'fs' ); const { Readable } = require( 'stream' ); const { tools, stream, logger } = require( '@ckeditor/ckeditor5-dev-utils' ); const chalk = require( 'chalk' ); @@ -39,9 +40,9 @@ const transformCommitForSubRepositoryFactory = require( '../utils/transform-comm */ module.exports = function generateChangelogForSinglePackage( options = {} ) { const log = logger(); - const packageJson = getPackageJson(); + const pkgJson = getPackageJson(); - logProcess( chalk.bold( `Generating changelog for "${ chalk.underline( packageJson.name ) }"...` ) ); + logProcess( chalk.bold( `Generating changelog for "${ chalk.underline( pkgJson.name ) }"...` ) ); const transformCommit = transformCommitForSubRepositoryFactory( { returnInvalidCommit: true @@ -50,11 +51,11 @@ module.exports = function generateChangelogForSinglePackage( options = {} ) { logProcess( 'Collecting all commits since the last release...' ); const commitOptions = { - from: options.from ? options.from : 'v' + packageJson.version + from: options.from ? options.from : 'v' + pkgJson.version }; // Initial release. - if ( semver.eq( packageJson.version, '0.0.1' ) ) { + if ( semver.eq( pkgJson.version, '0.0.1' ) ) { commitOptions.from = null; } @@ -77,7 +78,7 @@ module.exports = function generateChangelogForSinglePackage( options = {} ) { displayCommits( allCommits, { indentLevel: 1 } ); - return cli.provideVersion( packageJson.version, releaseType, { indentLevel: 1 } ); + return cli.provideVersion( pkgJson.version, releaseType, { indentLevel: 1 } ); } ) .then( version => { if ( version === 'skip' ) { @@ -87,7 +88,7 @@ module.exports = function generateChangelogForSinglePackage( options = {} ) { const isInternalRelease = version === 'internal'; if ( version === 'internal' ) { - version = semver.inc( packageJson.version, 'patch' ); + version = semver.inc( pkgJson.version, 'patch' ); } newVersion = version; @@ -97,7 +98,7 @@ module.exports = function generateChangelogForSinglePackage( options = {} ) { const commitStream = new Readable( { objectMode: true } ); commitStream._read = function() {}; - const previousTag = commitOptions.from ? 'v' + packageJson.version : null; + const previousTag = commitOptions.from ? 'v' + pkgJson.version : null; const writerContext = { version, @@ -105,7 +106,7 @@ module.exports = function generateChangelogForSinglePackage( options = {} ) { repoUrl: getRepositoryUrl(), currentTag: 'v' + version, previousTag, - isPatch: semver.diff( version, packageJson.version ) === 'patch', + isPatch: semver.diff( version, pkgJson.version ) === 'patch', isInternalRelease, highlightsPlaceholder: Boolean( options.highlightsPlaceholder ), collaborationFeatures: Boolean( options.collaborationFeatures ), @@ -150,6 +151,12 @@ module.exports = function generateChangelogForSinglePackage( options = {} ) { .then( changesFromCommits => { logProcess( 'Saving changelog...' ); + if ( fs.existsSync( changelogUtils.changelogFile ) ) { + logInfo( 'Changelog file does not exist. Creating...', { isWarning: true, indentLevel: 1 } ); + + changelogUtils.saveChangelog( changelogUtils.changelogHeader ); + } + let currentChangelog = changelogUtils.getChangelog(); // Remove header from current changelog. @@ -168,7 +175,7 @@ module.exports = function generateChangelogForSinglePackage( options = {} ) { logInfo( 'Saved.', { indentLevel: 1 } ); } ) .then( () => { - logInfo( `Changelog for "${ chalk.underline( packageJson.name ) }" (v${ newVersion }) has been generated.` ); + logInfo( `Changelog for "${ chalk.underline( pkgJson.name ) }" (v${ newVersion }) has been generated.` ); } ); function logProcess( message ) { @@ -180,11 +187,13 @@ module.exports = function generateChangelogForSinglePackage( options = {} ) { * @param {Object} [options={}] * @param {Number} [options.indentLevel=0] * @param {Boolean} [options.startWithNewLine=false] Whether to append a new line before the message. + * @param {Boolean} [options.isWarning=false] Whether to use `warning` method instead of `log`. */ function logInfo( message, options = {} ) { const indentLevel = options.indentLevel || 0; const startWithNewLine = options.startWithNewLine || false; + const method = options.isWarning ? 'warning' : 'info'; - log.info( `${ startWithNewLine ? '\n' : '' }${ ' '.repeat( indentLevel * cli.INDENT_SIZE ) }` + message ); + log[ method ]( `${ startWithNewLine ? '\n' : '' }${ ' '.repeat( indentLevel * cli.INDENT_SIZE ) }` + message ); } }; diff --git a/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogforsubpackages.js b/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogforsubpackages.js deleted file mode 100644 index 7ff3eca07..000000000 --- a/packages/ckeditor5-dev-env/lib/release-tools/tasks/generatechangelogforsubpackages.js +++ /dev/null @@ -1,130 +0,0 @@ -/** - * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. - * For licensing, see LICENSE.md. - */ - -'use strict'; - -const chalk = require( 'chalk' ); -const semver = require( 'semver' ); -const { tools, logger } = require( '@ckeditor/ckeditor5-dev-utils' ); -const getNewReleaseType = require( '../utils/getnewreleasetype' ); -const cli = require( '../utils/cli' ); -const versionUtils = require( '../utils/versions' ); -const changelogUtils = require( '../utils/changelog' ); -const displayCommits = require( '../utils/displaycommits' ); -const displaySkippedPackages = require( '../utils/displayskippedpackages' ); -const displayGeneratedChangelogs = require( '../utils/displaygeneratedchangelogs' ); -const executeOnPackages = require( '../utils/executeonpackages' ); -const getPackageJson = require( '../utils/getpackagejson' ); -const getSubPackagesPaths = require( '../utils/getsubpackagespaths' ); -const generateChangelogFromCommits = require( '../utils/generatechangelogfromcommits' ); -const transformCommitForSubPackageFactory = require( '../utils/transform-commit/transformcommitforsubpackagefactory' ); - -/** - * Generates the changelog for packages located in single repository. - * - * @param {Object} options - * @param {String} options.cwd Current working directory (packages) from which all paths will be resolved. - * @param {String} options.packages Where to look for other packages. - * @param {Array.} options.skipPackages Name of packages which won't be touched. - * @returns {Promise} - */ -module.exports = function generateChangelogForSubPackages( options ) { - const log = logger(); - const cwd = process.cwd(); - - const pathsCollection = getSubPackagesPaths( { - cwd: options.cwd, - packages: options.packages, - skipPackages: options.skipPackages || [] - } ); - - const skippedPackages = new Set(); - const generatedChangelogsMap = new Map(); - - return executeOnPackages( pathsCollection.matched, generateChangelogTask ) - .then( () => { - process.chdir( cwd ); - - // No changelog has generated. Abort. - if ( skippedPackages.size === pathsCollection.matched.size ) { - return; - } - - const shExecOptions = { verbosity: 'error' }; - - log.info( 'Committing generated changelogs.' ); - - tools.shExec( `git add ${ options.packages }/**/${ changelogUtils.changelogFile }`, shExecOptions ); - tools.shExec( 'git commit -m "Docs: Updated changelog for packages. [skip ci]"', shExecOptions ); - } ) - .then( () => { - displaySkippedPackages( pathsCollection.skipped ); - displayGeneratedChangelogs( generatedChangelogsMap ); - - log.info( 'Done.' ); - } ); - - function generateChangelogTask( dependencyPath ) { - process.chdir( dependencyPath ); - - const packageJson = getPackageJson(); - const dependencyName = packageJson.name; - let tagName = versionUtils.getLastFromChangelog(); - - if ( tagName ) { - tagName = packageJson.name + '@' + tagName; - } - - log.info( '\n' + chalk.bold.blue( `Generating changelog for "${ dependencyName }"...` ) ); - - const transformCommitFunction = transformCommitForSubPackageFactory( { - returnInvalidCommit: true - } ); - - return getNewReleaseType( transformCommitFunction, { tagName } ) - .then( result => { - displayCommits( result.commits ); - - const newReleaseType = result.releaseType !== 'skip' ? result.releaseType : null; - - return cli.provideVersion( packageJson.version, newReleaseType ); - } ) - .then( version => { - if ( version === 'skip' ) { - pathsCollection.skipped.add( dependencyPath ); - skippedPackages.add( dependencyPath ); - - return Promise.resolve(); - } - - let isInternalRelease = false; - - if ( version === 'internal' ) { - isInternalRelease = true; - version = semver.inc( packageJson.version, 'patch' ); - } - - const changelogOptions = { - version, - tagName, - isInternalRelease, - newTagName: packageJson.name + '@' + version, - transformCommit: transformCommitForSubPackageFactory() - }; - - return generateChangelogFromCommits( changelogOptions ) - .then( newVersion => { - log.info( - chalk.green( `Changelog for "${ dependencyName }" (v${ newVersion }) has been generated.` ) - ); - - generatedChangelogsMap.set( dependencyName, newVersion ); - } ); - } ) - .catch( err => { - log.error( err ); - } ); - } -}; diff --git a/packages/ckeditor5-dev-env/lib/release-tools/tasks/releasesubrepositories.js b/packages/ckeditor5-dev-env/lib/release-tools/tasks/releasesubrepositories.js index 3c7c3fd95..cdb3fafbc 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/tasks/releasesubrepositories.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/tasks/releasesubrepositories.js @@ -16,7 +16,7 @@ const displaySkippedPackages = require( '../utils/displayskippedpackages' ); const executeOnPackages = require( '../utils/executeonpackages' ); const { getChangesForVersion } = require( '../utils/changelog' ); const getPackageJson = require( '../utils/getpackagejson' ); -const getSubRepositoriesPaths = require( '../utils/getsubrepositoriespaths' ); +const getPackagesPaths = require( '../utils/getpackagespaths' ); const GitHubApi = require( '@octokit/rest' ); const PACKAGE_JSON_TEMPLATE_PATH = require.resolve( '../templates/release-package.json' ); @@ -96,7 +96,7 @@ module.exports = function releaseSubRepositories( options ) { const dryRun = Boolean( options.dryRun ); const emptyReleases = Array.isArray( options.emptyReleases ) ? options.emptyReleases : [ options.emptyReleases ].filter( Boolean ); - const pathsCollection = getSubRepositoriesPaths( { + const pathsCollection = getPackagesPaths( { cwd: options.cwd, packages: options.packages, skipPackages: options.skipPackages || [], diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/displaygeneratedchangelogs.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/displaygeneratedchangelogs.js deleted file mode 100644 index ece13234b..000000000 --- a/packages/ckeditor5-dev-env/lib/release-tools/utils/displaygeneratedchangelogs.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. - * For licensing, see LICENSE.md. - */ - -'use strict'; - -const chalk = require( 'chalk' ); -const { logger } = require( '@ckeditor/ckeditor5-dev-utils' ); -const { INDENT_SIZE } = require( './cli' ); - -/** - * Displays package names and their new versions. - * - * @param {Map} generatedChangelogsMap - */ -module.exports = function displayGeneratedChangelogs( generatedChangelogsMap ) { - if ( !generatedChangelogsMap.size ) { - return; - } - - const indent = ' '.repeat( INDENT_SIZE ); - - let message = indent + chalk.bold.underline( 'Changelogs for the following packages have been generated:' ) + '\n'; - - for ( const [ packageName, version ] of generatedChangelogsMap ) { - message += indent + ` * ${ packageName }: v${ version }\n`; - } - - logger().info( message ); -}; diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/getnewreleasetype.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/getnewreleasetype.js deleted file mode 100644 index 6936fe237..000000000 --- a/packages/ckeditor5-dev-env/lib/release-tools/utils/getnewreleasetype.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. - * For licensing, see LICENSE.md. - */ - -'use strict'; - -const conventionalCommitsParser = require( 'conventional-commits-parser' ); -const conventionalCommitsFilter = require( 'conventional-commits-filter' ); -const gitRawCommits = require( 'git-raw-commits' ); -const concat = require( 'concat-stream' ); -const parserOptions = require( './transform-commit/parser-options' ); -const getPackageJson = require( './getpackagejson' ); -const getNewVersionType = require( './getnewversiontype' ); - -/** - * Returns a type (major, minor, patch) of the next release based on commits. - * - * If given package has not changed, suggested version will be equal to 'skip'. - * - * It returns a promise that resolves to the `releaseType` and all `commits` that have been checked. - * - * @param {Function} transformCommit - * @param {Object} options - * @param {String|null} options.tagName Name of the last created tag for the repository. - * @returns {Promise.} - */ -module.exports = function getNewReleaseType( transformCommit, options = {} ) { - const gitRawCommitsOpts = { - format: '%B%n-hash-%n%H', - from: options.tagName, - merges: undefined, - firstParent: true - }; - - const context = { - packageData: getPackageJson() - }; - - return new Promise( ( resolve, reject ) => { - gitRawCommits( gitRawCommitsOpts ) - .on( 'error', err => { - if ( err.message.match( /'HEAD': unknown/ ) ) { - reject( new Error( 'Given repository is empty.' ) ); - } else if ( err.message.match( new RegExp( `'${ options.tagName }\\.\\.HEAD': unknown` ) ) ) { - reject( new Error( - `Cannot find tag "${ options.tagName }" (the latest version from the changelog) in given repository.` - ) ); - } else { - reject( err ); - } - } ) - .pipe( conventionalCommitsParser( parserOptions ) ) - .pipe( concat( data => { - const commits = conventionalCommitsFilter( data ) - .map( commit => transformCommit( commit, context ) ) - .reduce( ( allCommits, commit ) => { - if ( Array.isArray( commit ) ) { - allCommits.push( ...commit ); - } else { - allCommits.push( commit ); - } - - return allCommits; - }, [] ) - .filter( commit => commit ); - - return resolve( { - releaseType: getNewVersionType( commits ), - commits - } ); - } ) ); - } ); -}; diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/getsubrepositoriespaths.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/getpackagespaths.js similarity index 82% rename from packages/ckeditor5-dev-env/lib/release-tools/utils/getsubrepositoriespaths.js rename to packages/ckeditor5-dev-env/lib/release-tools/utils/getpackagespaths.js index 95da2a976..caf4989d3 100644 --- a/packages/ckeditor5-dev-env/lib/release-tools/utils/getsubrepositoriespaths.js +++ b/packages/ckeditor5-dev-env/lib/release-tools/utils/getpackagespaths.js @@ -16,11 +16,9 @@ const getPackageJson = require( './getpackagejson' ); * * - The first one is marked as `matched` and means that packages specified in a path (which is a combination of values specified as * `options.cwd` and `options.packages`) match to given criteria. - * - The second one is marked as `skipped` and means that packages should not be processed. They aren't defined in the main - * `package.json` as dependencies or were listed as packages to skip (`options.skipPackages` or don't mach to `options.scope`). + * - The second one is marked as `skipped` and means that packages should not be processed. They were listed as packages to skip + * (`options.skipPackages` or don't mach to `options.scope`). * - * By "sub repositories" we understand that packages have their own repositories and they are located inside another - * repository (similar to git submodules). * * @param {Object} options * @param {String} options.cwd Current work directory. @@ -31,7 +29,7 @@ const getPackageJson = require( './getpackagejson' ); * @param {Boolean} [options.skipMainRepository=false] If set on true, package found in `options.cwd` will be skipped. * @returns {PathsCollection} */ -module.exports = function getSubRepositoriesPaths( options ) { +module.exports = function getPackagesPaths( options ) { const collection = { matched: new Set(), skipped: new Set() @@ -50,9 +48,6 @@ module.exports = function getSubRepositoriesPaths( options ) { const packagesPath = path.join( options.cwd, options.packages ); const skipPackages = Array.isArray( options.skipPackages ) ? options.skipPackages : [ options.skipPackages ]; - const packageJson = getPackageJson( options.cwd ); - const dependencies = Object.keys( packageJson.dependencies || {} ); - for ( const directory of tools.getDirectories( packagesPath ) ) { const dependencyPath = path.join( packagesPath, directory ); @@ -72,10 +67,6 @@ module.exports = function getSubRepositoriesPaths( options ) { return collection; function isValidPackage( packageName ) { - if ( !dependencies.includes( packageName ) ) { - return false; - } - for ( const skipPackageGlob of skipPackages ) { if ( minimatch( packageName, skipPackageGlob ) ) { return false; diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/getsubpackagespaths.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/getsubpackagespaths.js deleted file mode 100644 index 10771e770..000000000 --- a/packages/ckeditor5-dev-env/lib/release-tools/utils/getsubpackagespaths.js +++ /dev/null @@ -1,65 +0,0 @@ -/** - * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. - * For licensing, see LICENSE.md. - */ - -'use strict'; - -const path = require( 'path' ); -const { tools } = require( '@ckeditor/ckeditor5-dev-utils' ); -const getPackageJson = require( './getpackagejson' ); -const minimatch = require( 'minimatch' ); - -/** - * Returns an object with two collections of paths to packages which are located in single repository. - * - * - The first one is marked as `matched` and means that packages specified in a path (which is a combination of values specified as - * `options.cwd` and `options.packages`) match to given criteria. - * - The second one is marked as `skipped` and means that packages should not be processed. They were listed as packages - * to skip (`options.skipPackages` or don't mach to `options.scope`). - * - * By "sub packages" we understand that packages are located in single repository (they do not own separate repositories). - * - * @param {Object} options - * @param {String} options.cwd Current work directory. - * @param {String} options.packages Name of directory where to look for packages. - * @param {String|Array.} options.skipPackages Glob pattern(s) which describes which packages should be skipped. - * @param {String} [options.scope] Package names have to match to specified glob pattern. - * @returns {PathsCollection} - */ -module.exports = function getSubPackagesPaths( options ) { - const packagesPath = path.join( options.cwd, options.packages ); - const skipPackages = Array.isArray( options.skipPackages ) ? options.skipPackages : [ options.skipPackages ]; - - const pathsCollection = { - matched: new Set(), - skipped: new Set() - }; - - for ( const directory of tools.getDirectories( packagesPath ) ) { - const dependencyPath = path.join( packagesPath, directory ); - const dependencyName = getPackageJson( dependencyPath ).name; - - if ( isValidPackage( dependencyName ) ) { - pathsCollection.matched.add( dependencyPath ); - } else { - pathsCollection.skipped.add( dependencyPath ); - } - } - - return pathsCollection; - - function isValidPackage( packageName ) { - for ( const skipPackageGlob of skipPackages ) { - if ( minimatch( packageName, skipPackageGlob ) ) { - return false; - } - } - - if ( options.scope ) { - return minimatch( packageName, options.scope ); - } - - return true; - } -}; diff --git a/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transformcommitforsubpackagefactory.js b/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transformcommitforsubpackagefactory.js deleted file mode 100644 index b205408c7..000000000 --- a/packages/ckeditor5-dev-env/lib/release-tools/utils/transform-commit/transformcommitforsubpackagefactory.js +++ /dev/null @@ -1,84 +0,0 @@ -/** - * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. - * For licensing, see LICENSE.md. - */ - -'use strict'; - -const transformCommitForSubRepositoryFactory = require( './transformcommitforsubrepositoryfactory' ); -const getChangedFilesForCommit = require( './getchangedfilesforcommit' ); - -/** - * Factory function. - * - * It returns a function that parses a single commit for a package which is located in multi-package repository. - * - * The commit will be parsed only if its at least one file is located in the current processing package. - * - * If the commit match to specified criteria, it will be passed to a function produced by `transformCommitForSubRepositoryFactory()`. - * - * Returns `undefined` if given commit should not be added to the changelog. This behavior can be changed - * using the `options.returnInvalidCommit` option. - * - * NOTE: An invalid commit will be returned only if it match to a parsed package. It means the commit must - * change at least one file which belongs to current processing package. - * - * @param {Object} [options={}] - * @param {Boolean} [options.returnInvalidCommit=false] Whether an invalid commit should be returned. - * @returns {Function} - */ -module.exports = function transformCommitForSubPackageFactory( options = {} ) { - /** - * @param {Commit} rawCommit - * @param {Object} context - * @param {Object} context.packageData Content from the `package.json` file for a parsing package. - * @returns {Commit|undefined} `undefined` means that the commit does not belong to the parsing package. - */ - return function transformCommitForSubPackage( rawCommit, context ) { - // Let's clone the commit. We don't want to modify the reference. - const commit = Object.assign( {}, rawCommit, { - notes: rawCommit.notes.map( note => Object.assign( {}, note ) ) - } ); - - // Skip the Lerna "Publish" commit. - if ( !commit.type && commit.header === 'Publish' && commit.body ) { - return; - } - - // Our merge commit always contains two lines: - // Merge ... - // Prefix: Subject of the changes. - // Unfortunately, merge commit made by Git does not contain the second line. - // Because of that hash of the commit is parsed as a body and the changelog will crash. - // See: https://github.com/ckeditor/ckeditor5-dev/issues/276. - if ( commit.merge && !commit.hash ) { - commit.hash = commit.body; - commit.header = commit.merge; - commit.body = null; - } - - const files = getChangedFilesForCommit( commit.hash ); - - if ( !files.length ) { - return; - } - - const packageName = context.packageData.name; - const packageDirectory = packageName.startsWith( '@' ) ? packageName.split( '/' )[ 1 ] : packageName; - - if ( !isValidCommit( files, packageDirectory ) ) { - return; - } - - const transformCommitForSubRepository = transformCommitForSubRepositoryFactory( { - returnInvalidCommit: options.returnInvalidCommit - } ); - - return transformCommitForSubRepository( commit ); - }; - - function isValidCommit( files, packageName ) { - // Commit is valid for the package if at least one file in the package was changed. - return files.some( filePath => filePath.startsWith( `packages/${ packageName }` ) ); - } -}; diff --git a/packages/ckeditor5-dev-env/tests/index.js b/packages/ckeditor5-dev-env/tests/index.js index f8262ce0c..27a7e7505 100644 --- a/packages/ckeditor5-dev-env/tests/index.js +++ b/packages/ckeditor5-dev-env/tests/index.js @@ -37,7 +37,6 @@ describe( 'dev-env/index', () => { release: { releaseSubRepositories: sandbox.stub(), generateChangelogForSinglePackage: sandbox.stub(), - generateChangelogForSubPackages: sandbox.stub(), generateChangelogForMonoRepository: sandbox.stub(), bumpVersions: sandbox.stub() } @@ -53,7 +52,6 @@ describe( 'dev-env/index', () => { mockery.registerMock( './release-tools/tasks/bumpversions', releaseTools.bumpVersions ); mockery.registerMock( './release-tools/tasks/generatechangelogforsinglepackage', releaseTools.generateChangelogForSinglePackage ); mockery.registerMock( './release-tools/tasks/releasesubrepositories', releaseTools.releaseSubRepositories ); - mockery.registerMock( './release-tools/tasks/generatechangelogforsubpackages', releaseTools.generateChangelogForSubPackages ); mockery.registerMock( './release-tools/tasks/generatechangelogformonorepository', releaseTools.generateChangelogForMonoRepository ); tasks = proxyquire( '../lib/index', { @@ -96,19 +94,6 @@ describe( 'dev-env/index', () => { } ); } ); - describe( 'generateChangelogForSubPackages()', () => { - it( 'generates a changelog for sub packages', () => { - stubs.release.generateChangelogForSubPackages.returns( Promise.resolve( { result: true } ) ); - - return tasks.generateChangelogForSubPackages( 'arg' ) - .then( response => { - expect( response.result ).to.equal( true ); - expect( stubs.release.generateChangelogForSubPackages.calledOnce ).to.equal( true ); - expect( stubs.release.generateChangelogForSubPackages.firstCall.args[ 0 ] ).to.equal( 'arg' ); - } ); - } ); - } ); - describe( 'generateChangelogForMonoRepository()', () => { it( 'generates a changelog for sub repositories', () => { stubs.release.generateChangelogForMonoRepository.returns( Promise.resolve( { result: true } ) ); diff --git a/packages/ckeditor5-dev-env/tests/release-tools/tasks/generatechangelogforsinglepackage.js b/packages/ckeditor5-dev-env/tests/release-tools/tasks/generatechangelogforsinglepackage.js deleted file mode 100644 index 9cfe78743..000000000 --- a/packages/ckeditor5-dev-env/tests/release-tools/tasks/generatechangelogforsinglepackage.js +++ /dev/null @@ -1,468 +0,0 @@ -/** - * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. - * For licensing, see LICENSE.md. - */ - -'use strict'; - -const expect = require( 'chai' ).expect; -const sinon = require( 'sinon' ); -const mockery = require( 'mockery' ); -const proxyquire = require( 'proxyquire' ); -const changelogUtils = require( '../../../lib/release-tools/utils/changelog' ); - -describe( 'dev-env/release-tools/tasks', () => { - describe( 'generateChangelogForSinglePackage()', () => { - let generateChangelogForSinglePackage, sandbox, stubs; - - beforeEach( () => { - sandbox = sinon.createSandbox(); - - stubs = { - changelogUtils: { - changelogFile: changelogUtils.changelogFile - }, - getNewReleaseType: sandbox.stub(), - displayCommits: sandbox.stub(), - logger: { - info: sandbox.stub(), - warning: sandbox.stub(), - error: sandbox.stub() - }, - tools: { - shExec: sandbox.stub() - }, - cli: { - provideVersion: sandbox.stub() - }, - transformCommitFactory: sandbox.stub(), - transformCommit: [ - sandbox.stub(), - sandbox.stub() - ], - generateChangelogFromCommits: sandbox.stub(), - versionUtils: { - getLastFromChangelog: sandbox.stub() - } - }; - - stubs.transformCommitFactory.onFirstCall().returns( stubs.transformCommit[ 0 ] ); - stubs.transformCommitFactory.onSecondCall().returns( stubs.transformCommit[ 1 ] ); - - mockery.enable( { - useCleanCache: true, - warnOnReplace: false, - warnOnUnregistered: false - } ); - - mockery.registerMock( '../utils/cli', stubs.cli ); - mockery.registerMock( '../utils/getnewreleasetype', stubs.getNewReleaseType ); - mockery.registerMock( '../utils/displaycommits', stubs.displayCommits ); - mockery.registerMock( '../utils/generatechangelogfromcommits', stubs.generateChangelogFromCommits ); - mockery.registerMock( '../utils/transform-commit/transformcommitforsubrepositoryfactory', stubs.transformCommitFactory ); - - generateChangelogForSinglePackage = proxyquire( '../../../lib/release-tools/tasks/generatechangelogforsinglepackage', { - '../utils/changelog': stubs.changelogUtils, - '../utils/versions': stubs.versionUtils, - '../utils/getpackagejson': () => ( { - name: 'test-package', - version: '0.0.1' - } ), - '@ckeditor/ckeditor5-dev-utils': { - tools: stubs.tools, - logger() { - return stubs.logger; - } - } - } ); - } ); - - afterEach( () => { - sandbox.restore(); - mockery.disable(); - } ); - - it( 'passes options to "transformCommitForSubRepositoryFactory()" correctly', () => { - const commits = [ {}, {} ]; - - stubs.getNewReleaseType.returns( Promise.resolve( { - releaseType: 'minor', - commits - } ) ); - - stubs.versionUtils.getLastFromChangelog.returns( '0.5.0' ); - stubs.generateChangelogFromCommits.returns( Promise.resolve() ); - stubs.cli.provideVersion.returns( Promise.resolve( '1.0.0' ) ); - - const options = { - newVersion: '1.0.0', - disableMajorBump: false, - useExplicitBreakingChangeGroups: true - }; - - return generateChangelogForSinglePackage( options ) - .then( () => { - expect( stubs.transformCommitFactory.calledTwice ).to.equal( true ); - - expect( stubs.transformCommitFactory.firstCall.args[ 0 ] ).to.deep.equal( { - returnInvalidCommit: true, - treatMajorAsMinorBreakingChange: false, - useExplicitBreakingChangeGroups: true - } ); - expect( stubs.transformCommitFactory.secondCall.args[ 0 ] ).to.deep.equal( { - treatMajorAsMinorBreakingChange: false, - useExplicitBreakingChangeGroups: true - } ); - } ); - } ); - - it( 'passes `options.indentLevel` to "generateChangelogFromCommits()" correctly', () => { - const commits = [ {}, {} ]; - - stubs.getNewReleaseType.returns( Promise.resolve( { - releaseType: 'minor', - commits - } ) ); - - stubs.versionUtils.getLastFromChangelog.returns( '0.5.0' ); - stubs.generateChangelogFromCommits.returns( Promise.resolve() ); - stubs.cli.provideVersion.returns( Promise.resolve( '1.0.0' ) ); - - const options = { - newVersion: '1.0.0', - indentLevel: 3 - }; - - return generateChangelogForSinglePackage( options ) - .then( () => { - expect( stubs.generateChangelogFromCommits.calledOnce ).to.equal( true ); - expect( stubs.generateChangelogFromCommits.firstCall.args[ 0 ] ).to.deep.equal( { - indentLevel: 3, - version: '1.0.0', - tagName: 'v0.5.0', - newTagName: 'v1.0.0', - transformCommit: stubs.transformCommit[ 1 ], - isInternalRelease: false, - skipLinks: false - } ); - } ); - } ); - - it( 'generates the changelog for specified version (user must confirm)', () => { - const commits = [ {}, {} ]; - - stubs.getNewReleaseType.returns( Promise.resolve( { - releaseType: 'minor', - commits - } ) ); - - stubs.versionUtils.getLastFromChangelog.returns( '0.5.0' ); - stubs.generateChangelogFromCommits.returns( Promise.resolve() ); - stubs.cli.provideVersion.returns( Promise.resolve( '1.0.0' ) ); - - return generateChangelogForSinglePackage( { newVersion: '1.0.0' } ) - .then( () => { - expect( stubs.transformCommitFactory.calledTwice ).to.equal( true ); - - expect( stubs.generateChangelogFromCommits.calledOnce ).to.equal( true ); - expect( stubs.generateChangelogFromCommits.firstCall.args[ 0 ] ).to.deep.equal( { - indentLevel: 0, - version: '1.0.0', - tagName: 'v0.5.0', - newTagName: 'v1.0.0', - transformCommit: stubs.transformCommit[ 1 ], - isInternalRelease: false, - skipLinks: false - } ); - - expect( stubs.logger.info.calledTwice ).to.equal( true ); - expect( stubs.logger.info.firstCall.args[ 0 ] ).to.match( - /Generating changelog for "[^"]+".../ - ); - expect( stubs.logger.info.secondCall.args[ 0 ] ).to.match( - /Changelog for "[^"]+" \(v1\.0\.0\) has been generated\./ - ); - } ); - } ); - - it( 'generates changelog for version provided by a user', () => { - const commits = [ {}, {} ]; - - stubs.getNewReleaseType.returns( Promise.resolve( { - releaseType: 'minor', - commits - } ) ); - stubs.cli.provideVersion.returns( Promise.resolve( '0.1.0' ) ); - stubs.versionUtils.getLastFromChangelog.returns( null ); - stubs.generateChangelogFromCommits.returns( Promise.resolve() ); - - return generateChangelogForSinglePackage() - .then( () => { - expect( stubs.transformCommitFactory.calledTwice ).to.equal( true ); - - expect( stubs.generateChangelogFromCommits.calledOnce ).to.equal( true ); - expect( stubs.generateChangelogFromCommits.firstCall.args[ 0 ] ).to.deep.equal( { - indentLevel: 0, - version: '0.1.0', - tagName: null, - newTagName: 'v0.1.0', - transformCommit: stubs.transformCommit[ 1 ], - isInternalRelease: false, - skipLinks: false - } ); - - expect( stubs.getNewReleaseType.calledOnce ).to.equal( true ); - expect( stubs.getNewReleaseType.firstCall.args[ 0 ] ).to.equal( stubs.transformCommit[ 0 ] ); - expect( stubs.getNewReleaseType.firstCall.args[ 1 ] ).to.deep.equal( { - tagName: null - } ); - - expect( stubs.cli.provideVersion.calledOnce ).to.equal( true ); - expect( stubs.cli.provideVersion.firstCall.args[ 0 ] ).to.equal( '0.0.1' ); - expect( stubs.cli.provideVersion.firstCall.args[ 1 ] ).to.equal( 'minor' ); - - expect( stubs.displayCommits.calledOnce ).to.equal( true ); - expect( stubs.displayCommits.firstCall.args[ 0 ] ).to.deep.equal( commits ); - } ); - } ); - - it( 'generates changelog (as "patch" bump) for "internal" version provided by a user', () => { - const commits = [ {}, {} ]; - - stubs.getNewReleaseType.returns( Promise.resolve( { - releaseType: 'minor', - commits - } ) ); - stubs.cli.provideVersion.returns( Promise.resolve( 'internal' ) ); - stubs.versionUtils.getLastFromChangelog.returns( null ); - stubs.generateChangelogFromCommits.returns( Promise.resolve() ); - - return generateChangelogForSinglePackage() - .then( () => { - expect( stubs.transformCommitFactory.calledTwice ).to.equal( true ); - - expect( stubs.generateChangelogFromCommits.calledOnce ).to.equal( true ); - expect( stubs.generateChangelogFromCommits.firstCall.args[ 0 ] ).to.deep.equal( { - indentLevel: 0, - version: '0.0.2', - tagName: null, - newTagName: 'v0.0.2', - transformCommit: stubs.transformCommit[ 1 ], - isInternalRelease: true, - skipLinks: false - } ); - - expect( stubs.getNewReleaseType.calledOnce ).to.equal( true ); - expect( stubs.getNewReleaseType.firstCall.args[ 0 ] ).to.equal( stubs.transformCommit[ 0 ] ); - expect( stubs.getNewReleaseType.firstCall.args[ 1 ] ).to.deep.equal( { - tagName: null - } ); - - expect( stubs.cli.provideVersion.calledOnce ).to.equal( true ); - expect( stubs.cli.provideVersion.firstCall.args[ 0 ] ).to.equal( '0.0.1' ); - expect( stubs.cli.provideVersion.firstCall.args[ 1 ] ).to.equal( 'minor' ); - - expect( stubs.displayCommits.calledOnce ).to.equal( true ); - expect( stubs.displayCommits.firstCall.args[ 0 ] ).to.deep.equal( commits ); - } ); - } ); - - it( '"options.newVersion" can be defined as an increment level ', () => { - const commits = [ {}, {} ]; - - stubs.getNewReleaseType.returns( Promise.resolve( { - releaseType: 'minor', - commits - } ) ); - stubs.cli.provideVersion.returns( Promise.resolve( '0.1.0' ) ); - stubs.versionUtils.getLastFromChangelog.returns( null ); - stubs.generateChangelogFromCommits.returns( Promise.resolve() ); - - return generateChangelogForSinglePackage( { newVersion: 'minor' } ) - .then( () => { - expect( stubs.transformCommitFactory.calledTwice ).to.equal( true ); - - expect( stubs.generateChangelogFromCommits.calledOnce ).to.equal( true ); - expect( stubs.generateChangelogFromCommits.firstCall.args[ 0 ] ).to.deep.equal( { - indentLevel: 0, - version: '0.1.0', - tagName: null, - newTagName: 'v0.1.0', - transformCommit: stubs.transformCommit[ 1 ], - isInternalRelease: false, - skipLinks: false - } ); - - expect( stubs.cli.provideVersion.calledOnce ).to.equal( true ); - expect( stubs.cli.provideVersion.firstCall.args[ 0 ] ).to.equal( '0.0.1' ); - expect( stubs.cli.provideVersion.firstCall.args[ 1 ] ).to.equal( 'minor' ); - - expect( stubs.displayCommits.called ).to.equal( true ); - } ); - } ); - - it( 'does not generate if a user provides "skip" as a new version (suggested a "minor" release)', () => { - const commits = [ {}, {} ]; - - stubs.getNewReleaseType.returns( Promise.resolve( { - releaseType: 'minor', - commits - } ) ); - - stubs.cli.provideVersion.returns( Promise.resolve( 'skip' ) ); - - return generateChangelogForSinglePackage() - .then( () => { - expect( stubs.transformCommitFactory.calledOnce ).to.equal( true ); - expect( stubs.generateChangelogFromCommits.called ).to.equal( false ); - expect( stubs.displayCommits.calledOnce ).to.equal( true ); - expect( stubs.displayCommits.firstCall.args[ 0 ] ).to.deep.equal( commits ); - } ); - } ); - - it( 'does not generate if a user provides "skip" as a new version (suggested a "skip" release)', () => { - const commits = [ {}, {} ]; - - stubs.getNewReleaseType.returns( Promise.resolve( { - releaseType: 'skip', - commits - } ) ); - - stubs.cli.provideVersion.returns( Promise.resolve( 'skip' ) ); - - return generateChangelogForSinglePackage() - .then( () => { - expect( stubs.transformCommitFactory.calledOnce ).to.equal( true ); - expect( stubs.generateChangelogFromCommits.called ).to.equal( false ); - expect( stubs.displayCommits.calledOnce ).to.equal( true ); - expect( stubs.displayCommits.firstCall.args[ 0 ] ).to.deep.equal( commits ); - } ); - } ); - - it( 'committed changelog should not trigger CI', () => { - const commits = [ {}, {} ]; - - stubs.getNewReleaseType.returns( Promise.resolve( { - releaseType: 'minor', - commits - } ) ); - - stubs.versionUtils.getLastFromChangelog.returns( '0.5.0' ); - stubs.generateChangelogFromCommits.returns( Promise.resolve() ); - stubs.cli.provideVersion.returns( Promise.resolve( '1.0.0' ) ); - - return generateChangelogForSinglePackage( { newVersion: '1.0.0' } ) - .then( () => { - expect( stubs.tools.shExec.secondCall.args[ 0 ] ).to.equal( - 'git commit -m "Docs: Changelog. [skip ci]"' - ); - } ); - } ); - - it( 'allows generating changelog internal changelog (newVersion as a version string)', () => { - stubs.versionUtils.getLastFromChangelog.returns( '0.0.1' ); - stubs.generateChangelogFromCommits.returns( Promise.resolve() ); - - return generateChangelogForSinglePackage( { newVersion: '0.1.0', isInternalRelease: true } ) - .then( () => { - expect( stubs.transformCommitFactory.calledOnce ).to.equal( true ); - expect( stubs.generateChangelogFromCommits.calledOnce ).to.equal( true ); - expect( stubs.generateChangelogFromCommits.firstCall.args[ 0 ] ).to.deep.equal( { - indentLevel: 0, - version: '0.1.0', - tagName: 'v0.0.1', - newTagName: 'v0.1.0', - transformCommit: stubs.transformCommit[ 0 ], - isInternalRelease: true, - skipLinks: false - } ); - } ); - } ); - - it( 'allows generating changelog internal changelog (newVersion as an increment level)', () => { - stubs.versionUtils.getLastFromChangelog.returns( '0.0.1' ); - stubs.generateChangelogFromCommits.returns( Promise.resolve() ); - - return generateChangelogForSinglePackage( { newVersion: 'major', isInternalRelease: true } ) - .then( () => { - expect( stubs.transformCommitFactory.calledOnce ).to.equal( true ); - expect( stubs.generateChangelogFromCommits.calledOnce ).to.equal( true ); - expect( stubs.generateChangelogFromCommits.firstCall.args[ 0 ] ).to.deep.equal( { - indentLevel: 0, - version: '1.0.0', - tagName: 'v0.0.1', - newTagName: 'v1.0.0', - transformCommit: stubs.transformCommit[ 0 ], - isInternalRelease: true, - skipLinks: false - } ); - } ); - } ); - - it( 'throws an error for internal changelog when specified invalid value as newVersion', () => { - stubs.versionUtils.getLastFromChangelog.returns( '0.0.1' ); - stubs.generateChangelogFromCommits.returns( Promise.resolve() ); - - return generateChangelogForSinglePackage( { newVersion: 'foo', isInternalRelease: true } ) - .then( - () => { - throw new Error( 'Supposed to be rejected.' ); - }, - error => { - expect( error.message ).to.equal( - 'If "isInternalRelease" is set on true, "newVersion" must be a version or increment level. Given "foo".' - ); - } - ); - } ); - - it( 'passes the "skipLinks" option to the changelog generator', () => { - stubs.getNewReleaseType.returns( Promise.resolve( { - releaseType: 'minor' - } ) ); - stubs.cli.provideVersion.returns( Promise.resolve( '0.1.0' ) ); - stubs.versionUtils.getLastFromChangelog.returns( null ); - stubs.generateChangelogFromCommits.returns( Promise.resolve() ); - - return generateChangelogForSinglePackage( { skipLinks: true } ) - .then( () => { - expect( stubs.transformCommitFactory.calledTwice ).to.equal( true ); - expect( stubs.generateChangelogFromCommits.calledOnce ).to.equal( true ); - expect( stubs.generateChangelogFromCommits.firstCall.args[ 0 ] ).to.deep.equal( { - indentLevel: 0, - version: '0.1.0', - tagName: null, - newTagName: 'v0.1.0', - transformCommit: stubs.transformCommit[ 1 ], - isInternalRelease: false, - skipLinks: true - } ); - } ); - } ); - - it( 'treats "MAJOR BREAKING CHANGES" as "MINOR BREAKING CHANGES"', () => { - stubs.getNewReleaseType.returns( Promise.resolve( { - releaseType: 'minor' - } ) ); - stubs.cli.provideVersion.returns( Promise.resolve( '0.1.0' ) ); - stubs.versionUtils.getLastFromChangelog.returns( null ); - stubs.generateChangelogFromCommits.returns( Promise.resolve() ); - - return generateChangelogForSinglePackage( { disableMajorBump: true } ) - .then( () => { - expect( stubs.transformCommitFactory.calledTwice ).to.equal( true ); - - expect( stubs.generateChangelogFromCommits.calledOnce ).to.equal( true ); - expect( stubs.generateChangelogFromCommits.firstCall.args[ 0 ] ).to.deep.equal( { - indentLevel: 0, - version: '0.1.0', - tagName: null, - newTagName: 'v0.1.0', - transformCommit: stubs.transformCommit[ 1 ], - isInternalRelease: false, - skipLinks: false - } ); - } ); - } ); - } ); -} ); diff --git a/packages/ckeditor5-dev-env/tests/release-tools/tasks/generatechangelogforsubpackages.js b/packages/ckeditor5-dev-env/tests/release-tools/tasks/generatechangelogforsubpackages.js deleted file mode 100644 index 1708cd629..000000000 --- a/packages/ckeditor5-dev-env/tests/release-tools/tasks/generatechangelogforsubpackages.js +++ /dev/null @@ -1,348 +0,0 @@ -/** - * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. - * For licensing, see LICENSE.md. - */ - -'use strict'; - -const path = require( 'path' ); -const sinon = require( 'sinon' ); -const expect = require( 'chai' ).expect; -const proxyquire = require( 'proxyquire' ); -const mockery = require( 'mockery' ); - -describe( 'dev-env/release-tools/tasks', () => { - let generateChangelogForSubPackages, sandbox, stubs; - - beforeEach( () => { - sandbox = sinon.createSandbox(); - - mockery.enable( { - useCleanCache: true, - warnOnReplace: false, - warnOnUnregistered: false - } ); - - stubs = { - transformCommitFunctionFactory: sandbox.stub(), - transformCommit: [], - getSubPackagesPaths: sandbox.stub(), - displaySkippedPackages: sandbox.stub(), - displayGeneratedChangelogs: sandbox.stub(), - generateChangelogFromCommits: sandbox.stub(), - getPackageJson: sandbox.stub(), - changelogUtils: { - changelogFile: 'CHANGELOG.md' - }, - getNewReleaseType: sandbox.stub(), - displayCommits: sandbox.stub(), - logger: { - info: sandbox.spy(), - warning: sandbox.spy(), - error: sandbox.spy() - }, - tools: { - shExec: sandbox.stub() - }, - cli: { - provideVersion: sandbox.stub() - }, - versionUtils: { - getLastFromChangelog: sandbox.stub() - } - }; - - for ( let i = 0; i < 4; ++i ) { - stubs.transformCommit.push( sandbox.stub() ); - stubs.transformCommitFunctionFactory.onCall( i ).returns( stubs.transformCommit[ i ] ); - } - - mockery.registerMock( '../utils/transform-commit/transformcommitforsubpackagefactory', stubs.transformCommitFunctionFactory ); - mockery.registerMock( '../utils/generatechangelogfromcommits', stubs.generateChangelogFromCommits ); - mockery.registerMock( '../utils/getsubpackagespaths', stubs.getSubPackagesPaths ); - mockery.registerMock( '../utils/displayskippedpackages', stubs.displaySkippedPackages ); - mockery.registerMock( '../utils/displaygeneratedchangelogs', stubs.displayGeneratedChangelogs ); - mockery.registerMock( '../utils/cli', stubs.cli ); - mockery.registerMock( '../utils/versions', stubs.versionUtils ); - mockery.registerMock( '../utils/getnewreleasetype', stubs.getNewReleaseType ); - mockery.registerMock( '../utils/displaycommits', stubs.displayCommits ); - - sandbox.stub( path, 'join' ).callsFake( ( ...chunks ) => chunks.join( '/' ) ); - - generateChangelogForSubPackages = proxyquire( '../../../lib/release-tools/tasks/generatechangelogforsubpackages', { - '@ckeditor/ckeditor5-dev-utils': { - tools: stubs.tools, - logger() { - return stubs.logger; - } - }, - '../utils/getpackagejson': stubs.getPackageJson, - '../utils/changelog': stubs.changelogUtils - } ); - } ); - - afterEach( () => { - sandbox.restore(); - mockery.disable(); - } ); - - describe( 'generateChangelogForSubPackages()', () => { - it( 'generates changelog entries for found sub packages', () => { - const commits = [ {}, {} ]; - const chdirStub = sandbox.stub( process, 'chdir' ); - sandbox.stub( process, 'cwd' ).returns( '/ckeditor5-dev' ); - - stubs.getSubPackagesPaths.returns( { - skipped: new Set(), - matched: new Set( [ - '/ckeditor5-dev/packages/ckeditor5-dev-foo', - '/ckeditor5-dev/packages/ckeditor5-dev-bar' - ] ) - } ); - - stubs.getPackageJson.onFirstCall().returns( { - name: '@ckeditor/ckeditor5-dev-foo', - version: '1.0.0' - } ); - stubs.versionUtils.getLastFromChangelog.onFirstCall().returns( '1.0.0' ); - stubs.getNewReleaseType.onFirstCall().returns( Promise.resolve( { commits, releaseType: 'patch' } ) ); - stubs.cli.provideVersion.onFirstCall().returns( Promise.resolve( '1.0.1' ) ); - stubs.generateChangelogFromCommits.onFirstCall().returns( Promise.resolve( '1.0.1' ) ); - - stubs.getPackageJson.onSecondCall().returns( { - name: '@ckeditor/ckeditor5-dev-bar', - version: '2.0.0' - } ); - stubs.versionUtils.getLastFromChangelog.onSecondCall().returns( '2.0.0' ); - stubs.getNewReleaseType.onSecondCall().returns( Promise.resolve( { commits, releaseType: 'minor' } ) ); - stubs.cli.provideVersion.onSecondCall().returns( Promise.resolve( '2.1.0' ) ); - stubs.generateChangelogFromCommits.onSecondCall().returns( Promise.resolve( '2.1.0' ) ); - - const generatedChangelogs = new Map( [ - [ '@ckeditor/ckeditor5-dev-foo', '1.0.1' ], - [ '@ckeditor/ckeditor5-dev-bar', '2.1.0' ] - ] ); - - const options = { - cwd: '/ckeditor5-dev', - packages: 'packages' - }; - - return generateChangelogForSubPackages( options ) - .then( () => { - expect( chdirStub.calledThrice ).to.equal( true ); - expect( chdirStub.firstCall.args[ 0 ] ).to.equal( '/ckeditor5-dev/packages/ckeditor5-dev-foo' ); - expect( chdirStub.secondCall.args[ 0 ] ).to.equal( '/ckeditor5-dev/packages/ckeditor5-dev-bar' ); - expect( chdirStub.thirdCall.args[ 0 ] ).to.equal( '/ckeditor5-dev' ); - - expect( stubs.getNewReleaseType.calledTwice ).to.equal( true ); - expect( stubs.getNewReleaseType.firstCall.args[ 0 ] ).to.equal( stubs.transformCommit[ 0 ] ); - expect( stubs.getNewReleaseType.firstCall.args[ 1 ] ).to.deep.equal( { - tagName: '@ckeditor/ckeditor5-dev-foo@1.0.0' - } ); - expect( stubs.getNewReleaseType.secondCall.args[ 0 ] ).to.equal( stubs.transformCommit[ 2 ] ); - expect( stubs.getNewReleaseType.secondCall.args[ 1 ] ).to.deep.equal( { - tagName: '@ckeditor/ckeditor5-dev-bar@2.0.0' - } ); - - expect( stubs.cli.provideVersion.calledTwice ).to.equal( true ); - expect( stubs.cli.provideVersion.firstCall.args[ 0 ] ).to.equal( '1.0.0' ); - expect( stubs.cli.provideVersion.firstCall.args[ 1 ] ).to.equal( 'patch' ); - expect( stubs.cli.provideVersion.secondCall.args[ 0 ] ).to.equal( '2.0.0' ); - expect( stubs.cli.provideVersion.secondCall.args[ 1 ] ).to.equal( 'minor' ); - - expect( stubs.logger.info.getCall( 0 ).args[ 0 ] ).to.match( - /Generating changelog for "@ckeditor\/ckeditor5-dev-foo"\.\.\./ - ); - expect( stubs.logger.info.getCall( 2 ).args[ 0 ] ).to.match( - /Generating changelog for "@ckeditor\/ckeditor5-dev-bar"\.\.\./ - ); - expect( stubs.logger.info.getCall( 4 ).args[ 0 ] ).to.match( /Committing generated changelogs\./ ); - - expect( stubs.displayGeneratedChangelogs.calledOnce ).to.equal( true ); - expect( stubs.displayGeneratedChangelogs.firstCall.args[ 0 ] ).to.deep.equal( generatedChangelogs ); - - expect( stubs.tools.shExec.calledTwice ).to.equal( true ); - expect( stubs.tools.shExec.firstCall.args[ 0 ] ).to.equal( 'git add packages/**/CHANGELOG.md' ); - expect( stubs.tools.shExec.secondCall.args[ 0 ] ).to.equal( - 'git commit -m "Docs: Updated changelog for packages. [skip ci]"' - ); - - expect( stubs.generateChangelogFromCommits.calledTwice ).to.equal( true ); - expect( stubs.generateChangelogFromCommits.firstCall.args[ 0 ] ).to.deep.equal( { - version: '1.0.1', - transformCommit: stubs.transformCommit[ 1 ], - tagName: '@ckeditor/ckeditor5-dev-foo@1.0.0', - newTagName: '@ckeditor/ckeditor5-dev-foo@1.0.1', - isInternalRelease: false - } ); - expect( stubs.generateChangelogFromCommits.secondCall.args[ 0 ] ).to.deep.equal( { - version: '2.1.0', - transformCommit: stubs.transformCommit[ 3 ], - tagName: '@ckeditor/ckeditor5-dev-bar@2.0.0', - newTagName: '@ckeditor/ckeditor5-dev-bar@2.1.0', - isInternalRelease: false - } ); - - expect( stubs.displayCommits.calledTwice ).to.equal( true ); - expect( stubs.displayCommits.firstCall.args[ 0 ] ).to.deep.equal( commits ); - expect( stubs.displayCommits.secondCall.args[ 0 ] ).to.deep.equal( commits ); - } ); - } ); - - it( 'ignores specified packages', () => { - const commits = [ {}, {} ]; - const chdirStub = sandbox.stub( process, 'chdir' ); - sandbox.stub( process, 'cwd' ).returns( '/ckeditor5-dev' ); - - stubs.getSubPackagesPaths.returns( { - skipped: new Set( [ - '/ckeditor5-dev/packages/ckeditor5-dev-bar' - ] ), - matched: new Set( [ - '/ckeditor5-dev/packages/ckeditor5-dev-foo' - ] ) - } ); - - stubs.getPackageJson.onFirstCall().returns( { - name: '@ckeditor/ckeditor5-dev-foo', - version: '1.0.0' - } ); - stubs.versionUtils.getLastFromChangelog.onFirstCall().returns( '1.0.0' ); - stubs.getNewReleaseType.onFirstCall().returns( Promise.resolve( { commits, releaseType: 'patch' } ) ); - stubs.cli.provideVersion.onFirstCall().returns( Promise.resolve( '1.0.1' ) ); - stubs.generateChangelogFromCommits.onFirstCall().returns( Promise.resolve( '1.0.1' ) ); - - const options = { - cwd: '/ckeditor5-dev', - packages: 'packages' - }; - - return generateChangelogForSubPackages( options ) - .then( () => { - expect( chdirStub.calledTwice ).to.equal( true ); - expect( chdirStub.firstCall.args[ 0 ] ).to.equal( '/ckeditor5-dev/packages/ckeditor5-dev-foo' ); - expect( chdirStub.secondCall.args[ 0 ] ).to.equal( '/ckeditor5-dev' ); - - expect( stubs.getNewReleaseType.calledOnce ).to.equal( true ); - expect( stubs.cli.provideVersion.calledOnce ).to.equal( true ); - - expect( stubs.displaySkippedPackages.calledOnce ).to.equal( true ); - expect( stubs.displaySkippedPackages.firstCall.args[ 0 ] ).to.deep.equal( new Set( [ - '/ckeditor5-dev/packages/ckeditor5-dev-bar' - ] ) ); - - expect( stubs.generateChangelogFromCommits.firstCall.args[ 0 ] ).to.deep.equal( { - version: '1.0.1', - transformCommit: stubs.transformCommit[ 1 ], - tagName: '@ckeditor/ckeditor5-dev-foo@1.0.0', - newTagName: '@ckeditor/ckeditor5-dev-foo@1.0.1', - isInternalRelease: false - } ); - - expect( stubs.displayCommits.calledOnce ).to.equal( true ); - expect( stubs.displayCommits.firstCall.args[ 0 ] ).to.deep.equal( commits ); - } ); - } ); - - it( 'displays packages which will not have a new entry in changelog', () => { - const chdirStub = sandbox.stub( process, 'chdir' ); - sandbox.stub( process, 'cwd' ).returns( '/ckeditor5-dev' ); - - stubs.getSubPackagesPaths.returns( { - skipped: new Set(), - matched: new Set( [ - '/ckeditor5-dev/packages/ckeditor5-dev-foo' - ] ) - } ); - - stubs.getPackageJson.onFirstCall().returns( { - name: '@ckeditor/ckeditor5-dev-foo', - version: '1.0.0' - } ); - stubs.versionUtils.getLastFromChangelog.onFirstCall().returns( '1.0.0' ); - stubs.getNewReleaseType.onFirstCall().returns( Promise.resolve( { releaseType: 'skip' } ) ); - stubs.cli.provideVersion.onFirstCall().returns( Promise.resolve( 'skip' ) ); - - const options = { - cwd: '/ckeditor5-dev', - packages: 'packages' - }; - - return generateChangelogForSubPackages( options ) - .then( () => { - expect( chdirStub.calledTwice ).to.equal( true ); - expect( chdirStub.firstCall.args[ 0 ] ).to.equal( '/ckeditor5-dev/packages/ckeditor5-dev-foo' ); - expect( chdirStub.secondCall.args[ 0 ] ).to.equal( '/ckeditor5-dev' ); - - expect( stubs.getNewReleaseType.calledOnce ).to.equal( true ); - expect( stubs.cli.provideVersion.calledOnce ).to.equal( true ); - expect( stubs.cli.provideVersion.firstCall.args[ 0 ] ).to.equal( '1.0.0' ); - expect( stubs.cli.provideVersion.firstCall.args[ 1 ] ).to.equal( null ); - - expect( stubs.displaySkippedPackages.calledOnce ).to.equal( true ); - expect( stubs.displaySkippedPackages.firstCall.args[ 0 ] ).to.deep.equal( new Set( [ - '/ckeditor5-dev/packages/ckeditor5-dev-foo' - ] ) ); - - expect( stubs.tools.shExec.called ).to.equal( false ); - expect( stubs.generateChangelogFromCommits.called ).to.equal( false ); - } ); - } ); - - it( 'allows generating changelog as "internal" release', () => { - sandbox.stub( process, 'chdir' ); - sandbox.stub( process, 'cwd' ).returns( '/ckeditor5-dev' ); - - stubs.getSubPackagesPaths.returns( { - skipped: new Set(), - matched: new Set( [ - '/ckeditor5-dev/packages/ckeditor5-dev-foo', - '/ckeditor5-dev/packages/ckeditor5-dev-bar' - ] ) - } ); - - stubs.getPackageJson.onFirstCall().returns( { - name: '@ckeditor/ckeditor5-dev-foo', - version: '1.0.0' - } ); - stubs.versionUtils.getLastFromChangelog.onFirstCall().returns( '1.0.0' ); - stubs.getNewReleaseType.onFirstCall().returns( Promise.resolve( { releaseType: 'patch' } ) ); - stubs.cli.provideVersion.onFirstCall().returns( Promise.resolve( 'internal' ) ); - stubs.generateChangelogFromCommits.onFirstCall().returns( Promise.resolve( '1.0.1' ) ); - - stubs.getPackageJson.onSecondCall().returns( { - name: '@ckeditor/ckeditor5-dev-bar', - version: '2.0.0' - } ); - stubs.versionUtils.getLastFromChangelog.onSecondCall().returns( '2.0.0' ); - stubs.getNewReleaseType.onSecondCall().returns( Promise.resolve( { releaseType: 'minor' } ) ); - stubs.cli.provideVersion.onSecondCall().returns( Promise.resolve( 'internal' ) ); - stubs.generateChangelogFromCommits.onSecondCall().returns( Promise.resolve( '2.0.1' ) ); - - const options = { - cwd: '/ckeditor5-dev', - packages: 'packages' - }; - - return generateChangelogForSubPackages( options ) - .then( () => { - expect( stubs.generateChangelogFromCommits.calledTwice ).to.equal( true ); - expect( stubs.generateChangelogFromCommits.firstCall.args[ 0 ] ).to.deep.equal( { - version: '1.0.1', - transformCommit: stubs.transformCommit[ 1 ], - tagName: '@ckeditor/ckeditor5-dev-foo@1.0.0', - newTagName: '@ckeditor/ckeditor5-dev-foo@1.0.1', - isInternalRelease: true - } ); - expect( stubs.generateChangelogFromCommits.secondCall.args[ 0 ] ).to.deep.equal( { - version: '2.0.1', - transformCommit: stubs.transformCommit[ 3 ], - tagName: '@ckeditor/ckeditor5-dev-bar@2.0.0', - newTagName: '@ckeditor/ckeditor5-dev-bar@2.0.1', - isInternalRelease: true - } ); - } ); - } ); - } ); -} ); diff --git a/packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/package.json b/packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/package.json deleted file mode 100644 index de7053ca3..000000000 --- a/packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "@ckeditor/foo-bar", - "version": "0.1.0", - "dependencies": { - "@ckeditor/alpha": "*", - "@ckeditor/beta": "*", - "@ckeditor/gamma": "*", - "@ckeditor/delta": "*", - "@ckeditor/epsilon": "*", - "@ckeditor/ckeditor5-dev-kappa": "*" - }, - "repository": { - "url": "https://github.com/ckeditor/foo-bar.git" - } -} diff --git a/packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/alpha/package.json b/packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/alpha/package.json deleted file mode 100644 index b621d7ec6..000000000 --- a/packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/alpha/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@ckeditor/alpha", - "version": "0.0.1", - "dependencies": { - "@ckeditor/beta": "*", - "@ckeditor/gamma": "*" - }, - "devDependencies": { - "@ckeditor/epsilon": "*" - }, - "peerDependencies": { - "ckeditor5-dev": "0.0.1" - }, - "repository": { - "url": "https://github.com/ckeditor/alpha.git" - } -} diff --git a/packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/beta/package.json b/packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/beta/package.json deleted file mode 100644 index 7bcc074cc..000000000 --- a/packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/beta/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "@ckeditor/beta", - "version": "0.2.0", - "dependencies": { - "@ckeditor/gamma": "*", - "@ckeditor/epsilon": "*" - }, - "repository": { - "url": "https://github.com/ckeditor/beta.git" - } -} diff --git a/packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/delta/package.json b/packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/delta/package.json deleted file mode 100644 index 76b121a8f..000000000 --- a/packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/delta/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@ckeditor/delta", - "version": "0.4.0", - "dependencies": { - "@ckeditor/alpha": "*", - "@ckeditor/gamma": "*" - }, - "devDependencies": { - "@ckeditor/beta": "*" - }, - "peerDependencies": { - "ckeditor5-dev": "0.0.1" - }, - "repository": { - "url": "https://github.com/ckeditor/delta.git" - } -} diff --git a/packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/dev-kappa/package.json b/packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/dev-kappa/package.json deleted file mode 100644 index d2ae2c8ce..000000000 --- a/packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/dev-kappa/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "@ckeditor/ckeditor5-dev-kappa", - "version": "1.0.0", - "dependencies": {}, - "devDependencies": {}, - "repository": { - "url": "https://github.com/ckeditor/ckeditor5-dev-kappa.git" - } -} diff --git a/packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/epsilon/package.json b/packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/epsilon/package.json deleted file mode 100644 index afbb4054e..000000000 --- a/packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/epsilon/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "@ckeditor/epsilon", - "version": "0.5.0", - "dependencies": { - "@ckeditor/alpha": "*" - }, - "devDependencies": { - "@ckeditor/beta": "*" - }, - "repository": { - "url": "https://github.com/ckeditor/epsilon.git" - } -} diff --git a/packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/gamma/package.json b/packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/gamma/package.json deleted file mode 100644 index 8ef7effdc..000000000 --- a/packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/gamma/package.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "@ckeditor/gamma", - "version": "0.3.0", - "devDependencies": { - "@ckeditor/epsilon": "*" - }, - "repository": { - "url": "https://github.com/ckeditor/gamma.git" - } -} diff --git a/packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/omega/package.json b/packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/omega/package.json deleted file mode 100644 index e030c1498..000000000 --- a/packages/ckeditor5-dev-env/tests/release-tools/tasks/stubs/releasesubrepositories/packages/omega/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@ckeditor/omega", - "version": "1.0.0", - "dependencies": { - "@ckeditor/beta": "*", - "@ckeditor/gamma": "*" - }, - "devDependencies": { - "@ckeditor/epsilon": "*" - }, - "peerDependencies": { - "ckeditor5-dev": "0.0.1" - }, - "repository": { - "url": "https://github.com/ckeditor/omega.git" - } -} From 0a921f00d08a9aafd3ed88cbf3203cd9f7323168 Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Fri, 15 May 2020 10:14:30 +0200 Subject: [PATCH 07/33] Prepare the repository to be handled as `ckeditor5` repository. --- README.md | 41 +++++++++++++------ package.json | 10 ++++- packages/ckeditor5-dev-docs/package.json | 6 ++- packages/ckeditor5-dev-env/package.json | 6 ++- packages/ckeditor5-dev-tests/package.json | 6 ++- packages/ckeditor5-dev-utils/package.json | 6 ++- .../ckeditor5-dev-webpack-plugin/package.json | 6 ++- packages/jsdoc-plugins/package.json | 6 ++- scripts/bump-versions.js | 31 ++++++++++++++ scripts/changelog.js | 11 ++++- scripts/publish.js | 32 +++++++++++++++ 11 files changed, 139 insertions(+), 22 deletions(-) create mode 100755 scripts/bump-versions.js create mode 100755 scripts/publish.js diff --git a/README.md b/README.md index aeaa0705a..23a7c68c8 100644 --- a/README.md +++ b/README.md @@ -52,20 +52,37 @@ Code coverage: yarn run coverage ``` -## Releasing +## Releasing packages + +### Changelog 1. Fetch all changes and switch to `master`! -1. Execute `yarn run changelog`. - * This task checks what changed in each package and bumps the version accordingly. If nothing changed at all, it won't create a new changelog entry. If changes were irrelevant (e.g. only depedencies) it will create an "internal changes" entry. - * Scan the logs which are printed by the tool in search for errors (incorrect changelog entries). Incorrect entries (e.g. ones without the type) are being ignored. You may need to create entries for them manually. This is done directly in `CHANGELOG.md` of the specific package. Make sure to verify the proposed version after you modify the changelog. - * When unsure what has really changed in this version of a specific package, use `git diff packages/ckeditor5-dev-/`. -1. After reviewing the changelog and committing all changes do `git push`. -1. Now, you can release the changed packages by using `lerna publish`. - * Lerna may propose to release more packages than you'd want – e.g. one of the packages might have some totally irrelevant change which you don't want to release now. You can do that by calling e.g.: `lerna publish --scope="@ckeditor/ckeditor5-dev-?(env|utils|webpack-plugin)"`. However, this means that if one of ignored packages depends on one of the release ones it won't have a version bump... so **usually it's better to just release everything**. - * Lerna will propose to release more packages than the one in which new changelog entries were generated – those are packages which depend on the ones which were really updated. That's fine. - * You need to pick version number of every package that Lerna wants to release. Do that based on what `yarn run changelog` proposed. - * Finally, Lerna says it will publish also `ckeditor5-dev` itself. This isn't true as its a private package, but it will be tagged anyway. **Whenever there's a major release in any of the sub packages, make sure to pick major release of `ckeditor5-dev` too**. Thanks to that it's possible later to get back to the previous stable releases e.g. if a hot fix is needed. -1. Your job's done. You can go now to `ckeditor5`, remove `yarn.lock`, potentially update something in `package.json`, run `yarn install` and commit that as `"Internal: Updated dependencies."`. +2. Execute `yarn run changelog`: + * This task checks what changed in each package and bumps the version accordingly. If nothing changed at all, it won't create a new changelog entry. If changes were irrelevant (e.g. only depedencies) it will create an "internal changes" entry. + * Scan the logs which are printed by the tool in search for errors (incorrect changelog entries). Incorrect entries (e.g. ones without the type) are being ignored. You may need to create entries for them manually. This is done directly in `CHANGELOG.md` (in the root directory). Make sure to verify the proposed version after you modify the changelog. + * When unsure what has really changed in this version of a specific package, use `git diff packages/ckeditor5-dev-/`. + +### Publishing + +After generating the changelog, you are able to release the package. + +First, you need to bump the version: + +```bash +yarn run release:bump-version +``` + +You can also use the `--dry-run` option in order to see what this task does. + +After bumping the version, you can publish the changes: + +```bash +yarn run release:publish +``` + +As in the previous task, the `--dry-run` option is also available. + +Your job's done. You can go now to `ckeditor5`, remove `yarn.lock`, potentially update something in `package.json`, run `yarn install` and commit that as `"Internal: Updated dependencies."`. ## License diff --git a/package.json b/package.json index 0b4f8323e..b59b3c31e 100644 --- a/package.json +++ b/package.json @@ -23,11 +23,17 @@ "author": "CKSource (http://cksource.com/)", "license": "GPL-2.0-or-later", "bugs": "https://github.com/ckeditor/ckeditor5-dev/issues", + "repository": { + "type": "git", + "url": "https://github.com/ckeditor/ckeditor5-dev.git" + }, "homepage": "https://github.com/ckeditor/ckeditor5-dev#readme", "scripts": { - "test": "mocha packages/ckeditor5-dev-env/tests --recursive --timeout 5000", + "test": "mocha packages/*/tests --recursive --timeout 5000", "coverage": "istanbul cover _mocha packages/*/tests -- --recursive --timeout 5000", - "changelog": "node ./scripts/changelog.js", + "changelog": "node ./scripts/release/changelog.js", + "release:bump-version": "node ./scripts/release/bump-versions.js", + "release:publish": "node ./scripts/release/publish.js", "lint": "eslint --quiet '**/*.js'", "precommit": "lint-staged" }, diff --git a/packages/ckeditor5-dev-docs/package.json b/packages/ckeditor5-dev-docs/package.json index 59a6706a7..f6333c610 100644 --- a/packages/ckeditor5-dev-docs/package.json +++ b/packages/ckeditor5-dev-docs/package.json @@ -23,5 +23,9 @@ "license": "GPL-2.0-or-later", "homepage": "https://github.com/ckeditor/ckeditor5-dev/tree/master/packages/ckeditor5-dev-docs", "bugs": "https://github.com/ckeditor/ckeditor5-dev/issues", - "repository": "https://github.com/ckeditor/ckeditor5-dev" + "repository": { + "type": "git", + "url": "https://github.com/ckeditor/ckeditor5-dev.git", + "directory": "packages/ckeditor5-dev-docs" + } } diff --git a/packages/ckeditor5-dev-env/package.json b/packages/ckeditor5-dev-env/package.json index 2a5500163..78e3213c0 100644 --- a/packages/ckeditor5-dev-env/package.json +++ b/packages/ckeditor5-dev-env/package.json @@ -47,5 +47,9 @@ "license": "GPL-2.0-or-later", "homepage": "https://github.com/ckeditor/ckeditor5-dev/tree/master/packages/ckeditor5-dev-env", "bugs": "https://github.com/ckeditor/ckeditor5-dev/issues", - "repository": "https://github.com/ckeditor/ckeditor5-dev" + "repository": { + "type": "git", + "url": "https://github.com/ckeditor/ckeditor5-dev.git", + "directory": "packages/ckeditor5-dev-env" + } } diff --git a/packages/ckeditor5-dev-tests/package.json b/packages/ckeditor5-dev-tests/package.json index d545b303e..4783a0fd9 100644 --- a/packages/ckeditor5-dev-tests/package.json +++ b/packages/ckeditor5-dev-tests/package.json @@ -74,5 +74,9 @@ "license": "GPL-2.0-or-later", "homepage": "https://github.com/ckeditor/ckeditor5-dev/tree/master/packages/ckeditor5-dev-tests", "bugs": "https://github.com/ckeditor/ckeditor5-dev/issues", - "repository": "https://github.com/ckeditor/ckeditor5-dev" + "repository": { + "type": "git", + "url": "https://github.com/ckeditor/ckeditor5-dev.git", + "directory": "packages/ckeditor5-dev-tests" + } } diff --git a/packages/ckeditor5-dev-utils/package.json b/packages/ckeditor5-dev-utils/package.json index 0e13b2ffc..03d552d6a 100644 --- a/packages/ckeditor5-dev-utils/package.json +++ b/packages/ckeditor5-dev-utils/package.json @@ -40,5 +40,9 @@ "license": "GPL-2.0-or-later", "homepage": "https://github.com/ckeditor/ckeditor5-dev/tree/master/packages/ckeditor5-dev-utils", "bugs": "https://github.com/ckeditor/ckeditor5-dev/issues", - "repository": "https://github.com/ckeditor/ckeditor5-dev" + "repository": { + "type": "git", + "url": "https://github.com/ckeditor/ckeditor5-dev.git", + "directory": "packages/ckeditor5-dev-utils" + } } diff --git a/packages/ckeditor5-dev-webpack-plugin/package.json b/packages/ckeditor5-dev-webpack-plugin/package.json index 4b2f3e2ef..2ca6a2f8f 100644 --- a/packages/ckeditor5-dev-webpack-plugin/package.json +++ b/packages/ckeditor5-dev-webpack-plugin/package.json @@ -24,5 +24,9 @@ "license": "GPL-2.0-or-later", "homepage": "https://github.com/ckeditor/ckeditor5-dev/tree/master/packages/ckeditor5-dev-webpack-plugin", "bugs": "https://github.com/ckeditor/ckeditor5-dev/issues", - "repository": "https://github.com/ckeditor/ckeditor5-dev" + "repository": { + "type": "git", + "url": "https://github.com/ckeditor/ckeditor5-dev.git", + "directory": "packages/ckeditor5-dev-webpack-plugin" + } } diff --git a/packages/jsdoc-plugins/package.json b/packages/jsdoc-plugins/package.json index 4467b1678..66191653d 100644 --- a/packages/jsdoc-plugins/package.json +++ b/packages/jsdoc-plugins/package.json @@ -30,5 +30,9 @@ "license": "MIT", "homepage": "https://github.com/ckeditor/ckeditor5-dev/tree/master/packages/jsdoc-plugins", "bugs": "https://github.com/ckeditor/ckeditor5-dev/issues", - "repository": "https://github.com/ckeditor/ckeditor5-dev" + "repository": { + "type": "git", + "url": "https://github.com/ckeditor/ckeditor5-dev.git", + "directory": "packages/jsdoc-plugins" + } } diff --git a/scripts/bump-versions.js b/scripts/bump-versions.js new file mode 100755 index 000000000..ff4ab56db --- /dev/null +++ b/scripts/bump-versions.js @@ -0,0 +1,31 @@ +#!/usr/bin/env node + +/** + * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/* eslint-env node */ + +'use strict'; + +// This scripts preparing all packages to release: +// - checking what should be released, +// - updates version of all dependencies for all packages, +// - validates the whole process (whether the changes could be published), +// - tagging new versions. +// +// You can test the whole process using `dry-run` mode. It won't change anything in the project +// and any repository. +// +// This task must be called before: `yarn run release:publish`. +// +// Use: +// yarn run release:bump-version --dry-run + +require( '../packages/ckeditor5-dev-env' ) + .bumpVersions( { + cwd: process.cwd(), + packages: 'packages', + dryRun: process.argv.includes( '--dry-run' ) + } ); diff --git a/scripts/changelog.js b/scripts/changelog.js index 854405404..17b107e65 100755 --- a/scripts/changelog.js +++ b/scripts/changelog.js @@ -8,7 +8,14 @@ 'use strict'; require( '../packages/ckeditor5-dev-env' ) - .generateChangelogForSubPackages( { + .generateChangelogForMonoRepository( { cwd: process.cwd(), - packages: 'packages' + packages: 'packages', + transformScope: name => { + if ( name.startsWith( 'dev-' ) ) { + return 'https://www.npmjs.com/package/@ckeditor/ckeditor5-' + name; + } + + return 'https://www.npmjs.com/package/@ckeditor/' + name; + } } ); diff --git a/scripts/publish.js b/scripts/publish.js new file mode 100755 index 000000000..8b0abfbc7 --- /dev/null +++ b/scripts/publish.js @@ -0,0 +1,32 @@ +#!/usr/bin/env node + +/** + * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/* eslint-env node */ + +'use strict'; + +// This scripts publish changes. +// +// You can test the whole process using `dry-run` mode. It won't change anything in the project +// and any repository. Nothing will be pushed. Instead of `npm publish`, the `npm pack` command will be called. +// +// Note: This task based on versions published on NPM and GitHub. If something went wrong, you can call this script one more time. +// +// This task should be executed after: `yarn run release:bump-version`. +// +// Use: +// yarn run release:publish --dry-run + +require( '../packages/ckeditor5-dev-env' ) + .releaseSubRepositories( { + cwd: process.cwd(), + packages: 'packages', + skipNpmPublish: [ + 'ckeditor5-dev' + ], + dryRun: process.argv.includes( '--dry-run' ) + } ); From 9979c9e28e5a47ece87f22c3cacb7df8d63dd5d1 Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Fri, 15 May 2020 10:22:35 +0200 Subject: [PATCH 08/33] Changelogs should point to the main repository. --- packages/ckeditor5-dev-docs/CHANGELOG.md | 208 +----- packages/ckeditor5-dev-env/CHANGELOG.md | 519 +------------- packages/ckeditor5-dev-tests/CHANGELOG.md | 638 +----------------- packages/ckeditor5-dev-utils/CHANGELOG.md | 293 +------- .../ckeditor5-dev-webpack-plugin/CHANGELOG.md | 168 +---- packages/jsdoc-plugins/CHANGELOG.md | 244 +------ 6 files changed, 6 insertions(+), 2064 deletions(-) diff --git a/packages/ckeditor5-dev-docs/CHANGELOG.md b/packages/ckeditor5-dev-docs/CHANGELOG.md index ef8d37451..2cc0cf250 100644 --- a/packages/ckeditor5-dev-docs/CHANGELOG.md +++ b/packages/ckeditor5-dev-docs/CHANGELOG.md @@ -1,210 +1,4 @@ Changelog ========= -## [11.0.13](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@11.0.11...@ckeditor/ckeditor5-dev-docs@11.0.13) (2020-02-26) - -Internal changes only (updated dependencies, documentation, etc.). - - -## [11.0.11](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@11.0.10...@ckeditor/ckeditor5-dev-docs@11.0.11) (2020-01-27) - -### Bug fixes - -* Switched to a fork of JSDoc with version 3.4.3 patched to be compatible with NodeJS 12. Also, bumped chalk library to fix thrown error. Closes [#525](https://github.com/ckeditor/ckeditor5-dev/issues/525). ([a7599ba](https://github.com/ckeditor/ckeditor5-dev/commit/a7599ba)) - - -## [11.0.10](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@11.0.1...@ckeditor/ckeditor5-dev-docs@11.0.10) (2020-01-09) - -Internal changes only (updated dependencies, documentation, etc.). - - -## [11.0.1](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@11.0.0...@ckeditor/ckeditor5-dev-docs@11.0.1) (2019-02-28) - -Internal changes only (updated dependencies, documentation, etc.). - - -## [11.0.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@10.0.4...@ckeditor/ckeditor5-dev-docs@11.0.0) (2019-02-19) - -### BREAKING CHANGES - -* Upgraded minimal versions of Node to `8.0.0` and npm to `5.7.1`. See: [ckeditor/ckeditor5#1507](https://github.com/ckeditor/ckeditor5/issues/1507). ([612ea3c](https://github.com/ckeditor/ckeditor5-cloud-services/commit/612ea3c)) - - -## [10.0.4](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@10.0.1...@ckeditor/ckeditor5-dev-docs@10.0.4) (2019-02-12) - -Internal changes only (updated dependencies, documentation, etc.). - - -## [10.0.1](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@10.0.0...@ckeditor/ckeditor5-dev-docs@10.0.1) (2018-09-24) - -Internal changes only (updated dependencies, documentation, etc.). - - -## [10.0.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@9.0.7...@ckeditor/ckeditor5-dev-docs@10.0.0) (2018-08-23) - -Updated required Node.js version to `>=6.9.0`. - - -## [9.0.7](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@9.0.0...@ckeditor/ckeditor5-dev-docs@9.0.7) (2018-07-17) - -Internal changes only (updated dependencies, documentation, etc.). - - -## [9.0.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@8.0.14...@ckeditor/ckeditor5-dev-docs@9.0.0) (2018-04-25) - -### Other changes - -* Changed the license to GPL2+ only. See [ckeditor/ckeditor5#991](https://github.com/ckeditor/ckeditor5/issues/991). ([e392d7d](https://github.com/ckeditor/ckeditor5-dev/commit/e392d7d)) - -### BREAKING CHANGES - -* The license under which CKEditor 5 is released has been changed from a triple GPL, LGPL and MPL license to GPL2+ only. See [ckeditor/ckeditor5#991](https://github.com/ckeditor/ckeditor5/issues/991) for more information. - - -## [8.0.14](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@8.0.13...@ckeditor/ckeditor5-dev-docs@8.0.14) (2018-03-27) - -Internal changes only (updated dependencies, documentation, etc.). - - -## [8.0.13](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@8.0.8...@ckeditor/ckeditor5-dev-docs@8.0.13) (2018-03-22) - -Internal changes only (updated dependencies, documentation, etc.). - - -## [8.0.8](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@8.0.0...@ckeditor/ckeditor5-dev-docs@8.0.8) (2018-01-22) - -### Other changes - -* Removed script for publishing nightly builds of the docs. See https://github.com/ckeditor/ckeditor5/issues/769. ([fa847e0](https://github.com/ckeditor/ckeditor5-dev/commit/fa847e0)) - - -## [8.0.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@7.5.0...@ckeditor/ckeditor5-dev-docs@8.0.0) (2017-11-13) - -### Other changes - -* Removed gulp dependency across the whole project. Closes [#296](https://github.com/ckeditor/ckeditor5-dev/issues/296). ([723bee5](https://github.com/ckeditor/ckeditor5-dev/commit/723bee5)) - - Now all packages use only npm scripts. Depending on usage you might either create a `"script"` entry in `pacakge.json` to invoke bin executables or require the library into a script. - - * Package `ckeditor5-dev-env` exposes new `translations` binary. - * Package `ckeditor5-dev-tests` exposes new `test:manual` binary. - * Removed `gulp-jsdoc3` from `ckeditor5-dev-docs`. Now `jsdoc` is invoked directly. - * Removed `options` param from logger methods. Logger no longer uses `gutil.log` method. - -### BREAKING CHANGES - -* Gulp tasks were removed. New npm scripts were introduced. - - -## [7.5.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@7.4.1...@ckeditor/ckeditor5-dev-docs@7.5.0) (2017-10-10) - -### Features - -* Provided support for `@observable` tag. Closes [#285](https://github.com/ckeditor/ckeditor5-dev/issues/285). ([fed57af](https://github.com/ckeditor/ckeditor5-dev/commit/fed57af)) - - -## [7.4.1](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@7.4.0...@ckeditor/ckeditor5-dev-docs@7.4.1) (2017-10-01) - -Internal changes only (updated dependencies, documentation, etc.). - -## [7.4.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@7.3.4...@ckeditor/ckeditor5-dev-docs@7.4.0) (2017-09-20) - -### Features - -* Provided `[@error](https://github.com/error)` tag detection in JSDoc. Closes [#280](https://github.com/ckeditor/ckeditor5-dev/issues/280). ([b7a0cf5](https://github.com/ckeditor/ckeditor5-dev/commit/b7a0cf5)) - - -## [7.3.4](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@7.3.0...@ckeditor/ckeditor5-dev-docs@7.3.4) (2017-09-05) - -### Other changes - -* Build nightly docs in production mode (minified). ([6315c74](https://github.com/ckeditor/ckeditor5-dev/commit/6315c74)) - - -## [7.3.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@7.2.2...@ckeditor/ckeditor5-dev-docs@7.3.0) (2017-08-18) - -### Features - -* All events will be automatically extended with `EventInfo` parameter. Closes [#257](https://github.com/ckeditor/ckeditor5-dev/issues/257). ([3968bd0](https://github.com/ckeditor/ckeditor5-dev/commit/3968bd0)) - - -## [7.2.2](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@7.2.1...@ckeditor/ckeditor5-dev-docs@7.2.2) (2017-07-12) - -### Bug fixes - -* Nightly docs should be available in latest/ and / directories on ckeditor.com. Closes [#242](https://github.com/ckeditor/ckeditor5-dev/issues/242). ([ff487ee](https://github.com/ckeditor/ckeditor5-dev/commit/ff487ee)) - - -## [7.2.1](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@7.2.0...@ckeditor/ckeditor5-dev-docs@7.2.1) (2017-07-11) - -### Bug fixes - -* Use a fork of gulp-jsdoc3 so we can harcode JSDoc version (to one with which our plugins work). See [#240](https://github.com/ckeditor/ckeditor5-dev/issues/240). ([2a494eb](https://github.com/ckeditor/ckeditor5-dev/commit/2a494eb)) - - -## [7.2.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@7.1.1...@ckeditor/ckeditor5-dev-docs@7.2.0) (2017-06-20) - -### Features - -* Static and mixed method, properties and events will be inherited too. Closes [#226](https://github.com/ckeditor/ckeditor5-dev/issues/226). ([a160840](https://github.com/ckeditor/ckeditor5-dev/commit/a160840)) - - -## [7.1.1](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@7.1.0...@ckeditor/ckeditor5-dev-docs@7.1.1) (2017-06-15) - -### Other changes - -* The publish-nightly script should check if it's triggered by a cron job (the check was temporarily disabled). ([3dece10](https://github.com/ckeditor/ckeditor5-dev/commit/3dece10)) - - -## [7.1.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@7.0.0...@ckeditor/ckeditor5-dev-docs@7.1.0) (2017-06-14) - -### Features - -* Added a bin script for publishing nightly builds of CKEditor 5 documentation. Closes [#230](https://github.com/ckeditor/ckeditor5-dev/issues/230). ([0d15864](https://github.com/ckeditor/ckeditor5-dev/commit/0d15864)) - - -## [7.0.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@6.4.0...@ckeditor/ckeditor5-dev-docs@7.0.0) (2017-05-29) - -### Other changes - -* Changed the option name from `validationOnly` to `validateOnly` to match CLI style. Closes [#223](https://github.com/ckeditor/ckeditor5-dev/issues/223). ([cbd8c3d](https://github.com/ckeditor/ckeditor5-dev/commit/cbd8c3d)) - -### BREAKING CHANGES - -* The `validationOnly` option is now called `validateOnly`. - - -## [6.4.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@6.3.0...@ckeditor/ckeditor5-dev-docs@6.4.0) (2017-05-29) - -### Features - -* Allow breaking the process if API docs validation fails. Closes [#221](https://github.com/ckeditor/ckeditor5-dev/issues/221). ([e2f0dec](https://github.com/ckeditor/ckeditor5-dev/commit/e2f0dec)) - - -## [6.3.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@6.2.3...@ckeditor/ckeditor5-dev-docs@6.3.0) (2017-05-18) - -### Features - -* Introduced JSDoc plugin enabling inheritance of static members. Closes [#201](https://github.com/ckeditor/ckeditor5-dev/issues/201). ([08c0a21](https://github.com/ckeditor/ckeditor5-dev/commit/08c0a21)) - - -## [6.2.3](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@6.2.2...@ckeditor/ckeditor5-dev-docs@6.2.3) (2017-05-18) - -### Bug fixes - -* Use more reliable way to resolve module paths. Closes [#206](https://github.com/ckeditor/ckeditor5-dev/issues/206). ([41e6a95](https://github.com/ckeditor/ckeditor5-dev/commit/41e6a95)) - - -## [6.2.2](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@6.2.1...@ckeditor/ckeditor5-dev-docs@6.2.2) - -Internal changes only (updated dependencies, documentation, etc.). - - -## [6.2.1](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-docs@6.2.0...@ckeditor/ckeditor5-dev-docs@6.2.1) (2017-04-27) - -Internal changes only (updated dependencies, documentation, etc.). - - -## 6.2.0 - -The big bang. +All changes in the package are documented in the main repository. See: https://github.com/ckeditor/ckeditor5-dev/blob/master/CHANGELOG.md. diff --git a/packages/ckeditor5-dev-env/CHANGELOG.md b/packages/ckeditor5-dev-env/CHANGELOG.md index c24c9e4df..2cc0cf250 100644 --- a/packages/ckeditor5-dev-env/CHANGELOG.md +++ b/packages/ckeditor5-dev-env/CHANGELOG.md @@ -1,521 +1,4 @@ Changelog ========= -## [18.0.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@17.1.4...@ckeditor/ckeditor5-dev-env@18.0.0) (2020-04-23) - -### BREAKING CHANGES - -* Omitting the language property in the `CKEditorWebpackPlugin` will not have any effect from now. This means that in both cases only the main `language` will be added to the main bundle and translations for other languages will be saved in separate files. -* The translation process no longer creates short ids for message strings. From now, the source code will not be changed by the translation process, translations for the main language will be added to the bundle(s) and translations for other languages will be outputted to separate executable Javascript files. - -### Features - -* Introduced support for plural translation forms. Closes [ckeditor/ckeditor5#6526](https://github.com/ckeditor/ckeditor5/issues/6526). Closes [ckeditor/ckeditor5#988](https://github.com/ckeditor/ckeditor5/issues/988). ([305590e](https://github.com/ckeditor/ckeditor5-dev/commit/305590e)) - - -## [17.1.4](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@17.1.3...@ckeditor/ckeditor5-dev-env@17.1.4) (2020-02-26) - -Internal changes only (updated dependencies, documentation, etc.). - - -## [17.1.3](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@17.1.2...@ckeditor/ckeditor5-dev-env@17.1.3) (2020-02-14) - -### Bug fixes - -* Fixed handling of the " character in translation messages and contexts. Closes [#523](https://github.com/ckeditor/ckeditor5-dev/issues/523). ([1d2da09](https://github.com/ckeditor/ckeditor5-dev/commit/1d2da09)) - - -## [17.1.2](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@17.1.1...@ckeditor/ckeditor5-dev-env@17.1.2) (2020-01-27) - -### Bug fixes - -* Switched to a fork of JSDoc with version 3.4.3 patched to be compatible with NodeJS 12. Also, bumped chalk library to fix thrown error. Closes [#525](https://github.com/ckeditor/ckeditor5-dev/issues/525). ([a7599ba](https://github.com/ckeditor/ckeditor5-dev/commit/a7599ba)) - - -## [17.1.1](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@17.1.0...@ckeditor/ckeditor5-dev-env@17.1.1) (2020-01-09) - -Internal changes only (updated dependencies, documentation, etc.). - - -## [17.1.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@17.0.0...@ckeditor/ckeditor5-dev-env@17.1.0) (2019-12-04) - -### Features - -* Introduced several improvements for `generateSummaryChangelog()` and `generateChangelogForSubRepositories()` tasks. Closes [#571](https://github.com/ckeditor/ckeditor5-dev/issues/571). ([ec6282f](https://github.com/ckeditor/ckeditor5-dev/commit/ec6282f)) - - -## [17.0.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@16.0.0...@ckeditor/ckeditor5-dev-env@17.0.0) (2019-10-22) - -### MAJOR BREAKING CHANGES - -* `generateChangelogForSubRepositories()` and `generateSummaryChangelog()` do not accept `options.newVersion` as an option anymore. -* `transformCommitForSubPackage()` and `transformCommitForSubRepository()` end with a suffix `Factory` (included as lower case in their file names). Now those functions return a new function that parses the commit (module replaced with a factory pattern). The `returnInvalidCommit` option was moved from `context` object to a factory function (as `options`). - -### NOTE - -* `generateChangelogForSinglePackage()` accepts an option `options.isInternalRelease` that specifies whether the release is "internal". Because the `options.newVersion` option can be specified as `'major'`, we need an additional parameter that will keep the internal release note. If `options.newVersion` is specified as `'internal'`, the function will behave as `options.isInternalRelease` is set on `true`. - -### Other changes - -* Changed rules how changelog generators work. See: [ckeditor/ckeditor5#1746](https://github.com/ckeditor/ckeditor5/issues/1746). ([501cbad](https://github.com/ckeditor/ckeditor5-dev/commit/501cbad)) - - - Notes from all commits will be saved in the changelog before "Features", "Bug fixes", "Other changes". They have been moved from the bottom to the top. - - Introduced new types of notes: - * `MAJOR BREAKING CHANGES` which means that the public API of the package has been changed, - * `MINOR BREAKING CHANGES` which means that the public API of the package has not been changed but some internals (utils, helpers, etc.) have changed. - - `BREAKING CHANGES` are treated as `MAJOR BREAKING CHANGES`, - - Before starting the generating changelog process, all `MAJOR BREAKING CHANGES` commits are printed out. A user must confirm whether those changes are really "MAJOR". The user can specify the version number but the commit list won't be shown. - - If the user confirms major changes, the tool will bump `major` versions for all packages. - - If the user rejects (no major changes), the tool will bump `minor|patch|internal` based on commits in packages. All commits will be printed out. - - Removed support for `options.newVersion` in `generateChangelogForSubRepositories()` and `generateSummaryChangelog()` tasks. - - `transformCommitForSubPackage()` and `transformCommitForSubRepository()` are "factories" now. They return a new function that parses the commit. See the "BREAKING CHANGES" section. - - -## [16.0.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@15.0.3...@ckeditor/ckeditor5-dev-env@16.0.0) (2019-08-26) - -### Other changes - -* Adjusted the changelog generator to match to planned changes related to merging issue trackers. Closes [ckeditor/ckeditor5#1988](https://github.com/ckeditor/ckeditor5/issues/1988). ([acfe1a6](https://github.com/ckeditor/ckeditor5-dev/commit/acfe1a6)) - -### BREAKING CHANGES - -* Due to merging our issue trackers, pkgJson.bugs will point to the same place for every package. We cannot rely on this value anymore. See [ckeditor/ckeditor5#1988](https://github.com/ckeditor/ckeditor5/issues/1988). Instead of we can take a value from pkgJson.repository and adjust it to match to our requirements. - - -## [15.0.3](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@15.0.2...@ckeditor/ckeditor5-dev-env@15.0.3) (2019-07-23) - -### Other changes - -* Adjusted repository, documentation and scripts to changes done in mgit/mrgit. See: [cksource/mgit2#85](https://github.com/cksource/mgit2/issues/85). ([8b4d08d](https://github.com/ckeditor/ckeditor5-dev/commit/8b4d08d)) - - -## [15.0.2](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@15.0.1...@ckeditor/ckeditor5-dev-env@15.0.2) (2019-07-16) - -### Bug fixes - -* Adjusted usage of GitHub API inside createGithubRelease() util. Closes [ckeditor/ckeditor5#1889](https://github.com/ckeditor/ckeditor5/issues/1889). ([d9befaf](https://github.com/ckeditor/ckeditor5-dev/commit/d9befaf)) - - -## [15.0.1](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@15.0.0...@ckeditor/ckeditor5-dev-env@15.0.1) (2019-07-16) - -### Bug fixes - -* Adjusted usage of GitHub API to the latest version. All API's methods return an instance of Promise instead of requiring a callback as the last parameter. Closes [ckeditor/ckeditor5#1889](https://github.com/ckeditor/ckeditor5/issues/1889). ([486f732](https://github.com/ckeditor/ckeditor5-dev/commit/486f732)) - - -## [15.0.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@14.1.2...@ckeditor/ckeditor5-dev-env@15.0.0) (2019-07-15) - -### Features - -* Before starting the publishing process on NPM, the task will check whether the current user is logged to npm. Removed `tasks.releaseRepository()`. It's now possible to release a single repo with the multi-repo release task. Closes [#496](https://github.com/ckeditor/ckeditor5-dev/issues/496). Closes [#498](https://github.com/ckeditor/ckeditor5-dev/issues/498). ([90dc7a1](https://github.com/ckeditor/ckeditor5-dev/commit/90dc7a1)) - - In order to release a single repository, first, you need to bump its version. Then you will be able to publish changes. For bumping version, you can use the following code: - - ```js - require( '@ckeditor/ckeditor5-dev-env' ) - .bumpVersions( { - cwd: process.cwd(), - packages: null, // <-- It means that you want to call the script for single package. - dryRun: process.argv.includes( '--dry-run' ) - } ); - ``` - - For publishing changes: - - ```js - require( '@ckeditor/ckeditor5-dev-env' ) - .releaseSubRepositories( { - cwd: process.cwd(), - packages: null, // <-- It means that you want to call the script for single package. - dryRun: process.argv.includes( '--dry-run' ) - } ); - ``` - - You can call both scripts with `--dry-run` option that allows you testing the entire process. Those scripts won't publish anything in this mode. - -### BREAKING CHANGES - -* `tasks.releaseRepository()` has been removed. Use `tasks.bumpVersions()` and `tasks.releaseSubRepositories()` instead. - - -## [14.1.2](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@14.1.1...@ckeditor/ckeditor5-dev-env@14.1.2) (2019-07-15) - -### Other changes - -* Upgraded dependencies for most of the packages. Merged Lerna + Yarn and they can work together now. Closes [#527](https://github.com/ckeditor/ckeditor5-dev/issues/527). Closes [#466](https://github.com/ckeditor/ckeditor5-dev/issues/466). ([dcc3215](https://github.com/ckeditor/ckeditor5-dev/commit/dcc3215)) - - -## [14.1.1](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@14.1.0...@ckeditor/ckeditor5-dev-env@14.1.1) (2019-04-04) - -### Bug fixes - -* Release tool will not crash when publishing a package for the first time. Closes [#491](https://github.com/ckeditor/ckeditor5-dev/issues/491). ([fcc875d](https://github.com/ckeditor/ckeditor5-dev/commit/fcc875d)) - - -## [14.1.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@14.0.1...@ckeditor/ckeditor5-dev-env@14.1.0) (2019-03-28) - -### Features - -* Multiple "Updated translations." commits will be merged into a single entry in the changelog. Closes [#486](https://github.com/ckeditor/ckeditor5-dev/issues/486). ([1479e67](https://github.com/ckeditor/ckeditor5-dev/commit/1479e67)) - -### Bug fixes - -* Fixed generating changelog for non-scoped packages. Closes [#331](https://github.com/ckeditor/ckeditor5-dev/issues/331). ([a365f08](https://github.com/ckeditor/ckeditor5-dev/commit/a365f08)) -* Made all commits display properly during generating the changelog. Closes [#488](https://github.com/ckeditor/ckeditor5-dev/issues/488). ([fa9ae30](https://github.com/ckeditor/ckeditor5-dev/commit/fa9ae30)) -* Merge 'stable' branch commit will be ignored during generating the changelog. Closes [#487](https://github.com/ckeditor/ckeditor5-dev/issues/487). ([7a401ef](https://github.com/ckeditor/ckeditor5-dev/commit/7a401ef)) - - -## [14.0.1](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@14.0.0...@ckeditor/ckeditor5-dev-env@14.0.1) (2019-02-28) - -Internal changes only (updated dependencies, documentation, etc.). - - -## [14.0.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@13.0.3...@ckeditor/ckeditor5-dev-env@14.0.0) (2019-02-19) - -### BREAKING CHANGES - -* Upgraded minimal versions of Node to `8.0.0` and npm to `5.7.1`. See: [ckeditor/ckeditor5#1507](https://github.com/ckeditor/ckeditor5/issues/1507). ([612ea3c](https://github.com/ckeditor/ckeditor5-cloud-services/commit/612ea3c)) - - -## [13.0.3](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@13.0.2...@ckeditor/ckeditor5-dev-env@13.0.3) (2019-02-12) - -Internal changes only (updated dependencies, documentation, etc.). - - -## [13.0.2](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@13.0.1...@ckeditor/ckeditor5-dev-env@13.0.2) (2018-11-22) - -### Bug fixes - -* Small fixes for the tool that publishes the packages. Closes [#445](https://github.com/ckeditor/ckeditor5-dev/issues/445). Closes [#446](https://github.com/ckeditor/ckeditor5-dev/issues/446). ([c593561](https://github.com/ckeditor/ckeditor5-dev/commit/c593561)) - - * For the real release, the tool won't ask about removing ZIP archives that are created when dry run mode is active. See [#445](https://github.com/ckeditor/ckeditor5-dev/issues/445). - * Publishing a package for the first time on GitHub will work properly. It didn't work because GitHub API returned `Not Found` response and the tool couldn't understand it. See [#446](https://github.com/ckeditor/ckeditor5-dev/issues/446). - - -## [13.0.1](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@13.0.0...@ckeditor/ckeditor5-dev-env@13.0.1) (2018-11-05) - -Internal changes only (updated dependencies, documentation, etc.). - - -## [13.0.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@12.0.2...@ckeditor/ckeditor5-dev-env@13.0.0) (2018-10-09) - -### Features - -* Releasing packages has been split from single step to two. Both steps support a `dry-run` mode which allows testing every step of the release process without publishing anything. Closes [#427](https://github.com/ckeditor/ckeditor5-dev/issues/427). ([f00cd31](https://github.com/ckeditor/ckeditor5-dev/commit/f00cd31)) - - For tagging repositories use `tasks.bumpVersions()` which updates version across all packages in the project. Before starting the updating process, the task validates whether all ingredients are defined (mostly whether changelogs were generated). - - For publishing changes use `tasks.releaseSubRepositories()` which cares about publishing changes on NPM and/or GitHub. It checks versions of packages published on NPM and GitHub so there is no risk to publish the same changes twice. - - Both tasks contain a dry-run mode which allows testing the whole process without a pain about pushing or publishing. The dry-run mode prints every called command on the screen. Instead of publishing package, it creates an archive that contains content which will be published. All commits made by `npm version` (and its hooks like `pre` or `post`) will be removed. - -### Bug fixes - -* Fixed invalid key name. ([2413072](https://github.com/ckeditor/ckeditor5-dev/commit/2413072)) - -### BREAKING CHANGES - -* `tasks.releaseSubRepositories()` does not updates versions any more. Use it together with `tasks.bumpVersions()`. -* `cli.configureReleaseOptions()` returns `npm` and `github` keys (and opposite values) instead of `skipNpm` and `skipGithub` - -BREAKNG CHANGES: `getSubRepositoriesPaths()` returns an object that contains two keys: `matched` and `skipped`. Was: `packages` and `skipped`. - -### NOTE - -* `tasks.generateChangelogForSubRepositories()` accepts `skipMainRepository` option which is passed to `getSubRepositoriesPaths()` util. If `skipMainRepository` option is set on true, the package defined in `options.cwd` will be added as `skipped`, if on false, as `matched`. - - -## [12.0.2](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@12.0.1...@ckeditor/ckeditor5-dev-env@12.0.2) (2018-10-02) - -### Bug fixes - -* Generated a changelog for the first time will have a proper link (in a header). Closes [#430](https://github.com/ckeditor/ckeditor5-dev/issues/430). ([e68c35b](https://github.com/ckeditor/ckeditor5-dev/commit/e68c35b)) - - -## [12.0.1](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@12.0.0...@ckeditor/ckeditor5-dev-env@12.0.1) (2018-09-24) - -Internal changes only (updated dependencies, documentation, etc.). - - -## [12.0.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@11.1.1...@ckeditor/ckeditor5-dev-env@12.0.0) (2018-08-23) - -Updated required Node.js version to `>=6.9.0`. - - -## [11.1.1](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@11.1.0...@ckeditor/ckeditor5-dev-env@11.1.1) (2018-07-17) - -Internal changes only (updated dependencies, documentation, etc.). - - -## [11.1.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@11.0.0...@ckeditor/ckeditor5-dev-env@11.1.0) (2018-07-17) - -### Features - -* The release tool supports updating the `peerDependencies` in `package.json`. Introduced a `dryRun` mode which allows testing the whole release process without publishing anything. The changelog generator for sub-repositories accepts the `newVersion` parameter. All generated changelog will use the version instead of analyzing a history of commits in a given repository. See [ckeditor/ckeditor5#1061](https://github.com/ckeditor/ckeditor5/issues/1061). ([263f37b](https://github.com/ckeditor/ckeditor5-dev/commit/263f37b)) - - Dry run mode for release sub-repositories: - - - `npm version` will not create a tag (only the commit will be made), - - `npm pack` will be called instead of `npm publish` (it packs the whole release to a ZIP archive), - - `git push` will be replaced with a log on the screen, - - creating a release on GitHub will be replaced with a log that will contain a URL to the release, - - every called command will be displayed. - - -## [11.0.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@10.0.0...@ckeditor/ckeditor5-dev-env@11.0.0) (2018-07-05) - -### Other changes - -* Updated `CKEditorWebpackPlugin` and related tools to support `webpack@4`. Closes [#371](https://github.com/ckeditor/ckeditor5-dev/issues/371). ([d0cbbca](https://github.com/ckeditor/ckeditor5-dev/commit/d0cbbca)) - -### BREAKING CHANGES - -* This package requires `webpack@4`. - - -## [10.0.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@9.0.3...@ckeditor/ckeditor5-dev-env@10.0.0) (2018-06-28) - -### Features - -* The changelog generator for a single package (`generateChangelogForSinglePackage()`) will allow hiding a link to compare releases on GitHub and links to particular commits. Closes [#415](https://github.com/ckeditor/ckeditor5-dev/issues/415). ([4d7dc4b](https://github.com/ckeditor/ckeditor5-dev/commit/4d7dc4b)) - -### BREAKING CHANGES - -* An optional parameter `newVersion` for `generateChangelogForSinglePackage()` method has been replaced with an `options` object (of which it is a key). - - -## [9.0.3](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@9.0.1...@ckeditor/ckeditor5-dev-env@9.0.3) (2018-06-28) - -Internal changes only (updated dependencies, documentation, etc.). - - -## [9.0.1](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@9.0.0...@ckeditor/ckeditor5-dev-env@9.0.1) (2018-05-04) - -Internal changes only (updated dependencies, documentation, etc.). - - -## [9.0.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@8.0.9...@ckeditor/ckeditor5-dev-env@9.0.0) (2018-04-25) - -### Bug fixes - -* An error that occurs during publishing a package on GitHub will not break the whole process and the rest packages would be published. Closes [#397](https://github.com/ckeditor/ckeditor5-dev/issues/397). ([7f66531](https://github.com/ckeditor/ckeditor5-dev/commit/7f66531)) -* The "Dependencies" header will not appear if no dependencies have been added or changed. Also, fixed the invalid spacing between two versions in the generated changelog. Closes [#398](https://github.com/ckeditor/ckeditor5-dev/issues/398). ([77bc394](https://github.com/ckeditor/ckeditor5-dev/commit/77bc394)) - -### Other changes - -* Changed the license to GPL2+ only. See [ckeditor/ckeditor5#991](https://github.com/ckeditor/ckeditor5/issues/991). ([e392d7d](https://github.com/ckeditor/ckeditor5-dev/commit/e392d7d)) - -### BREAKING CHANGES - -* The license under which CKEditor 5 is released has been changed from a triple GPL, LGPL and MPL license to GPL2+ only. See [ckeditor/ckeditor5#991](https://github.com/ckeditor/ckeditor5/issues/991) for more information. - - -## [8.0.9](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@8.0.8...@ckeditor/ckeditor5-dev-env@8.0.9) (2018-04-10) - -Internal changes only (updated dependencies, documentation, etc.). - - -## [8.0.8](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@8.0.7...@ckeditor/ckeditor5-dev-env@8.0.8) (2018-03-27) - -### Bug fixes - -* An invalid parameter was passed to the logger and it caused that logs were displayed incorrectly. Closes [#380](https://github.com/ckeditor/ckeditor5-dev/issues/380). ([27aaa13](https://github.com/ckeditor/ckeditor5-dev/commit/27aaa13)) - - -## [8.0.7](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@8.0.5...@ckeditor/ckeditor5-dev-env@8.0.7) (2018-03-22) - -Internal changes only (updated dependencies, documentation, etc.). - - -## [8.0.5](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@8.0.4...@ckeditor/ckeditor5-dev-env@8.0.5) (2018-01-22) - -### Bug fixes - -* Translation utils will now add correct license headers. ([c054c17](https://github.com/ckeditor/ckeditor5-dev/commit/c054c17)) - - -## [8.0.4](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@8.0.0...@ckeditor/ckeditor5-dev-env@8.0.4) (2017-12-20) - -### Bug fixes - -* Additional notes will be removed from commit's footer. Closes [#341](https://github.com/ckeditor/ckeditor5-dev/issues/341). ([95bcfd8](https://github.com/ckeditor/ckeditor5-dev/commit/95bcfd8)) - - -## [8.0.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@7.0.1...@ckeditor/ckeditor5-dev-env@8.0.0) (2017-11-30) - -### Features - -* `TranslationService` v2. Closes [ckeditor/ckeditor5#666](https://github.com/ckeditor/ckeditor5/issues/666). Closes [ckeditor/ckeditor5#624](https://github.com/ckeditor/ckeditor5/issues/624). ([ee2a1d2](https://github.com/ckeditor/ckeditor5-dev/commit/ee2a1d2)) - - -## [7.0.1](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@7.0.0...@ckeditor/ckeditor5-dev-env@7.0.1) (2017-11-28) - -### Bug fixes - -* Additional tags for continuous integration services used in commit message will be removed during generating the changelog. Closes [#309](https://github.com/ckeditor/ckeditor5-dev/issues/309). ([600f36e](https://github.com/ckeditor/ckeditor5-dev/commit/600f36e)) -* Changelog generator for internal releases will always add two blank lines. Closes [#308](https://github.com/ckeditor/ckeditor5-dev/issues/308). ([b7b5453](https://github.com/ckeditor/ckeditor5-dev/commit/b7b5453)) -* Links to releases will be generated correctly. Closes [#310](https://github.com/ckeditor/ckeditor5-dev/issues/310). ([5f98f9e](https://github.com/ckeditor/ckeditor5-dev/commit/5f98f9e)) - - -## [7.0.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@6.0.0...@ckeditor/ckeditor5-dev-env@7.0.0) (2017-11-13) - -### Other changes - -* Removed gulp dependency across the whole project. Closes [#296](https://github.com/ckeditor/ckeditor5-dev/issues/296). ([723bee5](https://github.com/ckeditor/ckeditor5-dev/commit/723bee5)) - - Now all packages use only npm scripts. Depending on usage you might either create a `"script"` entry in `pacakge.json` to invoke bin executables or require the library into a script. - - * Package `ckeditor5-dev-env` exposes new `translations` binary. - * Package `ckeditor5-dev-tests` exposes new `test:manual` binary. - * Removed `gulp-jsdoc3` from `ckeditor5-dev-docs`. Now `jsdoc` is invoked directly. - * Removed `options` param from logger methods. Logger no longer uses `gutil.log` method. - -### BREAKING CHANGES - -* Gulp tasks were removed. New npm scripts were introduced. - - -## [6.0.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@5.1.13...@ckeditor/ckeditor5-dev-env@6.0.0) (2017-11-10) - -### Features - -* Introduced a task which allows generating a summary changelog for a repository. Closes [#289](https://github.com/ckeditor/ckeditor5-dev/issues/289). ([eaf76b4](https://github.com/ckeditor/ckeditor5-dev/commit/eaf76b4)) - -### BREAKING CHANGES - -* Release tool won't generate changelogs for skipped packages anymore. This task will be handled by changelog generator. - -### NOTE - -* The changelog generator will propose `internal` bump version instead of `skip` if a package contains any commit. -* If a package does not contain any commit, the changelog will propose `skip` bump version. -* `internal` bump will increase the release version if the current version is specified as a release (`v1.0.0-alpha.1` becomes `v1.0.0-alpha.2`). - - -## [5.1.13](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@5.1.12...@ckeditor/ckeditor5-dev-env@5.1.13) (2017-10-20) - -### Bug fixes - -* Changed order of commands executed by the release tool to optimize the time it takes from the first published package to the last. Closes [#272](https://github.com/ckeditor/ckeditor5-dev/issues/272). Closes [#292](https://github.com/ckeditor/ckeditor5-dev/issues/292). ([451ff8c](https://github.com/ckeditor/ckeditor5-dev/commit/451ff8c)) - - Due to releasing packages one after another, the builds on CI might break and users' `npm install` commands might fail too. Now release tool will: - - * do all commits (generate missing changelogs or/and update dependencies' versions), - * publish all packages on NPM (all packages will contain proper versions), - * do all pushes (CI will not crash because all versions are valid), - * make the GitHub releases. - - This will ensure that the process takes minimum amount of time. - -### Other changes - -* Changed order of headers in generated changelog. Closes [#293](https://github.com/ckeditor/ckeditor5-dev/issues/293). ([ad660b4](https://github.com/ckeditor/ckeditor5-dev/commit/ad660b4)) - - -## [5.1.12](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@5.1.10...@ckeditor/ckeditor5-dev-env@5.1.12) (2017-10-01) - -### Bug fixes - -* If a part of a commit message matches "organization/repository#id" it will be replaced with a link to an issue in that specific repository. Also, scoped package names won't be replaced with links to user profiles. Closes [#269](https://github.com/ckeditor/ckeditor5-dev/issues/269). ([e9bf324](https://github.com/ckeditor/ckeditor5-dev/commit/e9bf324)) - - -## [5.1.10](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@5.1.8...@ckeditor/ckeditor5-dev-env@5.1.10) (2017-09-07) - -### Bug fixes - -* Merge commit which does not contain the second line will not crash the changelog tool. Closes [#276](https://github.com/ckeditor/ckeditor5-dev/issues/276). ([ab1ffd8](https://github.com/ckeditor/ckeditor5-dev/commit/ab1ffd8)) -* Several issues related to proper typing the commit subject. Closes [#270](https://github.com/ckeditor/ckeditor5-dev/issues/270). Closes [#271](https://github.com/ckeditor/ckeditor5-dev/issues/271). ([0df891d](https://github.com/ckeditor/ckeditor5-dev/commit/0df891d)) - - * If a commit message didn't end with a dot, it was ignored. Now it will be handled. - * Added aliases for `Fix` type of the commit. Now `Fixes` and `Fixed` will be handled as `Fix`. - * Merge commit which wasn't a pull request was ignored. Now it will be handled. - - -## [5.1.8](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@5.1.7...@ckeditor/ckeditor5-dev-env@5.1.8) (2017-09-01) - -### Bug fixes - -* Add better network error handling for downloading and uploading translations. Closes [#265](https://github.com/ckeditor/ckeditor5-dev/issues/265). ([c12fb15](https://github.com/ckeditor/ckeditor5-dev/commit/c12fb15)) - - -## [5.1.7](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@5.1.5...@ckeditor/ckeditor5-dev-env@5.1.7) (2017-08-23) - -### Bug fixes - -* Fixed Transifex URL scheme. Closes [#249](https://github.com/ckeditor/ckeditor5-dev/issues/249). ([3276048](https://github.com/ckeditor/ckeditor5-dev/commit/3276048)) - - -## [5.1.5](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@5.1.4...@ckeditor/ckeditor5-dev-env@5.1.5) (2017-08-16) - -### Bug fixes - -* "Publish" commits will not be parsed when generating the changelog. Closes [#220](https://github.com/ckeditor/ckeditor5-dev/issues/220). ([7501a6b](https://github.com/ckeditor/ckeditor5-dev/commit/7501a6b)) -* `cli.confirmRelease()` shouldn't reject the promise if the user did not confirm the process. Closes [#245](https://github.com/ckeditor/ckeditor5-dev/issues/245). ([d57f9c8](https://github.com/ckeditor/ckeditor5-dev/commit/d57f9c8)) - - -## [5.1.4](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@5.1.2...@ckeditor/ckeditor5-dev-env@5.1.4) (2017-08-09) - -### Other changes - -* The release process will now be error-proof by performing validation before starting taking any actions. Closes [#99](https://github.com/ckeditor/ckeditor5-dev/issues/99). Closes [#147](https://github.com/ckeditor/ckeditor5-dev/issues/147). Closes: [#149](https://github.com/ckeditor/ckeditor5-dev/issues/149). Closes: [#151](https://github.com/ckeditor/ckeditor5-dev/issues/151). ([330a8dc](https://github.com/ckeditor/ckeditor5-dev/commit/330a8dc)) - - -## [5.1.2](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@5.1.0...@ckeditor/ckeditor5-dev-env@5.1.2) (2017-06-14) - -Internal changes only (updated dependencies, documentation, etc.). - -## [5.1.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@5.0.1...@ckeditor/ckeditor5-dev-env@5.1.0) (2017-05-24) - -### Bug fixes - -* Changed the method for gathering files modified by a commit. Closes [#207](https://github.com/ckeditor/ckeditor5-dev/issues/207). ([cf79c4d](https://github.com/ckeditor/ckeditor5-dev/commit/cf79c4d)) - -### Features - -* Added "internal" option to the version picker. Closes [#184](https://github.com/ckeditor/ckeditor5-dev/issues/184). ([ec43528](https://github.com/ckeditor/ckeditor5-dev/commit/ec43528)) - - If you'll type "internal" as a new version during generating the changelog, all commits will be ignored when generating the changelog but the version will be bumped. - -### Other changes - -* Release tool will use `npm version` command for bumping the version. Closes [#213](https://github.com/ckeditor/ckeditor5-dev/issues/213). ([d72ccd4](https://github.com/ckeditor/ckeditor5-dev/commit/d72ccd4)) - - It allows using the `preversion` and `postversion` npm hooks. - - -## [5.0.1](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@5.0.0...@ckeditor/ckeditor5-dev-env@5.0.1) (2017-05-16) - -### Bug fixes - -* Cached `pot` files will be cleaned before new ones are collected. Closes [#181](https://github.com/ckeditor/ckeditor5-dev/issues/181). ([da5b1f7](https://github.com/ckeditor/ckeditor5-dev/commit/da5b1f7)) -* Changelog for internal changes will be followed by two blank lines instead of one. Closes [#188](https://github.com/ckeditor/ckeditor5-dev/issues/188). ([bb16c0d](https://github.com/ckeditor/ckeditor5-dev/commit/bb16c0d)) -* Changelog utils won't throw an error if the changelog file does not exist. Closes [#187](https://github.com/ckeditor/ckeditor5-dev/issues/187). ([9b946fd](https://github.com/ckeditor/ckeditor5-dev/commit/9b946fd)) -* Closed tickets should not be hoisted to the first line of a changelog item. Closes [#161](https://github.com/ckeditor/ckeditor5-dev/issues/161). ([bf8aa79](https://github.com/ckeditor/ckeditor5-dev/commit/bf8aa79)) -* Complex, multiline commits will be parsed correctly. Closes [#146](https://github.com/ckeditor/ckeditor5-dev/issues/146). ([25c2d71](https://github.com/ckeditor/ckeditor5-dev/commit/25c2d71)) - - -## [5.0.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-env@4.4.3...@ckeditor/ckeditor5-dev-env@5.0.0) (2017-04-27) - -### Bug fixes - -* The task for uploading translations will not throw anymore. Closes [#174](https://github.com/ckeditor/ckeditor5-dev/issues/174). ([a3b619d](https://github.com/ckeditor/ckeditor5-dev/commit/a3b619d)) - -### Features - -* A task for generating changelogs in a monorepo was introduced. Several other improvements were made on the occasion. Closes [#148](https://github.com/ckeditor/ckeditor5-dev/issues/148). Closes [#121](https://github.com/ckeditor/ckeditor5-dev/issues/121). Closes [#110](https://github.com/ckeditor/ckeditor5-dev/issues/110). Closes [#96](https://github.com/ckeditor/ckeditor5-dev/issues/96). ([fefc1de](https://github.com/ckeditor/ckeditor5-dev/commit/fefc1de)) - -### BREAKING CHANGES - -* Task `tasks.generateChangelog()` has been renamed to `tasks.generateChangelogForSinglePackage()`. -* Task `generateChangelogForDependencies()` has been renamed to `tasks.generateChangelogForSubRepositories()`. -* Task `tasks.createRelease()` has been renamed to `tasks.releaseRepository()`. -* Task `tasks.releaseDependencies()` has been renamed to `tasks.releaseSubRepositories()`. - -### NOTE - -* Introduced a new task – `tasks.generateChangelogForSubRepositories()`. - - -## 4.4.3 - -The big bang. +All changes in the package are documented in the main repository. See: https://github.com/ckeditor/ckeditor5-dev/blob/master/CHANGELOG.md. diff --git a/packages/ckeditor5-dev-tests/CHANGELOG.md b/packages/ckeditor5-dev-tests/CHANGELOG.md index c6a29b024..2cc0cf250 100644 --- a/packages/ckeditor5-dev-tests/CHANGELOG.md +++ b/packages/ckeditor5-dev-tests/CHANGELOG.md @@ -1,640 +1,4 @@ Changelog ========= -## [19.2.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-tests@19.1.0...@ckeditor/ckeditor5-dev-tests@19.2.0) (2020-05-14) - -### Features - -* Allowed `ckeditor5-dev-tests` package to search for test files in the `external/*/packages/` directory. See [ckeditor/ckeditor5#6787](https://github.com/ckeditor/ckeditor5/issues/6787). ([df44a5e](https://github.com/ckeditor/ckeditor5-dev/commit/df44a5e)) - - -## [19.1.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-tests@19.0.0...@ckeditor/ckeditor5-dev-tests@19.1.0) (2020-05-13) - -### Features - -* Make port number configurable for manual tests server. Closes [#632](https://github.com/ckeditor/ckeditor5-dev/issues/632). ([ff50385](https://github.com/ckeditor/ckeditor5-dev/commit/ff50385)) -* It's now possible to pass a custom path to the `ckeditor5-dev-tests-check-dependencies` bin as a CLI argument. Closes [#630](https://github.com/ckeditor/ckeditor5-dev/issues/630). ([5ee2e7f](https://github.com/ckeditor/ckeditor5-dev/commit/5ee2e7f)) - - -## [19.0.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-tests@18.2.1...@ckeditor/ckeditor5-dev-tests@19.0.0) (2020-04-23) - -### BREAKING CHANGES - -* Omitting the language property in the `CKEditorWebpackPlugin` will not have any effect from now. This means that in both cases only the main `language` will be added to the main bundle and translations for other languages will be saved in separate files. -* The translation process no longer creates short ids for message strings. From now, the source code will not be changed by the translation process, translations for the main language will be added to the bundle(s) and translations for other languages will be outputted to separate executable Javascript files. - -### Features - -* Introduced support for plural translation forms. Closes [ckeditor/ckeditor5#6526](https://github.com/ckeditor/ckeditor5/issues/6526). Closes [ckeditor/ckeditor5#988](https://github.com/ckeditor/ckeditor5/issues/988). ([305590e](https://github.com/ckeditor/ckeditor5-dev/commit/305590e)) - - -## [18.2.1](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-tests@18.2.0...@ckeditor/ckeditor5-dev-tests@18.2.1) (2020-04-16) - -### Other changes - -* The leak detector now prints the outerHTML of the elements leaked. Closes [#617](https://github.com/ckeditor/ckeditor5-dev/issues/617). ([6f70021](https://github.com/ckeditor/ckeditor5-dev/commit/6f70021)) - - -## [18.2.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-tests@18.1.0...@ckeditor/ckeditor5-dev-tests@18.2.0) (2020-04-14) - -### Features - -* Code coverage is also stored as a JSON file. Closes [#615](https://github.com/ckeditor/ckeditor5-dev/issues/615). ([075f5c1](https://github.com/ckeditor/ckeditor5-dev/commit/075f5c1)) - - -## [18.1.0](https://github.com/ckeditor/ckeditor5-dev/compare/@ckeditor/ckeditor5-dev-tests@18.0.5...@ckeditor/ckeditor5-dev-tests@18.1.0) (2020-04-08) - -### Other changes - -* The `