@ckeditor/ckeditor5-dev-changelog 50.3.0 → 51.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +243 -84
- package/dist/types.d.ts +6 -2
- package/dist/utils/composechangelog.d.ts +2 -5
- package/dist/utils/constants.d.ts +1 -0
- package/dist/utils/detectreleasechannel.d.ts +9 -0
- package/dist/utils/determinenextversion.d.ts +5 -9
- package/dist/utils/findchangelogentrypaths.d.ts +1 -0
- package/dist/utils/getreleasetype.d.ts +6 -0
- package/dist/utils/internalerror.d.ts +0 -1
- package/dist/utils/movechangelogentryfiles.d.ts +11 -0
- package/dist/utils/promptreleasetype.d.ts +9 -0
- package/dist/utils/providenewversion.d.ts +3 -0
- package/dist/utils/validateinputversion.d.ts +14 -0
- package/package.json +2 -2
- package/template/template.md +2 -2
package/dist/index.js
CHANGED
|
@@ -18,6 +18,7 @@ const CHANGELOG_HEADER = 'Changelog\n=========';
|
|
|
18
18
|
const NPM_URL = 'https://www.npmjs.com/package';
|
|
19
19
|
const VERSIONING_POLICY_URL = 'https://ckeditor.com/docs/ckeditor5/latest/framework/guides/support/versioning-policy.html';
|
|
20
20
|
const CHANGESET_DIRECTORY = '.changelog';
|
|
21
|
+
const PRE_RELEASE_DIRECTORY = 'pre-release';
|
|
21
22
|
upath.join(import.meta.dirname, '../template/template.md');
|
|
22
23
|
const SECTIONS = {
|
|
23
24
|
major: {
|
|
@@ -282,6 +283,9 @@ function getIssueLinkObject(issue, gitHubUrl) {
|
|
|
282
283
|
const repoUrlMatch = issue.match(ISSUE_URL_PATTERN);
|
|
283
284
|
if (repoUrlMatch) {
|
|
284
285
|
const { owner, repository, number } = repoUrlMatch.groups;
|
|
286
|
+
if (issue.startsWith(gitHubUrl)) {
|
|
287
|
+
return { displayName: `#${number}`, link: issue };
|
|
288
|
+
}
|
|
285
289
|
return { displayName: `${owner}/${repository}#${number}`, link: issue };
|
|
286
290
|
}
|
|
287
291
|
return { displayName: '', link: '' };
|
|
@@ -529,6 +533,49 @@ function prepareChangelogContent(existingChangelog, newChangelog) {
|
|
|
529
533
|
class UserAbortError extends Error {
|
|
530
534
|
}
|
|
531
535
|
|
|
536
|
+
/**
|
|
537
|
+
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
538
|
+
* For licensing, see LICENSE.md.
|
|
539
|
+
*/
|
|
540
|
+
async function validateInputVersion(options) {
|
|
541
|
+
const { newVersion, version, releaseType, packageName, suggestedVersion } = options;
|
|
542
|
+
const [newChannel] = semver.prerelease(newVersion) || ['latest'];
|
|
543
|
+
const [currentChannel] = semver.prerelease(version) || ['latest'];
|
|
544
|
+
// Generic semantic‑version checks.
|
|
545
|
+
if (!semver.valid(newVersion)) {
|
|
546
|
+
return 'Please provide a valid version.';
|
|
547
|
+
}
|
|
548
|
+
if (!semver.gt(newVersion, version)) {
|
|
549
|
+
return `Provided version must be higher than "${version}".`;
|
|
550
|
+
}
|
|
551
|
+
if (!(await npm.checkVersionAvailability(newVersion, packageName))) {
|
|
552
|
+
return 'Given version is already taken.';
|
|
553
|
+
}
|
|
554
|
+
// Rules that depend on release type.
|
|
555
|
+
const isPrerelease = releaseType === 'prerelease';
|
|
556
|
+
const isPrereleasePromote = releaseType === 'prerelease-promote';
|
|
557
|
+
const isLatest = releaseType === 'latest';
|
|
558
|
+
// Pre‑release types must always include a channel suffix.
|
|
559
|
+
if ((isPrerelease || isPrereleasePromote) && newChannel === 'latest') {
|
|
560
|
+
return 'You chose the "pre-release" release type. Please provide a version with a channel suffix.';
|
|
561
|
+
}
|
|
562
|
+
// Promoting a pre‑release: new version ≥ suggested version.
|
|
563
|
+
if (isPrereleasePromote && !semver.gte(newVersion, suggestedVersion)) {
|
|
564
|
+
return `Provided version must be higher or equal to "${suggestedVersion}".`;
|
|
565
|
+
}
|
|
566
|
+
// Continuing a pre‑release stream: channel cannot change.
|
|
567
|
+
if (isPrerelease &&
|
|
568
|
+
currentChannel !== 'latest' &&
|
|
569
|
+
currentChannel !== newChannel) {
|
|
570
|
+
return `Provided channel must be the same existing channel ${currentChannel}.`;
|
|
571
|
+
}
|
|
572
|
+
// Latest release must not carry a channel suffix.
|
|
573
|
+
if (isLatest && newChannel !== 'latest') {
|
|
574
|
+
return 'You chose the "latest" release type. Please provide a version without a channel suffix.';
|
|
575
|
+
}
|
|
576
|
+
return true;
|
|
577
|
+
}
|
|
578
|
+
|
|
532
579
|
/**
|
|
533
580
|
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
534
581
|
* For licensing, see LICENSE.md.
|
|
@@ -584,39 +631,69 @@ async function askContinueConfirmation(indentLevel = 0) {
|
|
|
584
631
|
* Creates a prompt question for version input with validation.
|
|
585
632
|
*/
|
|
586
633
|
function createVersionQuestion(options) {
|
|
587
|
-
const { version, packageName, bumpType, indentLevel = 0 } = options;
|
|
588
|
-
const suggestedVersion =
|
|
634
|
+
const { version, packageName, bumpType, releaseChannel, releaseType, indentLevel = 0 } = options;
|
|
635
|
+
const suggestedVersion = getSuggestedVersion(bumpType, version, releaseChannel) || version;
|
|
589
636
|
const message = 'Type the new version ' +
|
|
590
|
-
`(current: "${version}", suggested: "${suggestedVersion}"
|
|
637
|
+
`(current: "${version}", suggested: "${suggestedVersion}":`;
|
|
591
638
|
return [{
|
|
592
639
|
type: 'input',
|
|
593
640
|
name: 'version',
|
|
594
641
|
default: suggestedVersion,
|
|
595
642
|
message,
|
|
596
643
|
filter: (newVersion) => newVersion.trim(),
|
|
597
|
-
|
|
598
|
-
// Allow 'internal' as a special version.
|
|
599
|
-
if (newVersion === 'internal') {
|
|
600
|
-
return true;
|
|
601
|
-
}
|
|
602
|
-
// Require a semver valid version, e.g., `1.0.0`, `1.0.0-alpha.0`, etc.
|
|
603
|
-
if (!semver.valid(newVersion)) {
|
|
604
|
-
return 'Please provide a valid version or "internal" for internal changes.';
|
|
605
|
-
}
|
|
606
|
-
// The provided version must be higher than the current version.
|
|
607
|
-
if (!semver.gt(newVersion, version)) {
|
|
608
|
-
return `Provided version must be higher than "${version}".`;
|
|
609
|
-
}
|
|
610
|
-
const isAvailable = await npm.checkVersionAvailability(newVersion, packageName);
|
|
611
|
-
// Check against availability in the npm registry.
|
|
612
|
-
if (!isAvailable) {
|
|
613
|
-
return 'Given version is already taken.';
|
|
614
|
-
}
|
|
615
|
-
return true;
|
|
616
|
-
},
|
|
644
|
+
validate: (newVersion) => validateInputVersion({ newVersion, version, releaseType, packageName, suggestedVersion }),
|
|
617
645
|
prefix: ' '.repeat(indentLevel * CLI_INDENT_SIZE) + chalk.cyan('?')
|
|
618
646
|
}];
|
|
619
647
|
}
|
|
648
|
+
function getSuggestedVersion(bumpType, version, releaseChannel) {
|
|
649
|
+
if (bumpType === 'prerelease' && releaseChannel !== 'latest') {
|
|
650
|
+
return semver.inc(version, bumpType, releaseChannel);
|
|
651
|
+
}
|
|
652
|
+
else if (bumpType === 'prerelease' && releaseChannel === 'latest') {
|
|
653
|
+
// Using 'premajor` and `alpha` channel for a case, when introducing a prerelease for the next major.
|
|
654
|
+
// E.g. 1.0.0 -> 2.0.0-alpha.0.
|
|
655
|
+
return semver.inc(version, 'premajor', 'alpha');
|
|
656
|
+
}
|
|
657
|
+
else {
|
|
658
|
+
return semver.inc(version, bumpType);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
664
|
+
* For licensing, see LICENSE.md.
|
|
665
|
+
*/
|
|
666
|
+
/**
|
|
667
|
+
* Detects the release channel from a version string.
|
|
668
|
+
*/
|
|
669
|
+
function detectReleaseChannel(version, promotePrerelease = false) {
|
|
670
|
+
const prerelease = semver.prerelease(version);
|
|
671
|
+
if (!prerelease) {
|
|
672
|
+
return 'latest';
|
|
673
|
+
}
|
|
674
|
+
const currentChannel = prerelease[0];
|
|
675
|
+
if (promotePrerelease) {
|
|
676
|
+
if (currentChannel === 'alpha') {
|
|
677
|
+
return 'beta';
|
|
678
|
+
}
|
|
679
|
+
if (currentChannel === 'beta') {
|
|
680
|
+
return 'rc';
|
|
681
|
+
}
|
|
682
|
+
logInfo(chalk.yellow(`Warning! Unknown release channel to promote from ${currentChannel}.`));
|
|
683
|
+
return 'alpha';
|
|
684
|
+
}
|
|
685
|
+
return currentChannel;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
690
|
+
* For licensing, see LICENSE.md.
|
|
691
|
+
*/
|
|
692
|
+
/**
|
|
693
|
+
* Custom error class for handling validation errors in the changelog generation process.
|
|
694
|
+
*/
|
|
695
|
+
class InternalError extends Error {
|
|
696
|
+
}
|
|
620
697
|
|
|
621
698
|
/**
|
|
622
699
|
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
@@ -624,27 +701,39 @@ function createVersionQuestion(options) {
|
|
|
624
701
|
*/
|
|
625
702
|
/**
|
|
626
703
|
* Determines the next version for a single package or a mono-repository setup based on
|
|
627
|
-
* the change sections,
|
|
704
|
+
* the change sections, user input, and semantic versioning rules.
|
|
628
705
|
*
|
|
629
706
|
* The function handles:
|
|
630
707
|
* * Automatic version bump calculation from categorized changelog sections (major, minor, patch).
|
|
631
|
-
* *
|
|
708
|
+
* * Version bump for prerelease channels.
|
|
632
709
|
* * User prompts for version input when no explicit version is provided.
|
|
633
710
|
*/
|
|
634
711
|
async function determineNextVersion(options) {
|
|
635
|
-
const { sections, currentVersion, packageName, nextVersion } = options;
|
|
636
|
-
if (nextVersion === 'internal') {
|
|
637
|
-
const internalVersionBump = getInternalVersionBump(currentVersion);
|
|
638
|
-
logInfo(`○ ${chalk.cyan(`Determined the next version to be ${internalVersionBump.newVersion}.`)}`);
|
|
639
|
-
return internalVersionBump;
|
|
640
|
-
}
|
|
712
|
+
const { sections, currentVersion, packageName, nextVersion, releaseType } = options;
|
|
641
713
|
if (nextVersion) {
|
|
642
714
|
logInfo(`○ ${chalk.cyan(`Determined the next version to be ${nextVersion}.`)}`);
|
|
643
|
-
|
|
715
|
+
const isNightlyVersion = nextVersion.startsWith('0.0.0-');
|
|
716
|
+
if (isNightlyVersion) {
|
|
717
|
+
return nextVersion;
|
|
718
|
+
}
|
|
719
|
+
const validationResult = await validateInputVersion({
|
|
720
|
+
newVersion: nextVersion,
|
|
721
|
+
suggestedVersion: nextVersion,
|
|
722
|
+
version: currentVersion,
|
|
723
|
+
releaseType,
|
|
724
|
+
packageName
|
|
725
|
+
});
|
|
726
|
+
if (typeof validationResult === 'string') {
|
|
727
|
+
throw new InternalError(validationResult);
|
|
728
|
+
}
|
|
729
|
+
return nextVersion;
|
|
644
730
|
}
|
|
645
731
|
logInfo(`○ ${chalk.cyan('Determining the new version...')}`);
|
|
646
732
|
let bumpType = 'patch';
|
|
647
|
-
if (
|
|
733
|
+
if (releaseType === 'prerelease' || releaseType === 'prerelease-promote') {
|
|
734
|
+
bumpType = 'prerelease';
|
|
735
|
+
}
|
|
736
|
+
else if (sections.major.entries.length || sections.breaking.entries.length) {
|
|
648
737
|
bumpType = 'major';
|
|
649
738
|
}
|
|
650
739
|
else if (sections.minor.entries.length || sections.feature.entries.length) {
|
|
@@ -655,20 +744,12 @@ async function determineNextVersion(options) {
|
|
|
655
744
|
const userProvidedVersion = await provideNewVersion({
|
|
656
745
|
packageName,
|
|
657
746
|
bumpType,
|
|
747
|
+
releaseType,
|
|
658
748
|
version: currentVersion,
|
|
749
|
+
releaseChannel: detectReleaseChannel(currentVersion, releaseType === 'prerelease-promote'),
|
|
659
750
|
displayValidationWarning: areErrorsPresent || areWarningsPresent
|
|
660
751
|
});
|
|
661
|
-
|
|
662
|
-
return getInternalVersionBump(currentVersion);
|
|
663
|
-
}
|
|
664
|
-
return { newVersion: userProvidedVersion, isInternal: false };
|
|
665
|
-
}
|
|
666
|
-
function getInternalVersionBump(currentVersion) {
|
|
667
|
-
const version = semver.inc(currentVersion, 'patch');
|
|
668
|
-
if (!version) {
|
|
669
|
-
throw new Error('Unable to determine new version based on the version in root package.json.');
|
|
670
|
-
}
|
|
671
|
-
return { newVersion: version, isInternal: true };
|
|
752
|
+
return userProvidedVersion;
|
|
672
753
|
}
|
|
673
754
|
|
|
674
755
|
/**
|
|
@@ -819,11 +900,12 @@ function getPackageName(value) {
|
|
|
819
900
|
* Gathers changelog entry file paths (Markdown files) from the main repository and any configured external repositories.
|
|
820
901
|
*/
|
|
821
902
|
async function findChangelogEntryPaths(options) {
|
|
822
|
-
const { cwd, externalRepositories, shouldSkipLinks } = options;
|
|
903
|
+
const { cwd, externalRepositories, shouldSkipLinks, includeSubdirectories = true } = options;
|
|
904
|
+
const globPattern = includeSubdirectories ? '**/*.md' : '*.md';
|
|
823
905
|
return AsyncArray
|
|
824
906
|
.from(Promise.resolve(externalRepositories))
|
|
825
907
|
.map(async (repo) => {
|
|
826
|
-
const changesetGlob = await glob(
|
|
908
|
+
const changesetGlob = await glob(globPattern, {
|
|
827
909
|
cwd: upath.join(repo.cwd, CHANGESET_DIRECTORY),
|
|
828
910
|
absolute: true
|
|
829
911
|
});
|
|
@@ -836,7 +918,7 @@ async function findChangelogEntryPaths(options) {
|
|
|
836
918
|
};
|
|
837
919
|
})
|
|
838
920
|
.then(async (externalResults) => {
|
|
839
|
-
const mainChangesetGlob = await glob(
|
|
921
|
+
const mainChangesetGlob = await glob(globPattern, {
|
|
840
922
|
cwd: upath.join(cwd, CHANGESET_DIRECTORY),
|
|
841
923
|
absolute: true
|
|
842
924
|
});
|
|
@@ -994,25 +1076,6 @@ function extractDateFromFilename(changesetPath) {
|
|
|
994
1076
|
return parsedDate;
|
|
995
1077
|
}
|
|
996
1078
|
|
|
997
|
-
/**
|
|
998
|
-
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
999
|
-
* For licensing, see LICENSE.md.
|
|
1000
|
-
*/
|
|
1001
|
-
/**
|
|
1002
|
-
* Custom error class for handling validation errors in the changelog generation process.
|
|
1003
|
-
*/
|
|
1004
|
-
class InternalError extends Error {
|
|
1005
|
-
constructor() {
|
|
1006
|
-
const message = 'No valid entries were found. Please ensure that:\n' +
|
|
1007
|
-
'1) Input files exist in the `.changelog/` directory.\n' +
|
|
1008
|
-
'2) The `cwd` parameter points to the root of your project.\n' +
|
|
1009
|
-
'3) The `packagesDirectory` parameter correctly specifies the packages folder.\n' +
|
|
1010
|
-
'If no errors appear in the console but inputs are present, your project configuration may be incorrect.\n' +
|
|
1011
|
-
'If validation errors are shown, please resolve them according to the details provided.\n';
|
|
1012
|
-
super(message);
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1016
1079
|
/**
|
|
1017
1080
|
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
1018
1081
|
* For licensing, see LICENSE.md.
|
|
@@ -1031,7 +1094,13 @@ function filterVisibleSections(sectionsWithEntries) {
|
|
|
1031
1094
|
})
|
|
1032
1095
|
.map(([, section]) => section);
|
|
1033
1096
|
if (!sectionsToDisplay.length) {
|
|
1034
|
-
|
|
1097
|
+
const message = 'No valid entries were found. Please ensure that:\n' +
|
|
1098
|
+
'1) Input files exist in the `.changelog/` directory.\n' +
|
|
1099
|
+
'2) The `cwd` parameter points to the root of your project.\n' +
|
|
1100
|
+
'3) The `packagesDirectory` parameter correctly specifies the packages folder.\n' +
|
|
1101
|
+
'If no errors appear in the console but inputs are present, your project configuration may be incorrect.\n' +
|
|
1102
|
+
'If validation errors are shown, please resolve them according to the details provided.\n';
|
|
1103
|
+
throw new InternalError(message);
|
|
1035
1104
|
}
|
|
1036
1105
|
return sectionsToDisplay;
|
|
1037
1106
|
}
|
|
@@ -1058,13 +1127,12 @@ function getDateFormatted(date) {
|
|
|
1058
1127
|
* * A version header with a link to the GitHub comparison view (except for an initial version).
|
|
1059
1128
|
* * Sections with grouped changelog entries and their messages.
|
|
1060
1129
|
* * A collapsible summary of released packages and their version bumps for a mono-repository setup.
|
|
1061
|
-
* * Special handling for
|
|
1130
|
+
* * Special handling for single-package repositories.
|
|
1062
1131
|
*/
|
|
1063
1132
|
async function composeChangelog(options) {
|
|
1064
|
-
const { cwd, date, currentVersion, newVersion, sections, releasedPackagesInfo,
|
|
1133
|
+
const { cwd, date, currentVersion, newVersion, sections, releasedPackagesInfo, isSinglePackage } = options;
|
|
1065
1134
|
const gitHubUrl = await workspaces.getRepositoryUrl(cwd, { async: true });
|
|
1066
1135
|
const dateFormatted = getDateFormatted(date);
|
|
1067
|
-
const packagesNames = [...packagesMetadata.keys()];
|
|
1068
1136
|
const header = currentVersion === '0.0.1' ?
|
|
1069
1137
|
`## ${newVersion} (${dateFormatted})` :
|
|
1070
1138
|
`## [${newVersion}](${gitHubUrl}/compare/v${currentVersion}...v${newVersion}) (${dateFormatted})`;
|
|
@@ -1080,19 +1148,13 @@ async function composeChangelog(options) {
|
|
|
1080
1148
|
'',
|
|
1081
1149
|
...packages.map(packageName => `* [${packageName}](${NPM_URL}/${packageName}/v/${newVersion}): ${version}`)
|
|
1082
1150
|
])).flat().join('\n');
|
|
1083
|
-
const internalVersionsBumps = [
|
|
1084
|
-
'',
|
|
1085
|
-
SECTIONS.other.title + ':',
|
|
1086
|
-
'',
|
|
1087
|
-
packagesNames.map(name => `* [${name}](${NPM_URL}/${name}/v/${newVersion}): v${currentVersion} => v${newVersion}`)
|
|
1088
|
-
].flat().join('\n');
|
|
1089
1151
|
const changelog = [
|
|
1090
1152
|
header,
|
|
1091
1153
|
'',
|
|
1092
|
-
|
|
1154
|
+
sectionsAsString
|
|
1093
1155
|
];
|
|
1094
1156
|
if (!isSinglePackage) {
|
|
1095
|
-
changelog.push('### Released packages', '', `Check out the [Versioning policy](${VERSIONING_POLICY_URL}) guide for more information.`, '', '<details>', '<summary>Released packages (summary)</summary>',
|
|
1157
|
+
changelog.push('### Released packages', '', `Check out the [Versioning policy](${VERSIONING_POLICY_URL}) guide for more information.`, '', '<details>', '<summary>Released packages (summary)</summary>', packagesVersionBumps, '</details>', '');
|
|
1096
1158
|
}
|
|
1097
1159
|
return changelog.join('\n');
|
|
1098
1160
|
}
|
|
@@ -1112,6 +1174,40 @@ async function removeChangelogEntryFiles(entryPaths) {
|
|
|
1112
1174
|
.map(file => fs$1.unlink(file)));
|
|
1113
1175
|
}
|
|
1114
1176
|
|
|
1177
|
+
/**
|
|
1178
|
+
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
1179
|
+
* For licensing, see LICENSE.md.
|
|
1180
|
+
*/
|
|
1181
|
+
/**
|
|
1182
|
+
* Moves changelog entry files to cycle-specific directories instead of deleting them.
|
|
1183
|
+
* This preserves the history of changes across prerelease cycles.
|
|
1184
|
+
* Returns an array of entry paths that were modified by the move operation
|
|
1185
|
+
*/
|
|
1186
|
+
async function moveChangelogEntryFiles(entryPaths) {
|
|
1187
|
+
const targetDir = PRE_RELEASE_DIRECTORY;
|
|
1188
|
+
const modifiedEntryPaths = [];
|
|
1189
|
+
logInfo(`○ ${chalk.cyan(`Moving changelog entries to ${targetDir}/ directory...`)}`);
|
|
1190
|
+
for (const repo of entryPaths) {
|
|
1191
|
+
const { cwd, filePaths } = repo;
|
|
1192
|
+
const changelogDir = upath.join(cwd, CHANGESET_DIRECTORY);
|
|
1193
|
+
const targetPath = upath.join(changelogDir, targetDir);
|
|
1194
|
+
await fs$1.ensureDir(targetPath);
|
|
1195
|
+
const modifiedFilePaths = [];
|
|
1196
|
+
for (const filePath of filePaths) {
|
|
1197
|
+
const fileName = upath.basename(filePath);
|
|
1198
|
+
const targetFilePath = upath.join(targetPath, fileName);
|
|
1199
|
+
await fs$1.rename(filePath, targetFilePath);
|
|
1200
|
+
modifiedFilePaths.push(targetFilePath);
|
|
1201
|
+
modifiedFilePaths.push(filePath);
|
|
1202
|
+
}
|
|
1203
|
+
modifiedEntryPaths.push({
|
|
1204
|
+
...repo,
|
|
1205
|
+
filePaths: modifiedFilePaths
|
|
1206
|
+
});
|
|
1207
|
+
}
|
|
1208
|
+
return modifiedEntryPaths;
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1115
1211
|
/**
|
|
1116
1212
|
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
1117
1213
|
* For licensing, see LICENSE.md.
|
|
@@ -1134,6 +1230,61 @@ async function commitChanges(version, repositories) {
|
|
|
1134
1230
|
}
|
|
1135
1231
|
}
|
|
1136
1232
|
|
|
1233
|
+
/**
|
|
1234
|
+
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
1235
|
+
* For licensing, see LICENSE.md.
|
|
1236
|
+
*/
|
|
1237
|
+
/**
|
|
1238
|
+
* Prompts the user to choose between latest or prerelease
|
|
1239
|
+
*/
|
|
1240
|
+
async function promptReleaseType(currentVersion) {
|
|
1241
|
+
const { releaseType } = await inquirer.prompt([
|
|
1242
|
+
{
|
|
1243
|
+
type: 'list',
|
|
1244
|
+
name: 'releaseType',
|
|
1245
|
+
message: 'Please select the release type.',
|
|
1246
|
+
choices: getQuestions(currentVersion)
|
|
1247
|
+
}
|
|
1248
|
+
]);
|
|
1249
|
+
return releaseType;
|
|
1250
|
+
}
|
|
1251
|
+
function getQuestions(currentVersion) {
|
|
1252
|
+
const currentVersionPrerelease = semver.prerelease(currentVersion);
|
|
1253
|
+
if (!currentVersionPrerelease) {
|
|
1254
|
+
return [
|
|
1255
|
+
{ name: 'Latest (stable) release (e.g. 1.0.0 -> 2.0.0)', value: 'latest' },
|
|
1256
|
+
{ name: 'Pre-release (e.g. 1.0.0 -> 2.0.0-alpha.0)', value: 'prerelease' }
|
|
1257
|
+
];
|
|
1258
|
+
}
|
|
1259
|
+
if (currentVersionPrerelease[0] === 'rc') {
|
|
1260
|
+
return [
|
|
1261
|
+
{ name: 'Latest (stable) release (e.g. 1.0.0-beta.2 -> 1.0.0)', value: 'latest' },
|
|
1262
|
+
{ name: 'Pre-release continuation (e.g. 1.0.0-alpha.0 -> 1.0.0-alpha.1)', value: 'prerelease' }
|
|
1263
|
+
];
|
|
1264
|
+
}
|
|
1265
|
+
return [
|
|
1266
|
+
{ name: 'Latest (stable) release (e.g. 1.0.0-beta.2 -> 1.0.0)', value: 'latest' },
|
|
1267
|
+
{ name: 'Pre-release continuation (e.g. 1.0.0-alpha.0 -> 1.0.0-alpha.1)', value: 'prerelease' },
|
|
1268
|
+
{ name: 'Pre-release promotion (e.g. 1.0.0-alpha.1 -> 1.0.0-beta.0)', value: 'prerelease-promote' }
|
|
1269
|
+
];
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
/**
|
|
1273
|
+
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
1274
|
+
* For licensing, see LICENSE.md.
|
|
1275
|
+
*/
|
|
1276
|
+
function getReleaseType(currentVersion, nextVersion) {
|
|
1277
|
+
const [currentChannel] = semver.prerelease(currentVersion) || ['latest'];
|
|
1278
|
+
const [nextChannel] = semver.prerelease(nextVersion) || ['latest'];
|
|
1279
|
+
if (nextChannel === 'latest') {
|
|
1280
|
+
return 'latest';
|
|
1281
|
+
}
|
|
1282
|
+
if (nextChannel === currentChannel) {
|
|
1283
|
+
return 'prerelease';
|
|
1284
|
+
}
|
|
1285
|
+
return 'prerelease-promote';
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1137
1288
|
/**
|
|
1138
1289
|
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
1139
1290
|
* For licensing, see LICENSE.md.
|
|
@@ -1164,10 +1315,12 @@ const main = async (options) => {
|
|
|
1164
1315
|
shouldIgnoreRootPackage,
|
|
1165
1316
|
externalRepositories
|
|
1166
1317
|
});
|
|
1318
|
+
const releaseType = nextVersion ? getReleaseType(currentVersion, nextVersion) : await promptReleaseType(currentVersion);
|
|
1167
1319
|
const entryPaths = await findChangelogEntryPaths({
|
|
1168
1320
|
cwd,
|
|
1169
1321
|
externalRepositories,
|
|
1170
|
-
shouldSkipLinks
|
|
1322
|
+
shouldSkipLinks,
|
|
1323
|
+
includeSubdirectories: releaseType === 'latest' || releaseType === 'prerelease-promote'
|
|
1171
1324
|
});
|
|
1172
1325
|
const parsedChangesetFiles = await parseChangelogEntries(entryPaths, isSinglePackage);
|
|
1173
1326
|
const sectionsWithEntries = groupEntriesBySection({
|
|
@@ -1191,9 +1344,10 @@ const main = async (options) => {
|
|
|
1191
1344
|
});
|
|
1192
1345
|
}
|
|
1193
1346
|
// Display a prompt to provide a new version in the console.
|
|
1194
|
-
const
|
|
1347
|
+
const newVersion = await determineNextVersion({
|
|
1195
1348
|
currentVersion,
|
|
1196
1349
|
nextVersion,
|
|
1350
|
+
releaseType,
|
|
1197
1351
|
sections: sectionsWithEntries,
|
|
1198
1352
|
packageName: shouldIgnoreRootPackage ? npmPackageToCheck : rootPackageName
|
|
1199
1353
|
});
|
|
@@ -1208,18 +1362,23 @@ const main = async (options) => {
|
|
|
1208
1362
|
cwd,
|
|
1209
1363
|
date,
|
|
1210
1364
|
newVersion,
|
|
1211
|
-
isInternal,
|
|
1212
1365
|
isSinglePackage,
|
|
1213
|
-
packagesMetadata,
|
|
1214
1366
|
releasedPackagesInfo,
|
|
1215
1367
|
sections: filterVisibleSections(sectionsWithEntries)
|
|
1216
1368
|
});
|
|
1217
1369
|
if (disableFilesystemOperations) {
|
|
1218
1370
|
return newChangelog;
|
|
1219
1371
|
}
|
|
1220
|
-
|
|
1372
|
+
let pathsToCommit = entryPaths;
|
|
1373
|
+
// Handle changelog entry files based on release type.
|
|
1374
|
+
if (releaseType === 'latest') {
|
|
1375
|
+
await removeChangelogEntryFiles(entryPaths);
|
|
1376
|
+
}
|
|
1377
|
+
else {
|
|
1378
|
+
pathsToCommit = await moveChangelogEntryFiles(entryPaths);
|
|
1379
|
+
}
|
|
1221
1380
|
await modifyChangelog(newChangelog, cwd);
|
|
1222
|
-
await commitChanges(newVersion,
|
|
1381
|
+
await commitChanges(newVersion, pathsToCommit.map(({ cwd, isRoot, filePaths }) => ({ cwd, isRoot, filePaths })));
|
|
1223
1382
|
logInfo('○ ' + chalk.green('Done!'));
|
|
1224
1383
|
};
|
|
1225
1384
|
/**
|
package/dist/types.d.ts
CHANGED
|
@@ -6,9 +6,9 @@ import type { SECTIONS } from './utils/constants.js';
|
|
|
6
6
|
export type ConfigBase = RepositoryConfig & {
|
|
7
7
|
/**
|
|
8
8
|
* The next version number to use. If not provided, will be calculated based on changes.
|
|
9
|
-
*
|
|
9
|
+
* Must be a valid version in terms of the semantic versioning specification.
|
|
10
10
|
*/
|
|
11
|
-
nextVersion?: string
|
|
11
|
+
nextVersion?: string;
|
|
12
12
|
/**
|
|
13
13
|
* Array of external repository configurations to include in the changelog.
|
|
14
14
|
*/
|
|
@@ -117,4 +117,8 @@ export type FileMetadata = {
|
|
|
117
117
|
communityCredits: Array<string>;
|
|
118
118
|
validations: Array<string>;
|
|
119
119
|
};
|
|
120
|
+
export type ChangelogReleaseType = 'latest' | // e.g. 1.0.0 -> 2.0.0 or 2.0.0-beta.1 -> 2.0.0.
|
|
121
|
+
'prerelease' | // e.g. 1.0.0 -> 2.0.0-alpha.0 or 2.0.0-alpha.0 -> 2.0.0-alpha.1.
|
|
122
|
+
'prerelease-promote';
|
|
123
|
+
export type ReleaseChannel = 'alpha' | 'beta' | 'rc' | 'latest';
|
|
120
124
|
export {};
|
|
@@ -3,16 +3,14 @@
|
|
|
3
3
|
* For licensing, see LICENSE.md.
|
|
4
4
|
*/
|
|
5
5
|
import type { ReleaseInfo, Section } from '../types.js';
|
|
6
|
-
type ComposeChangelogOptions = {
|
|
6
|
+
export type ComposeChangelogOptions = {
|
|
7
7
|
cwd: string;
|
|
8
8
|
date: string;
|
|
9
9
|
currentVersion: string;
|
|
10
10
|
newVersion: string;
|
|
11
11
|
sections: Array<Section>;
|
|
12
12
|
releasedPackagesInfo: Array<ReleaseInfo>;
|
|
13
|
-
isInternal: boolean;
|
|
14
13
|
isSinglePackage: boolean;
|
|
15
|
-
packagesMetadata: Map<string, string>;
|
|
16
14
|
};
|
|
17
15
|
/**
|
|
18
16
|
* Generates a formatted changelog string for a new version release.
|
|
@@ -21,7 +19,6 @@ type ComposeChangelogOptions = {
|
|
|
21
19
|
* * A version header with a link to the GitHub comparison view (except for an initial version).
|
|
22
20
|
* * Sections with grouped changelog entries and their messages.
|
|
23
21
|
* * A collapsible summary of released packages and their version bumps for a mono-repository setup.
|
|
24
|
-
* * Special handling for
|
|
22
|
+
* * Special handling for single-package repositories.
|
|
25
23
|
*/
|
|
26
24
|
export declare function composeChangelog(options: ComposeChangelogOptions): Promise<string>;
|
|
27
|
-
export {};
|
|
@@ -7,6 +7,7 @@ export declare const CHANGELOG_HEADER = "Changelog\n=========";
|
|
|
7
7
|
export declare const NPM_URL = "https://www.npmjs.com/package";
|
|
8
8
|
export declare const VERSIONING_POLICY_URL = "https://ckeditor.com/docs/ckeditor5/latest/framework/guides/support/versioning-policy.html";
|
|
9
9
|
export declare const CHANGESET_DIRECTORY = ".changelog";
|
|
10
|
+
export declare const PRE_RELEASE_DIRECTORY = "pre-release";
|
|
10
11
|
export declare const TEMPLATE_FILE: string;
|
|
11
12
|
export declare const SECTIONS: {
|
|
12
13
|
readonly major: {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md.
|
|
4
|
+
*/
|
|
5
|
+
import type { ReleaseChannel } from '../types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Detects the release channel from a version string.
|
|
8
|
+
*/
|
|
9
|
+
export declare function detectReleaseChannel(version: string, promotePrerelease?: boolean): ReleaseChannel;
|
|
@@ -2,25 +2,21 @@
|
|
|
2
2
|
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
3
|
* For licensing, see LICENSE.md.
|
|
4
4
|
*/
|
|
5
|
-
import type { SectionsWithEntries } from '../types.js';
|
|
6
|
-
type NextVersionOutput = {
|
|
7
|
-
isInternal: boolean;
|
|
8
|
-
newVersion: string;
|
|
9
|
-
};
|
|
5
|
+
import type { ChangelogReleaseType, SectionsWithEntries } from '../types.js';
|
|
10
6
|
export type DetermineNextVersionOptions = {
|
|
11
7
|
sections: SectionsWithEntries;
|
|
12
8
|
currentVersion: string;
|
|
13
9
|
packageName: string;
|
|
14
10
|
nextVersion: string | undefined;
|
|
11
|
+
releaseType: ChangelogReleaseType;
|
|
15
12
|
};
|
|
16
13
|
/**
|
|
17
14
|
* Determines the next version for a single package or a mono-repository setup based on
|
|
18
|
-
* the change sections,
|
|
15
|
+
* the change sections, user input, and semantic versioning rules.
|
|
19
16
|
*
|
|
20
17
|
* The function handles:
|
|
21
18
|
* * Automatic version bump calculation from categorized changelog sections (major, minor, patch).
|
|
22
|
-
* *
|
|
19
|
+
* * Version bump for prerelease channels.
|
|
23
20
|
* * User prompts for version input when no explicit version is provided.
|
|
24
21
|
*/
|
|
25
|
-
export declare function determineNextVersion(options: DetermineNextVersionOptions): Promise<
|
|
26
|
-
export {};
|
|
22
|
+
export declare function determineNextVersion(options: DetermineNextVersionOptions): Promise<string>;
|
|
@@ -7,6 +7,7 @@ type FindChangelogEntryPathsOptions = {
|
|
|
7
7
|
cwd: string;
|
|
8
8
|
externalRepositories: Array<RepositoryConfig>;
|
|
9
9
|
shouldSkipLinks: boolean;
|
|
10
|
+
includeSubdirectories?: boolean;
|
|
10
11
|
};
|
|
11
12
|
/**
|
|
12
13
|
* Gathers changelog entry file paths (Markdown files) from the main repository and any configured external repositories.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md.
|
|
4
|
+
*/
|
|
5
|
+
import { type ChangelogReleaseType } from '../types.js';
|
|
6
|
+
export declare function getReleaseType(currentVersion: string, nextVersion: string): ChangelogReleaseType;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md.
|
|
4
|
+
*/
|
|
5
|
+
import type { ChangesetPathsWithGithubUrl } from '../types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Moves changelog entry files to cycle-specific directories instead of deleting them.
|
|
8
|
+
* This preserves the history of changes across prerelease cycles.
|
|
9
|
+
* Returns an array of entry paths that were modified by the move operation
|
|
10
|
+
*/
|
|
11
|
+
export declare function moveChangelogEntryFiles(entryPaths: Array<ChangesetPathsWithGithubUrl>): Promise<Array<ChangesetPathsWithGithubUrl>>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md.
|
|
4
|
+
*/
|
|
5
|
+
import type { ChangelogReleaseType } from '../types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Prompts the user to choose between latest or prerelease
|
|
8
|
+
*/
|
|
9
|
+
export declare function promptReleaseType(currentVersion: string): Promise<ChangelogReleaseType>;
|
|
@@ -3,12 +3,15 @@
|
|
|
3
3
|
* For licensing, see LICENSE.md.
|
|
4
4
|
*/
|
|
5
5
|
import { type ReleaseType } from 'semver';
|
|
6
|
+
import type { ChangelogReleaseType, ReleaseChannel } from '../types.js';
|
|
6
7
|
type Options = {
|
|
7
8
|
packageName: string;
|
|
8
9
|
version: string;
|
|
9
10
|
bumpType: ReleaseType;
|
|
11
|
+
releaseChannel: ReleaseChannel;
|
|
10
12
|
indentLevel?: number;
|
|
11
13
|
displayValidationWarning: boolean;
|
|
14
|
+
releaseType: ChangelogReleaseType;
|
|
12
15
|
};
|
|
13
16
|
/**
|
|
14
17
|
* Prompts the user to provide a new version for a package.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md.
|
|
4
|
+
*/
|
|
5
|
+
import type { ChangelogReleaseType } from '../types.js';
|
|
6
|
+
type ValidateOptions = {
|
|
7
|
+
newVersion: string;
|
|
8
|
+
version: string;
|
|
9
|
+
releaseType: ChangelogReleaseType;
|
|
10
|
+
packageName: string;
|
|
11
|
+
suggestedVersion: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function validateInputVersion(options: ValidateOptions): Promise<string | true>;
|
|
14
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ckeditor/ckeditor5-dev-changelog",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "51.0.0",
|
|
4
4
|
"description": "A CKEditor 5 development tool for handling changelogs.",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"author": "CKSource (http://cksource.com/)",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"ckeditor5-dev-changelog-create-entry": "bin/generate-template.js"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@ckeditor/ckeditor5-dev-utils": "^
|
|
31
|
+
"@ckeditor/ckeditor5-dev-utils": "^51.0.0",
|
|
32
32
|
"chalk": "^5.0.0",
|
|
33
33
|
"date-fns": "^4.0.0",
|
|
34
34
|
"fs-extra": "^11.0.0",
|
package/template/template.md
CHANGED
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
#
|
|
10
10
|
# For guidance on breaking changes, see:
|
|
11
11
|
# https://ckeditor.com/docs/ckeditor5/latest/updating/versioning-policy.html#major-and-minor-breaking-changes
|
|
12
|
-
type:
|
|
12
|
+
type:
|
|
13
13
|
|
|
14
14
|
# Optional: Affected package(s), using short names.
|
|
15
|
-
#
|
|
15
|
+
# Leave empty when used in a single-package repository.
|
|
16
16
|
# Example: ckeditor5-core
|
|
17
17
|
scope:
|
|
18
18
|
-
|