Skip to content

Commit

Permalink
feat: add update command (#435)
Browse files Browse the repository at this point in the history
  • Loading branch information
hkuczynski committed Jun 24, 2022
1 parent 991e138 commit afce55c
Show file tree
Hide file tree
Showing 9 changed files with 174 additions and 26 deletions.
1 change: 1 addition & 0 deletions lib/src/command_runner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class VeryGoodCommandRunner extends CommandRunner<int> {
addCommand(CreateCommand(analytics: _analytics, logger: logger));
addCommand(PackagesCommand(logger: logger));
addCommand(TestCommand(logger: logger));
addCommand(UpdateCommand(logger: logger, pubUpdater: pubUpdater));
}

/// Standard timeout duration for the CLI.
Expand Down
1 change: 1 addition & 0 deletions lib/src/commands/commands.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export 'create/create.dart';
export 'packages.dart';
export 'test/test.dart';
export 'update.dart';
58 changes: 58 additions & 0 deletions lib/src/commands/update.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import 'package:args/command_runner.dart';
import 'package:mason/mason.dart' hide packageVersion;
import 'package:pub_updater/pub_updater.dart';
import 'package:very_good_cli/src/command_runner.dart';
import 'package:very_good_cli/src/version.dart';

/// {@template update_command}
/// `very_good update` command which updates very_good cli.
/// {@endtemplate}
class UpdateCommand extends Command<int> {
/// {@macro update_command}
UpdateCommand({
Logger? logger,
PubUpdater? pubUpdater,
}) : _logger = logger ?? Logger(),
_pubUpdater = pubUpdater ?? PubUpdater();

final Logger _logger;
final PubUpdater _pubUpdater;

@override
String get description => 'Update Very Good CLI.';

@override
String get name => 'update';

@override
Future<int> run() async {
final updateCheckProgress = _logger.progress('Checking for updates');
late final String latestVersion;
try {
latestVersion = await _pubUpdater.getLatestVersion(packageName);
} catch (error) {
updateCheckProgress.fail();
_logger.err('$error');
return ExitCode.software.code;
}
updateCheckProgress.complete('Checked for updates');

final isUpToDate = packageVersion == latestVersion;
if (isUpToDate) {
_logger.info('Very Good CLI is already at the latest version.');
return ExitCode.success.code;
}

final updateProgress = _logger.progress('Updating to $latestVersion');
try {
await _pubUpdater.update(packageName: packageName);
} catch (error) {
updateProgress.fail();
_logger.err('$error');
return ExitCode.software.code;
}
updateProgress.complete('Updated to $latestVersion');

return ExitCode.success.code;
}
}
3 changes: 2 additions & 1 deletion test/helpers/command_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ void Function() withRunner(
FutureOr<void> Function(
VeryGoodCommandRunner commandRunner,
Logger logger,
PubUpdater pubUpdater,
List<String> printLogs,
)
runnerFn,
Expand Down Expand Up @@ -69,6 +70,6 @@ void Function() withRunner(
),
).thenAnswer((_) => Future.value(true));

await runnerFn(commandRunner, logger, printLogs);
await runnerFn(commandRunner, logger, pubUpdater, printLogs);
});
}
1 change: 1 addition & 0 deletions test/src/command_runner_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const expectedUsage = [
''' Creates a new very good project in the specified directory.\n'''
' packages Command for managing packages.\n'
' test Run tests in a Dart or Flutter project.\n'
' update Update Very Good CLI.\n'
'\n'
'Run "very_good help <command>" for more information about a command.'
];
Expand Down
24 changes: 12 additions & 12 deletions test/src/commands/create/create_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ void main() {

test(
'help',
withRunner((commandRunner, logger, printLogs) async {
withRunner((commandRunner, logger, pubUpdater, printLogs) async {
final result = await commandRunner.run(['create', '--help']);
expect(printLogs, equals(expectedUsage));
expect(result, equals(ExitCode.success.code));
Expand All @@ -136,7 +136,7 @@ void main() {
test(
'throws UsageException when --project-name is missing '
'and directory base is not a valid package name',
withRunner((commandRunner, logger, printLogs) async {
withRunner((commandRunner, logger, pubUpdater, printLogs) async {
const expectedErrorMessage = '".tmp" is not a valid package name.\n\n'
'See https://dart.dev/tools/pub/pubspec#name for more information.';
final result = await commandRunner.run(['create', '.tmp']);
Expand All @@ -147,7 +147,7 @@ void main() {

test(
'throws UsageException when --project-name is invalid',
withRunner((commandRunner, logger, printLogs) async {
withRunner((commandRunner, logger, pubUpdater, printLogs) async {
const expectedErrorMessage = '"My App" is not a valid package name.\n\n'
'See https://dart.dev/tools/pub/pubspec#name for more information.';
final result = await commandRunner.run(
Expand All @@ -160,7 +160,7 @@ void main() {

test(
'throws UsageException when output directory is missing',
withRunner((commandRunner, logger, printLogs) async {
withRunner((commandRunner, logger, pubUpdater, printLogs) async {
const expectedErrorMessage =
'No option specified for the output directory.';
final result = await commandRunner.run(['create']);
Expand All @@ -171,7 +171,7 @@ void main() {

test(
'throws UsageException when multiple output directories are provided',
withRunner((commandRunner, logger, printLogs) async {
withRunner((commandRunner, logger, pubUpdater, printLogs) async {
const expectedErrorMessage = 'Multiple output directories specified.';
final result = await commandRunner.run(['create', './a', './b']);
expect(result, equals(ExitCode.usage.code));
Expand Down Expand Up @@ -322,7 +322,7 @@ void main() {
test(
'is a valid alias',
withRunner(
(commandRunner, logger, printLogs) async {
(commandRunner, logger, pubUpdater, printLogs) async {
const orgName = 'com.my.org';
final tempDir = Directory.systemTemp.createTempSync();
final result = await commandRunner.run(
Expand All @@ -347,7 +347,7 @@ void main() {

test(
'no delimiters',
withRunner((commandRunner, logger, printLogs) async {
withRunner((commandRunner, logger, pubUpdater, printLogs) async {
const orgName = 'My App';
final result = await commandRunner.run(
['create', '.', '--org-name', orgName],
Expand All @@ -359,7 +359,7 @@ void main() {

test(
'less than 2 domains',
withRunner((commandRunner, logger, printLogs) async {
withRunner((commandRunner, logger, pubUpdater, printLogs) async {
const orgName = 'verybadtest';
final result = await commandRunner.run(
['create', '.', '--org-name', orgName],
Expand All @@ -371,7 +371,7 @@ void main() {

test(
'invalid characters present',
withRunner((commandRunner, logger, printLogs) async {
withRunner((commandRunner, logger, pubUpdater, printLogs) async {
const orgName = 'very%.bad@.#test';
final result = await commandRunner.run(
['create', '.', '--org-name', orgName],
Expand All @@ -383,7 +383,7 @@ void main() {

test(
'segment starts with a non-letter',
withRunner((commandRunner, logger, printLogs) async {
withRunner((commandRunner, logger, pubUpdater, printLogs) async {
const orgName = 'very.bad.1test';
final result = await commandRunner.run(
['create', '.', '--org-name', orgName],
Expand All @@ -395,7 +395,7 @@ void main() {

test(
'valid prefix but invalid suffix',
withRunner((commandRunner, logger, printLogs) async {
withRunner((commandRunner, logger, pubUpdater, printLogs) async {
const orgName = 'very.good.prefix.bad@@suffix';
final result = await commandRunner.run(
['create', '.', '--org-name', orgName],
Expand Down Expand Up @@ -498,7 +498,7 @@ void main() {
group('invalid template name', () {
test(
'invalid template name',
withRunner((commandRunner, logger, printLogs) async {
withRunner((commandRunner, logger, pubUpdater, printLogs) async {
const templateName = 'badtemplate';
const expectedErrorMessage =
'''"$templateName" is not an allowed value for option "template".''';
Expand Down
20 changes: 10 additions & 10 deletions test/src/commands/packages_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ void main() {
group('packages', () {
test(
'help',
withRunner((commandRunner, logger, printLogs) async {
withRunner((commandRunner, logger, pubUpdater, printLogs) async {
final result = await commandRunner.run(['packages', '--help']);
expect(printLogs, equals(expectedPackagesUsage));
expect(result, equals(ExitCode.success.code));
Expand All @@ -58,7 +58,7 @@ void main() {
group('get', () {
test(
'help',
withRunner((commandRunner, logger, printLogs) async {
withRunner((commandRunner, logger, pubUpdater, printLogs) async {
final result = await commandRunner.run(['packages', 'get', '--help']);
expect(printLogs, equals(expectedPackagesGetUsage));
expect(result, equals(ExitCode.success.code));
Expand All @@ -74,7 +74,7 @@ void main() {
test(
'throws usage exception '
'when too many arguments are provided',
withRunner((commandRunner, logger, printLogs) async {
withRunner((commandRunner, logger, pubUpdater, printLogs) async {
final result = await commandRunner.run(
['packages', 'get', 'arg1', 'arg2'],
);
Expand All @@ -85,7 +85,7 @@ void main() {
test(
'throws pubspec not found exception '
'when no pubspec.yaml exists',
withRunner((commandRunner, logger, printLogs) async {
withRunner((commandRunner, logger, pubUpdater, printLogs) async {
final result = await commandRunner.run(['packages', 'get', 'test']);
expect(result, equals(ExitCode.noInput.code));
verify(() {
Expand All @@ -97,7 +97,7 @@ void main() {
test(
'throws pubspec not found exception '
'when no pubspec.yaml exists (recursive)',
withRunner((commandRunner, logger, printLogs) async {
withRunner((commandRunner, logger, pubUpdater, printLogs) async {
final result = await commandRunner.run(
['packages', 'get', '-r', 'test'],
);
Expand All @@ -110,7 +110,7 @@ void main() {

test(
'throws when installation fails',
withRunner((commandRunner, logger, printLogs) async {
withRunner((commandRunner, logger, pubUpdater, printLogs) async {
final directory = Directory.systemTemp.createTempSync();
File(path.join(directory.path, 'pubspec.yaml')).writeAsStringSync('');
final result = await commandRunner.run(
Expand All @@ -122,7 +122,7 @@ void main() {

test(
'ignores .fvm directory',
withRunner((commandRunner, logger, printLogs) async {
withRunner((commandRunner, logger, pubUpdater, printLogs) async {
final tempDirectory = Directory.systemTemp.createTempSync();
final directory = Directory(path.join(tempDirectory.path, '.fvm'))
..createSync();
Expand All @@ -148,7 +148,7 @@ void main() {
test(
'completes normally '
'when pubspec.yaml exists',
withRunner((commandRunner, logger, printLogs) async {
withRunner((commandRunner, logger, pubUpdater, printLogs) async {
final directory = Directory.systemTemp.createTempSync();
File(path.join(directory.path, 'pubspec.yaml')).writeAsStringSync(
'''
Expand All @@ -174,7 +174,7 @@ void main() {
test(
'completes normally '
'when pubspec.yaml exists (recursive)',
withRunner((commandRunner, logger, printLogs) async {
withRunner((commandRunner, logger, pubUpdater, printLogs) async {
final directory = Directory.systemTemp.createTempSync();
final pubspecA = File(
path.join(directory.path, 'example_a', 'pubspec.yaml'),
Expand Down Expand Up @@ -220,7 +220,7 @@ void main() {
test(
'completes normally '
'when pubspec.yaml exists and directory is not ignored (recursive)',
withRunner((commandRunner, logger, printLogs) async {
withRunner((commandRunner, logger, pubUpdater, printLogs) async {
final tempDirectory = Directory.systemTemp.createTempSync();
final directory = Directory(
path.join(tempDirectory.path, 'macos_plugin'),
Expand Down
6 changes: 3 additions & 3 deletions test/src/commands/test/test_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ void main() {

test(
'help',
withRunner((commandRunner, logger, printLogs) async {
withRunner((commandRunner, logger, pubUpdater, printLogs) async {
final result = await commandRunner.run(['test', '--help']);
expect(printLogs, equals(expectedTestUsage));
expect(result, equals(ExitCode.success.code));
Expand All @@ -118,7 +118,7 @@ void main() {
test(
'throws pubspec not found exception '
'when no pubspec.yaml exists',
withRunner((commandRunner, logger, printLogs) async {
withRunner((commandRunner, logger, pubUpdater, printLogs) async {
final directory = Directory.systemTemp.createTempSync();
Directory.current = directory.path;
final result = await commandRunner.run(['test']);
Expand All @@ -132,7 +132,7 @@ void main() {
test(
'throws pubspec not found exception '
'when no pubspec.yaml exists (recursive)',
withRunner((commandRunner, logger, printLogs) async {
withRunner((commandRunner, logger, pubUpdater, printLogs) async {
final directory = Directory.systemTemp.createTempSync();
Directory.current = directory.path;
final result = await commandRunner.run(['test', '-r']);
Expand Down
Loading

0 comments on commit afce55c

Please sign in to comment.