From e9ad2bcf945880146619700d66e66ddc3342c762 Mon Sep 17 00:00:00 2001 From: Sigurd Meldgaard Date: Fri, 6 Sep 2024 12:13:00 +0200 Subject: [PATCH] `pub bump` command (#4361) --- lib/src/command/bump.dart | 131 ++++++++++++++++++ lib/src/command_runner.dart | 2 + lib/src/pub_embeddable_command.dart | 2 + test/bump_test.dart | 103 ++++++++++++++ .../embedding/embedding_test/--help.txt | 1 + .../goldens/help_test/pub bump --help.txt | 18 +++ .../help_test/pub bump breaking --help.txt | 12 ++ .../help_test/pub bump major --help.txt | 12 ++ .../help_test/pub bump minor --help.txt | 12 ++ .../help_test/pub bump patch --help.txt | 12 ++ 10 files changed, 305 insertions(+) create mode 100644 lib/src/command/bump.dart create mode 100644 test/bump_test.dart create mode 100644 test/testdata/goldens/help_test/pub bump --help.txt create mode 100644 test/testdata/goldens/help_test/pub bump breaking --help.txt create mode 100644 test/testdata/goldens/help_test/pub bump major --help.txt create mode 100644 test/testdata/goldens/help_test/pub bump minor --help.txt create mode 100644 test/testdata/goldens/help_test/pub bump patch --help.txt diff --git a/lib/src/command/bump.dart b/lib/src/command/bump.dart new file mode 100644 index 000000000..906ca2b13 --- /dev/null +++ b/lib/src/command/bump.dart @@ -0,0 +1,131 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:async'; + +import 'package:collection/collection.dart'; +import 'package:pub_semver/pub_semver.dart'; +import 'package:yaml/yaml.dart'; +import 'package:yaml_edit/yaml_edit.dart'; + +import '../command.dart'; +import '../io.dart'; +import '../log.dart' as log; + +class BumpSubcommand extends PubCommand { + @override + final String name; + @override + final String description; + + final Version Function(Version) updateVersion; + BumpSubcommand(this.name, this.description, this.updateVersion) { + argParser.addFlag( + 'dry-run', + abbr: 'n', + negatable: false, + help: "Report what would change, but don't change anything.", + ); + } + + String? _versionLines(YamlMap map, String text, String prefix) { + final entry = map.nodes.entries + .firstWhereOrNull((e) => (e.key as YamlNode).value == 'version'); + if (entry == null) return null; + + final firstLine = (entry.key as YamlNode).span.start.line; + final lastLine = entry.value.span.end.line; + final lines = text.split('\n'); + return lines + .sublist(firstLine, lastLine + 1) + .map((x) => '$prefix$x') + .join('\n'); + } + + @override + Future runProtected() async { + final pubspec = entrypoint.workPackage.pubspec; + final currentVersion = pubspec.version; + + final newVersion = updateVersion(currentVersion); + + final originalPubspecText = + readTextFile(entrypoint.workPackage.pubspecPath); + final yamlEditor = YamlEditor(originalPubspecText); + yamlEditor.update(['version'], newVersion.toString()); + final updatedPubspecText = yamlEditor.toString(); + final beforeText = _versionLines(pubspec.fields, originalPubspecText, '- '); + final afterText = _versionLines( + yamlEditor.parseAt([]) as YamlMap, + updatedPubspecText, + '+ ', + ); + if (argResults.flag('dry-run')) { + log.message('Would update version from $currentVersion to $newVersion.'); + log.message('Diff:'); + if (beforeText != null) { + log.message(beforeText); + } + if (afterText != null) { + log.message(afterText); + } + } else { + log.message('Updating version from $currentVersion to $newVersion.'); + log.message('Diff:'); + + if (beforeText != null) { + log.message(beforeText); + } + if (afterText != null) { + log.message(afterText); + log.message('\nRemember to update `CHANGELOG.md` before publishing.'); + } + writeTextFile( + entrypoint.workPackage.pubspecPath, + yamlEditor.toString(), + ); + } + } +} + +class BumpCommand extends PubCommand { + @override + String get name => 'bump'; + @override + String get description => ''' +Increases the version number of the current package. +'''; + + BumpCommand() { + addSubcommand( + BumpSubcommand( + 'major', + 'Increment the major version number (eg. 3.1.2 -> 4.0.0)', + (v) => v.nextMajor, + ), + ); + addSubcommand( + BumpSubcommand( + 'minor', + 'Increment the minor version number (eg. 3.1.2 -> 3.2.0)', + (v) => v.nextMinor, + ), + ); + addSubcommand( + BumpSubcommand( + 'patch', + 'Increment the patch version number (eg. 3.1.2 -> 3.1.3)', + (v) => v.nextPatch, + ), + ); + + addSubcommand( + BumpSubcommand( + 'breaking', + 'Increment to the next breaking version (eg. 0.1.2 -> 0.2.0)', + (v) => v.nextBreaking, + ), + ); + } +} diff --git a/lib/src/command_runner.dart b/lib/src/command_runner.dart index e089aad84..cb42f4761 100644 --- a/lib/src/command_runner.dart +++ b/lib/src/command_runner.dart @@ -11,6 +11,7 @@ import 'package:path/path.dart' as p; import 'command.dart' show PubTopLevel, lineLength; import 'command/add.dart'; +import 'command/bump.dart'; import 'command/cache.dart'; import 'command/deps.dart'; import 'command/downgrade.dart'; @@ -139,6 +140,7 @@ class PubCommandRunner extends CommandRunner implements PubTopLevel { // When adding new commands be sure to also add them to // `pub_embeddable_command.dart`. addCommand(AddCommand()); + addCommand(BumpCommand()); addCommand(CacheCommand()); addCommand(DepsCommand()); addCommand(DowngradeCommand()); diff --git a/lib/src/pub_embeddable_command.dart b/lib/src/pub_embeddable_command.dart index a5fad5156..e36bb4229 100644 --- a/lib/src/pub_embeddable_command.dart +++ b/lib/src/pub_embeddable_command.dart @@ -5,6 +5,7 @@ import 'command.dart' show PubCommand, PubTopLevel; import 'command.dart'; import 'command/add.dart'; +import 'command/bump.dart'; import 'command/cache.dart'; import 'command/deps.dart'; import 'command/downgrade.dart'; @@ -69,6 +70,7 @@ class PubEmbeddableCommand extends PubCommand implements PubTopLevel { // // New commands should (most likely) be included in both lists. addSubcommand(AddCommand()); + addSubcommand(BumpCommand()); addSubcommand(CacheCommand()); addSubcommand(DepsCommand()); addSubcommand(DowngradeCommand()); diff --git a/test/bump_test.dart b/test/bump_test.dart new file mode 100644 index 000000000..b558a5562 --- /dev/null +++ b/test/bump_test.dart @@ -0,0 +1,103 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:test/test.dart'; + +import 'descriptor.dart'; +import 'test_pub.dart'; + +void main() { + void testBump(String part, String from, String to) { + test('Bumps the $part version from $from to $to', () async { + await dir(appPath, [ + file( + 'pubspec.yaml', + ''' +name: myapp +version: $from # comment +environment: + sdk: $defaultSdkConstraint +''', + ), + ]).create(); + await runPub( + args: ['bump', part, '--dry-run'], + output: ''' +Would update version from $from to $to. +Diff: +- version: $from # comment ++ version: $to # comment +''', + ); + await runPub( + args: ['bump', part], + output: ''' +Updating version from $from to $to. +Diff: +- version: $from # comment ++ version: $to # comment + +Remember to update `CHANGELOG.md` before publishing. + ''', + ); + await appDir(pubspec: {'version': to}).validate(); + }); + } + + testBump('major', '0.0.0', '1.0.0'); + testBump('major', '1.2.3', '2.0.0'); + testBump('minor', '0.1.1-dev+2', '0.2.0'); + testBump('minor', '1.2.3', '1.3.0'); + testBump('patch', '0.1.1-dev+2', '0.1.1'); + testBump('patch', '0.1.1+2', '0.1.2'); + testBump('patch', '1.2.3', '1.2.4'); + testBump('breaking', '0.2.0', '0.3.0'); + testBump('breaking', '1.2.3', '2.0.0'); + + test('Creates top-level version field if missing', () async { + await dir(appPath, [ + file('pubspec.yaml', ''' +name: my_app +'''), + ]).create(); + await runPub( + args: ['bump', 'breaking'], + output: contains('Updating version from 0.0.0 to 0.1.0'), + ); + await dir(appPath, [ + file('pubspec.yaml', ''' +name: my_app +version: 0.1.0 +'''), + ]).validate(); + }); + + test('Writes all lines of diff', () async { + await dir(appPath, [ + file('pubspec.yaml', ''' +name: my_app +version: >- + 1.0.0 +'''), + ]).create(); + await runPub( + args: ['bump', 'minor'], + output: allOf( + contains('Updating version from 1.0.0 to 1.1.0'), + contains(''' +Diff: +- version: >- +- 1.0.0 ++ version: 1.1.0 +'''), + ), + ); + await dir(appPath, [ + file('pubspec.yaml', ''' +name: my_app +version: 1.1.0 +'''), + ]).validate(); + }); +} diff --git a/test/testdata/goldens/embedding/embedding_test/--help.txt b/test/testdata/goldens/embedding/embedding_test/--help.txt index 55eacc6be..16beaacbf 100644 --- a/test/testdata/goldens/embedding/embedding_test/--help.txt +++ b/test/testdata/goldens/embedding/embedding_test/--help.txt @@ -14,6 +14,7 @@ Usage: pub_command_runner pub [arguments...] Available subcommands: add Add dependencies to `pubspec.yaml`. + bump Increases the version number of the current package. cache Work with the system cache. deps Print package dependencies. downgrade Downgrade the current package's dependencies to oldest versions. diff --git a/test/testdata/goldens/help_test/pub bump --help.txt b/test/testdata/goldens/help_test/pub bump --help.txt new file mode 100644 index 000000000..a076958bf --- /dev/null +++ b/test/testdata/goldens/help_test/pub bump --help.txt @@ -0,0 +1,18 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub bump --help +Increases the version number of the current package. + + +Usage: pub bump [arguments...] +-h, --help Print this usage information. + +Available subcommands: + breaking Increment to the next breaking version (eg. 0.1.2 -> 0.2.0) + major Increment the major version number (eg. 3.1.2 -> 4.0.0) + minor Increment the minor version number (eg. 3.1.2 -> 3.2.0) + patch Increment the patch version number (eg. 3.1.2 -> 3.1.3) + +Run "pub help" to see global options. + diff --git a/test/testdata/goldens/help_test/pub bump breaking --help.txt b/test/testdata/goldens/help_test/pub bump breaking --help.txt new file mode 100644 index 000000000..d25b9f9b7 --- /dev/null +++ b/test/testdata/goldens/help_test/pub bump breaking --help.txt @@ -0,0 +1,12 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub bump breaking --help +Increment to the next breaking version (eg. 0.1.2 -> 0.2.0) + +Usage: pub bump breaking [arguments...] +-h, --help Print this usage information. +-n, --dry-run Report what would change, but don't change anything. + +Run "pub help" to see global options. + diff --git a/test/testdata/goldens/help_test/pub bump major --help.txt b/test/testdata/goldens/help_test/pub bump major --help.txt new file mode 100644 index 000000000..15937ad36 --- /dev/null +++ b/test/testdata/goldens/help_test/pub bump major --help.txt @@ -0,0 +1,12 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub bump major --help +Increment the major version number (eg. 3.1.2 -> 4.0.0) + +Usage: pub bump major [arguments...] +-h, --help Print this usage information. +-n, --dry-run Report what would change, but don't change anything. + +Run "pub help" to see global options. + diff --git a/test/testdata/goldens/help_test/pub bump minor --help.txt b/test/testdata/goldens/help_test/pub bump minor --help.txt new file mode 100644 index 000000000..927d5c2a2 --- /dev/null +++ b/test/testdata/goldens/help_test/pub bump minor --help.txt @@ -0,0 +1,12 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub bump minor --help +Increment the minor version number (eg. 3.1.2 -> 3.2.0) + +Usage: pub bump minor [arguments...] +-h, --help Print this usage information. +-n, --dry-run Report what would change, but don't change anything. + +Run "pub help" to see global options. + diff --git a/test/testdata/goldens/help_test/pub bump patch --help.txt b/test/testdata/goldens/help_test/pub bump patch --help.txt new file mode 100644 index 000000000..057b66934 --- /dev/null +++ b/test/testdata/goldens/help_test/pub bump patch --help.txt @@ -0,0 +1,12 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub bump patch --help +Increment the patch version number (eg. 3.1.2 -> 3.1.3) + +Usage: pub bump patch [arguments...] +-h, --help Print this usage information. +-n, --dry-run Report what would change, but don't change anything. + +Run "pub help" to see global options. +