Skip to content

Commit e322218

Browse files
authored
feat: add verify-only flag to update command (#817)
1 parent 0ca916d commit e322218

File tree

2 files changed

+126
-12
lines changed

2 files changed

+126
-12
lines changed

packages/dart_frog_cli/lib/src/commands/update/update.dart

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import 'dart:io';
22

3-
import 'package:args/command_runner.dart';
3+
import 'package:dart_frog_cli/src/command.dart';
44
import 'package:dart_frog_cli/src/command_runner.dart';
55
import 'package:dart_frog_cli/src/version.dart';
66
import 'package:mason/mason.dart' hide packageVersion;
@@ -9,13 +9,19 @@ import 'package:pub_updater/pub_updater.dart';
99
/// {@template update_command}
1010
/// `dart_frog update` command which updates the dart_frog_cli.
1111
/// {@endtemplate}
12-
class UpdateCommand extends Command<int> {
12+
class UpdateCommand extends DartFrogCommand {
1313
/// {@macro update_command}
1414
UpdateCommand({
1515
required Logger logger,
1616
PubUpdater? pubUpdater,
1717
}) : _logger = logger,
18-
_pubUpdater = pubUpdater ?? PubUpdater();
18+
_pubUpdater = pubUpdater ?? PubUpdater() {
19+
argParser.addFlag(
20+
'verify-only',
21+
help: 'Check if an update is available, without committing to update.',
22+
negatable: false,
23+
);
24+
}
1925

2026
final Logger _logger;
2127
final PubUpdater _pubUpdater;
@@ -26,8 +32,13 @@ class UpdateCommand extends Command<int> {
2632
@override
2733
String get name => 'update';
2834

35+
@override
36+
final String invocation = 'dart_frog update';
37+
2938
@override
3039
Future<int> run() async {
40+
final verifyOnly = results['verify-only'] as bool;
41+
3142
final updateCheckProgress = _logger.progress('Checking for updates');
3243
late final String latestVersion;
3344
try {
@@ -43,6 +54,13 @@ class UpdateCommand extends Command<int> {
4354
if (isUpToDate) {
4455
_logger.info('$packageName is already at the latest version.');
4556
return ExitCode.success.code;
57+
} else if (verifyOnly) {
58+
_logger
59+
..info('A new version of $packageName is available.\n')
60+
..info(styleBold.wrap('The latest version: $latestVersion'))
61+
..info('Your current version: $packageVersion\n')
62+
..info('To update now, run "$executableName update".');
63+
return ExitCode.success.code;
4664
}
4765

4866
final updateProgress = _logger.progress('Updating to $latestVersion');

packages/dart_frog_cli/test/src/commands/update/update_test.dart

Lines changed: 105 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
// ignore_for_file: no_adjacent_strings_in_list
2+
13
import 'dart:io';
24

5+
import 'package:args/args.dart';
36
import 'package:dart_frog_cli/src/command_runner.dart';
47
import 'package:dart_frog_cli/src/commands/update/update.dart';
58
import 'package:dart_frog_cli/src/version.dart';
@@ -8,11 +11,28 @@ import 'package:mocktail/mocktail.dart';
811
import 'package:pub_updater/pub_updater.dart';
912
import 'package:test/test.dart';
1013

11-
class MockLogger extends Mock implements Logger {}
14+
import '../../../helpers/helpers.dart';
15+
16+
class _MockLogger extends Mock implements Logger {}
17+
18+
class _MockPubUpdater extends Mock implements PubUpdater {}
19+
20+
class _MockProgress extends Mock implements Progress {}
1221

13-
class MockPubUpdater extends Mock implements PubUpdater {}
22+
class _MockArgResults extends Mock implements ArgResults {}
1423

15-
class MockProgress extends Mock implements Progress {}
24+
class _MockProcessSignal extends Mock implements ProcessSignal {}
25+
26+
const expectedUsage = [
27+
'Update the Dart Frog CLI.\n'
28+
'\n'
29+
'Usage: dart_frog update\n'
30+
'-h, --help Print this usage information.\n'
31+
' --verify-only Check if an update is available, without '
32+
'committing to update.\n'
33+
'\n'
34+
'Run "dart_frog help" to see global options.'
35+
];
1636

1737
void main() {
1838
const latestVersion = '0.0.0';
@@ -24,12 +44,15 @@ void main() {
2444
late Logger logger;
2545
late PubUpdater pubUpdater;
2646
late UpdateCommand command;
47+
late ArgResults argResults;
48+
late DartFrogCommandRunner commandRunner;
2749

2850
setUp(() {
29-
logger = MockLogger();
30-
pubUpdater = MockPubUpdater();
51+
logger = _MockLogger();
52+
pubUpdater = _MockPubUpdater();
53+
argResults = _MockArgResults();
3154

32-
when(() => logger.progress(any())).thenReturn(MockProgress());
55+
when(() => logger.progress(any())).thenReturn(_MockProgress());
3356
when(
3457
() => pubUpdater.getLatestVersion(any()),
3558
).thenAnswer((_) async => packageVersion);
@@ -40,9 +63,32 @@ void main() {
4063
),
4164
).thenAnswer((_) => Future.value(processResult));
4265

43-
command = UpdateCommand(logger: logger, pubUpdater: pubUpdater);
66+
when(() => argResults['verify-only']).thenReturn(false);
67+
68+
command = UpdateCommand(logger: logger, pubUpdater: pubUpdater)
69+
..testArgResults = argResults;
70+
71+
final sigint = _MockProcessSignal();
72+
when(sigint.watch).thenAnswer((_) => const Stream.empty());
73+
74+
commandRunner = DartFrogCommandRunner(
75+
logger: logger,
76+
pubUpdater: _MockPubUpdater(),
77+
exit: (_) {},
78+
sigint: sigint,
79+
);
4480
});
4581

82+
test(
83+
'usage shows help text',
84+
overridePrint((printLogs) async {
85+
final result = await commandRunner.run(['update', '--help']);
86+
87+
expect(result, equals(ExitCode.success.code));
88+
expect(printLogs, equals(expectedUsage));
89+
}),
90+
);
91+
4692
test('handles pub latest version query errors', () async {
4793
when(
4894
() => pubUpdater.getLatestVersion(any()),
@@ -59,6 +105,56 @@ void main() {
59105
);
60106
});
61107

108+
group('--verify-only', () {
109+
test(
110+
'logs latest available version',
111+
() async {
112+
when(
113+
() => pubUpdater.getLatestVersion(any()),
114+
).thenAnswer((_) async => latestVersion);
115+
when(() => argResults['verify-only']).thenReturn(true);
116+
117+
final result = await command.run();
118+
119+
expect(result, equals(ExitCode.success.code));
120+
verify(
121+
() => logger.info('A new version of $packageName is available.\n'),
122+
).called(1);
123+
verify(
124+
() => logger.info(
125+
styleBold.wrap('The latest version: $latestVersion'),
126+
),
127+
).called(1);
128+
verify(
129+
() => logger.info('Your current version: $packageVersion\n'),
130+
).called(1);
131+
verify(
132+
() => logger.info('To update now, run "$executableName update".'),
133+
).called(1);
134+
},
135+
);
136+
137+
test(
138+
'does not update',
139+
() async {
140+
when(
141+
() => pubUpdater.getLatestVersion(any()),
142+
).thenAnswer((_) async => latestVersion);
143+
when(() => argResults['verify-only']).thenReturn(true);
144+
145+
final result = await command.run();
146+
147+
expect(result, equals(ExitCode.success.code));
148+
verifyNever(
149+
() => pubUpdater.update(
150+
packageName: any(named: 'packageName'),
151+
versionConstraint: any(named: 'versionConstraint'),
152+
),
153+
);
154+
},
155+
);
156+
});
157+
62158
test('handles pub update errors', () async {
63159
when(
64160
() => pubUpdater.getLatestVersion(any()),
@@ -119,7 +215,7 @@ void main() {
119215
),
120216
).thenAnswer((_) => Future.value(processResult));
121217

122-
when(() => logger.progress(any())).thenReturn(MockProgress());
218+
when(() => logger.progress(any())).thenReturn(_MockProgress());
123219
final result = await command.run();
124220
expect(result, equals(ExitCode.success.code));
125221
verify(() => logger.progress('Checking for updates')).called(1);
@@ -136,7 +232,7 @@ void main() {
136232
when(
137233
() => pubUpdater.getLatestVersion(any()),
138234
).thenAnswer((_) async => packageVersion);
139-
when(() => logger.progress(any())).thenReturn(MockProgress());
235+
when(() => logger.progress(any())).thenReturn(_MockProgress());
140236
final result = await command.run();
141237
expect(result, equals(ExitCode.success.code));
142238
verify(

0 commit comments

Comments
 (0)