From fed343b2dd58e9a30b29244c38f8ba815a104082 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20=C5=BD=C3=ADdek?= Date: Wed, 5 Jun 2024 10:02:39 +0200 Subject: [PATCH] feat: `changelogFormat` configuration, add `includeDate` boolean (#720) * feat: changelogFormat configuration, add includeDate boolean * fix new line * add test * docs * fix json * fmt * use intl * internal annot * eol --- docs/configuration/overview.mdx | 19 ++++++++++- .../lib/src/command_configs/version.dart | 28 ++++++++++++++-- packages/melos/lib/src/common/changelog.dart | 24 +++++++++++++- packages/melos/pubspec.yaml | 1 + packages/melos/test/changelog_test.dart | 32 +++++++++++++++++++ 5 files changed, 100 insertions(+), 4 deletions(-) diff --git a/docs/configuration/overview.mdx b/docs/configuration/overview.mdx index eee458cb6..35386bd58 100644 --- a/docs/configuration/overview.mdx +++ b/docs/configuration/overview.mdx @@ -364,4 +364,21 @@ Whether to include commit bodies in the changelog. Defaults to `false`. #### onlyBreaking -Whether to include only breaking changes in the changelog. Defaults to `true`. \ No newline at end of file +Whether to include only breaking changes in the changelog. Defaults to `true`. + +### changelogFormat + +Configure the format of the generated CHANGELOG.md. + +```yaml +command: + version: + changelogFormat: + includeDate: true +``` + +#### includeDate + +Whether to include the date in the generated CHANGELOG.md. Defaults to `false`. + +With enabled, changelog entry header will include the date in the `yyyy-MM-dd` format. diff --git a/packages/melos/lib/src/command_configs/version.dart b/packages/melos/lib/src/command_configs/version.dart index 71cea179d..35afbb358 100644 --- a/packages/melos/lib/src/command_configs/version.dart +++ b/packages/melos/lib/src/command_configs/version.dart @@ -22,6 +22,7 @@ class VersionCommandConfigs { List? aggregateChangelogs, this.fetchTags = true, this.hooks = VersionLifecycleHooks.empty, + this.includeDateInChangelogEntry = false, }) : _aggregateChangelogs = aggregateChangelogs; factory VersionCommandConfigs.fromYaml( @@ -156,6 +157,19 @@ class VersionCommandConfigs { path: 'command/version/changelogCommitBodies', ); + final changelogFormat = assertKeyIsA?>( + key: 'changelogFormat', + map: yaml, + path: 'command/version', + ) ?? + const {}; + + final includeDate = assertKeyIsA( + key: 'includeDate', + map: changelogFormat, + path: 'command/version/changelogFormat', + ); + return VersionCommandConfigs( branch: branch, message: message, @@ -169,6 +183,7 @@ class VersionCommandConfigs { aggregateChangelogs: aggregateChangelogs, fetchTags: fetchTags ?? true, hooks: hooks, + includeDateInChangelogEntry: includeDate ?? false, ); } @@ -217,6 +232,9 @@ class VersionCommandConfigs { /// Lifecycle hooks for this command. final VersionLifecycleHooks hooks; + /// Whether to include the date in the changelog entry in format `yyyy-MM-dd`. + final bool includeDateInChangelogEntry; + Map toJson() { return { if (branch != null) 'branch': branch, @@ -229,6 +247,9 @@ class VersionCommandConfigs { aggregateChangelogs.map((config) => config.toJson()).toList(), 'fetchTags': fetchTags, 'hooks': hooks.toJson(), + 'changelogFormat': { + 'includeDate': includeDateInChangelogEntry, + }, }; } @@ -246,7 +267,8 @@ class VersionCommandConfigs { const DeepCollectionEquality() .equals(other.aggregateChangelogs, aggregateChangelogs) && other.fetchTags == fetchTags && - other.hooks == hooks; + other.hooks == hooks && + other.includeDateInChangelogEntry == includeDateInChangelogEntry; @override int get hashCode => @@ -260,7 +282,8 @@ class VersionCommandConfigs { releaseUrl.hashCode ^ const DeepCollectionEquality().hash(aggregateChangelogs) ^ fetchTags.hashCode ^ - hooks.hashCode; + hooks.hashCode ^ + includeDateInChangelogEntry.hashCode; @override String toString() { @@ -276,6 +299,7 @@ VersionCommandConfigs( aggregateChangelogs: $aggregateChangelogs, fetchTags: $fetchTags, hooks: $hooks, + includeDateInChangelogEntry: $includeDateInChangelogEntry, )'''; } } diff --git a/packages/melos/lib/src/common/changelog.dart b/packages/melos/lib/src/common/changelog.dart index 6267c4493..784021d5f 100644 --- a/packages/melos/lib/src/common/changelog.dart +++ b/packages/melos/lib/src/common/changelog.dart @@ -1,3 +1,5 @@ +import 'package:intl/intl.dart'; +import 'package:meta/meta.dart'; import 'package:path/path.dart' as p; import 'package:pub_semver/pub_semver.dart'; @@ -93,9 +95,20 @@ extension MarkdownStringBufferExtension on StringBuffer { extension ChangelogStringBufferExtension on StringBuffer { void writePackageChangelog(MelosPendingPackageUpdate update) { + final config = update.workspace.config; + final includeDate = config.commands.version.includeDateInChangelogEntry; + // Changelog entry header. write('## '); - writeln(update.nextVersion); + if (includeDate) { + final now = DateTime.now(); + + write(update.nextVersion); + write(' - '); + writeln(now.toFormattedString()); + } else { + writeln(update.nextVersion); + } writeln(); if (update.reason == PackageUpdateReason.dependency) { @@ -230,3 +243,12 @@ extension on String { }); } } + +extension DateTimeExt on DateTime { + /// Returns a formatted string in the format `yyyy-MM-dd`. + @internal + String toFormattedString() { + final format = DateFormat('yyyy-MM-dd'); + return format.format(this); + } +} diff --git a/packages/melos/pubspec.yaml b/packages/melos/pubspec.yaml index 6940df84a..398a658e8 100644 --- a/packages/melos/pubspec.yaml +++ b/packages/melos/pubspec.yaml @@ -33,6 +33,7 @@ dependencies: glob: ^2.1.2 graphs: ^2.3.1 http: ^1.1.0 + intl: ^0.19.0 meta: ^1.10.0 mustache_template: ^2.0.0 path: ^1.8.3 diff --git a/packages/melos/test/changelog_test.dart b/packages/melos/test/changelog_test.dart index 1dc0c89c9..1ba4115a7 100644 --- a/packages/melos/test/changelog_test.dart +++ b/packages/melos/test/changelog_test.dart @@ -120,6 +120,35 @@ void main() { ); }); + group('includeDateInChangelogEntry', () { + test('should not include date by default', () { + final changelogEntryDate = DateTime.now().toFormattedString(); + + final workspace = buildWorkspaceWithRepository(); + final package = workspace.allPackages['test_pkg']!; + final commit = testCommit(message: 'feat: a'); + + expect( + renderCommitPackageUpdate(workspace, package, commit), + isNot(contains(changelogEntryDate)), + ); + }); + + test('should include date when enabled', () { + final changelogEntryDate = DateTime.now().toFormattedString(); + + final workspace = + buildWorkspaceWithRepository(includeDateInChangelogEntry: true); + final package = workspace.allPackages['test_pkg']!; + final commit = testCommit(message: 'feat: a'); + + expect( + renderCommitPackageUpdate(workspace, package, commit), + contains(changelogEntryDate), + ); + }); + }); + test('when repository is specified, adds links to referenced issues/PRs', () { final workspace = buildWorkspaceWithRepository(); final package = workspace.allPackages['test_pkg']!; @@ -137,6 +166,7 @@ MelosWorkspace buildWorkspaceWithRepository({ bool includeScopes = false, bool linkToCommits = false, bool includeCommitId = false, + bool includeDateInChangelogEntry = false, }) { final workspaceBuilder = VirtualWorkspaceBuilder( ''' @@ -146,6 +176,8 @@ MelosWorkspace buildWorkspaceWithRepository({ includeScopes: $includeScopes includeCommitId: $includeCommitId linkToCommits: $linkToCommits + changelogFormat: + includeDate: $includeDateInChangelogEntry ''', )..addPackage( '''