Skip to content

Commit

Permalink
feat: implement scoped changelogs (#421)
Browse files Browse the repository at this point in the history
Co-authored-by: Gabriel Terwesten <gabriel@terwesten.net>
  • Loading branch information
lesnitsky and blaugold authored Nov 30, 2022
1 parent ce6e4ef commit f0eca8d
Show file tree
Hide file tree
Showing 10 changed files with 440 additions and 204 deletions.
47 changes: 42 additions & 5 deletions docs/configuration/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ Supported hosts:
repository: https://github.com/invertase/melos
```

When using a self-hosted GitHub or GitLab instance, you can specify the repository location like this:
When using a self-hosted GitHub or GitLab instance, you can specify the
repository location like this:

```yaml
repository:
Expand Down Expand Up @@ -184,7 +185,7 @@ A template for the commit message, that is generated by `melos version`.
Templates must use mustache syntax and have the following variables available:

- `new_package_versions`: A list of the versioned packages and their new
versions.
versions.

The default is:

Expand Down Expand Up @@ -240,7 +241,8 @@ command:
Whether to add links to commits in the CHANGELOG.md that is generated by
`melos version`.

Enabling this option, requires [`repository`](/configuration/overview#repository) to be specified.
Enabling this option, requires
[`repository`](/configuration/overview#repository) to be specified.

```yaml
command:
Expand All @@ -259,6 +261,41 @@ command:
workspaceChangelog: true
```

### `command/version/changelogs`

Configure aggregate changelogs which document the changes made to multiple
packages.

```yaml
command:
version:
changelogs:
- path: FOO_CHANGELOG.md
description: |
All notable changes to foo packages will be documented in this file.
packageFilters:
scope: foo_*
```

### `command/version/changelogs/path`

The path to the changelog file relative to the workspace root.

### `command/version/changelogs/packageFilters`

Package filters to match packages that should be included in the changelog.

See [Filtering Packages](/filters) for all available filters.

### `command/version/changelogs/description`

> optional

A description to include at the top of the changelog.

If you change this value, you will need to manually update the changelog file to
reflect the new description.

### `command/version/updateGitTagRefs`

Whether to update package version tags in git dependencies of dependents when
Expand All @@ -276,7 +313,7 @@ command:

### `command/version/releaseUrl`

Whether to generate and print a link to the prefilled release creation page for each package after
versioning. Defaults to `false`.
Whether to generate and print a link to the prefilled release creation page for
each package after versioning. Defaults to `false`.

[glob]: https://docs.python.org/3/library/glob.html
6 changes: 3 additions & 3 deletions packages/melos/lib/src/commands/runner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import 'package:yaml/yaml.dart';
import 'package:yaml_edit/yaml_edit.dart';

import '../command_runner/version.dart';
import '../common/aggregate_changelog.dart';
import '../common/exception.dart';
import '../common/git.dart';
import '../common/git_commit.dart';
Expand All @@ -27,11 +28,10 @@ import '../common/intellij_project.dart';
import '../common/io.dart';
import '../common/pending_package_update.dart';
import '../common/platform.dart';
import '../common/utils.dart';
import '../common/utils.dart' as utils;
import '../common/versioning.dart' as versioning;
import '../common/utils.dart';
import '../common/versioning.dart';
import '../common/workspace_changelog.dart';
import '../common/versioning.dart' as versioning;
import '../global_options.dart';
import '../logging.dart';
import '../package.dart';
Expand Down
61 changes: 45 additions & 16 deletions packages/melos/lib/src/commands/version.dart
Original file line number Diff line number Diff line change
Expand Up @@ -650,24 +650,51 @@ mixin _VersionMixin on _RunMixin {
}
});

// Build a workspace root changelog if enabled.
if (updateChangelog &&
workspace.config.commands.version.workspaceChangelog) {
final today = DateTime.now();
final dateSlug =
"${today.year.toString()}-${today.month.toString().padLeft(2, '0')}-"
"${today.day.toString().padLeft(2, '0')}";
final workspaceChangelog = WorkspaceChangelog(
workspace,
dateSlug,
pendingPackageUpdates,
logger,
if (updateChangelog) {
await Future.wait(
workspace.config.commands.version.aggregateChangelogs
.map((changelogConfig) {
return writeAggregateChangelog(
workspace,
changelogConfig,
pendingPackageUpdates,
);
}),
);

await workspaceChangelog.write();
}
}

Future<void> writeAggregateChangelog(
MelosWorkspace workspace,
AggregateChangelogConfig config,
List<MelosPendingPackageUpdate> pendingPackageUpdates,
) async {
final today = DateTime.now();
final dateSlug = [
today.year.toString(),
today.month.toString().padLeft(2, '0'),
today.day.toString().padLeft(2, '0')
].join('-');

final packages =
await workspace.allPackages.applyFilter(config.packageFilter);
// ignore: parameter_assignments
pendingPackageUpdates = pendingPackageUpdates
.where((update) => packages[update.package.name] != null)
.toList();

final changelog = AggregateChangelog(
workspace,
config.description,
dateSlug,
pendingPackageUpdates,
logger,
config.path,
);

await changelog.write();
}

Set<String> _getPackagesWithVersionableCommits(
Map<String, List<RichGitCommit>> packageCommits,
) {
Expand Down Expand Up @@ -772,13 +799,15 @@ mixin _VersionMixin on _RunMixin {
List<MelosPendingPackageUpdate> pendingPackageUpdates,
MelosWorkspace workspace,
) async {
if (workspace.config.commands.version.workspaceChangelog) {
for (final changelog
in workspace.config.commands.version.aggregateChangelogs) {
await gitAdd(
'CHANGELOG.md',
changelog.path,
workingDirectory: workspace.path,
logger: logger,
);
}

await Future.forEach(pendingPackageUpdates,
(MelosPendingPackageUpdate pendingPackageUpdate) async {
await gitAdd(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,29 @@ import '../workspace.dart';
import 'changelog.dart';
import 'io.dart';
import 'pending_package_update.dart';
import 'utils.dart';

class WorkspaceChangelog {
WorkspaceChangelog(
class AggregateChangelog {
AggregateChangelog(
this.workspace,
this.title,
this.description,
this.newEntryTitle,
this.pendingPackageUpdates,
this.logger,
this.path,
);

final MelosWorkspace workspace;
final String title;
final String? description;
final String newEntryTitle;
final MelosLogger logger;
final List<MelosPendingPackageUpdate> pendingPackageUpdates;
final String path;

String get _changelogFileHeader => '''
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
${description?.withoutTrailing('\n') ?? ''}
''';

String _packageVersionTitle(MelosPendingPackageUpdate update) {
Expand All @@ -67,7 +71,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
pendingPackageUpdates.where((update) => !update.hasBreakingChanges);

body.writeln(_changelogFileHeader);
body.writeln('## $title');
body.writeln('## $newEntryTitle');
body.writeln();
body.writeln('### Changes');
body.writeln();
Expand Down Expand Up @@ -153,8 +157,8 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
return body.toString();
}

String get path {
return joinAll([workspace.path, 'CHANGELOG.md']);
String get absolutePath {
return joinAll([workspace.path, path]);
}

@override
Expand All @@ -163,8 +167,8 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
}

Future<String> read() async {
if (fileExists(path)) {
final contents = await readTextFileAsync(path);
if (fileExists(absolutePath)) {
final contents = await readTextFileAsync(absolutePath);
return contents.replaceFirst(_changelogFileHeader, '');
}
return '';
Expand All @@ -181,6 +185,6 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
}
contents = '$markdown$contents';

await writeTextFileAsync(path, contents);
await writeTextFileAsync(absolutePath, contents);
}
}
9 changes: 8 additions & 1 deletion packages/melos/lib/src/common/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ const envKeyMelosTerminalWidth = 'MELOS_TERMINAL_WIDTH';

final melosPackageUri = Uri.parse('package:melos/melos.dart');

extension Indent on String {
extension StringUtils on String {
String indent(String indent) {
final split = this.split('\n');

Expand All @@ -97,6 +97,13 @@ extension Indent on String {

return buffer.toString();
}

String withoutTrailing(String trailer) {
if (endsWith(trailer)) {
return substring(0, length - trailer.length);
}
return this;
}
}

int get terminalWidth {
Expand Down
2 changes: 1 addition & 1 deletion packages/melos/lib/src/common/versioning.dart
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ Version incrementBuildNumber(Version currentVersion) {
if (build.isEmpty) {
nextBuildNumber = 0;
} else if (build.length == 1) {
final Object? buildNumber = build.first;
final buildNumber = build.first;
if (buildNumber is int) {
nextBuildNumber = buildNumber + 1;
}
Expand Down
Loading

0 comments on commit f0eca8d

Please sign in to comment.