Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion packages/flutterfire_cli/bin/flutterfire.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import 'package:flutterfire_cli/version.g.dart';
import 'package:pub_updater/pub_updater.dart';

Future<void> main(List<String> arguments) async {
if (arguments.contains('--version') || arguments.contains('-v')) {
if (isCliVersionRequest(arguments)) {
print(cliVersion);
// No version checks on CIs.
if (utils.isCI) return;
Expand Down Expand Up @@ -74,3 +74,11 @@ Future<void> main(List<String> arguments) async {
rethrow;
}
}

/// Whether the arguments request the FlutterFire CLI version.
///
/// Only a standalone version flag belongs to the CLI. Subcommands may define
/// their own version option, such as the BoM version accepted by `install`.
bool isCliVersionRequest(List<String> arguments) =>
arguments.length == 1 &&
(arguments.single == '--version' || arguments.single == '-v');
44 changes: 31 additions & 13 deletions packages/flutterfire_cli/lib/src/commands/install.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import 'dart:convert';
import 'dart:io';

import 'package:ansi_styles/ansi_styles.dart';
import 'package:args/args.dart';
import 'package:collection/collection.dart';

import '../common/utils.dart';
Expand Down Expand Up @@ -85,6 +86,28 @@ enum FlutterFirePlugins {
FlutterFirePlugins.values.map((plugin) => plugin.name).toList();
}

/// Maps prompt selection indexes to the exact plugin list shown to the user.
///
/// The prompt excludes plugins that are unavailable in the selected BoM, so
/// its indexes must not be applied to the unfiltered [FlutterFirePlugins]
/// values.
List<FlutterFirePlugins> pluginsFromSelectionIndexes(
List<FlutterFirePlugins> availablePlugins,
List<int> selectedIndexes,
) => selectedIndexes.map((index) => availablePlugins[index]).toList();

/// Returns the BoM version supplied as a positional argument or option.
///
/// [ArgResults.rest] contains only positional arguments, unlike
/// [ArgResults.arguments], which also contains command options.
String? bomVersionFromArguments(ArgResults arguments) {
if (arguments.rest.length == 1) {
return arguments.rest.single;
}

return arguments['version'] as String?;
}

class InstallCommand extends FlutterFireCommand {
InstallCommand(FlutterApp? flutterApp) : super(flutterApp) {
setupDefaultFirebaseCliOptions();
Expand Down Expand Up @@ -138,12 +161,15 @@ class InstallCommand extends FlutterFireCommand {
return selectedPlugins;
}

final selectedPlugins = <FlutterFirePlugins>[];
final listAvailablePluginsInVersion = availablePlugins.keys.toList();
final choices = FlutterFirePlugins.values
// Keep the filtered enum values as well as their labels so prompt indexes
// can be resolved against the same list the user sees.
final availablePluginChoices = FlutterFirePlugins.values
.where(
(element) => listAvailablePluginsInVersion.contains(element.name),
)
.toList();
final choices = availablePluginChoices
.map((plugin) => plugin.displayName)
.toList();
final defaultSelection = List<bool>.filled(choices.length, false);
Expand All @@ -164,10 +190,7 @@ class InstallCommand extends FlutterFireCommand {
choices,
defaultSelection: defaultSelection,
);
for (final index in selectedChoices) {
selectedPlugins.add(FlutterFirePlugins.values[index]);
}
return selectedPlugins;
return pluginsFromSelectionIndexes(availablePluginChoices, selectedChoices);
}

Future<Map<String, String>> _getPluginVersionsFromJSON(
Expand Down Expand Up @@ -204,13 +227,8 @@ class InstallCommand extends FlutterFireCommand {
@override
Future<void> run() async {
// Get the BoM version number from the arguments
late String bomVersion;

if (argResults?.arguments.length == 1) {
bomVersion = argResults!.arguments[0];
} else if (argResults?['version'] != null) {
bomVersion = argResults!['version'] as String;
} else {
final bomVersion = bomVersionFromArguments(argResults!);
if (bomVersion == null) {
stderr.writeln(
'Usage for install command: flutterfire install <version>',
);
Expand Down
52 changes: 52 additions & 0 deletions packages/flutterfire_cli/test/install_unit_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import 'package:args/args.dart';
import 'package:flutterfire_cli/src/commands/install.dart';
import 'package:test/test.dart';

import '../bin/flutterfire.dart';

void main() {
group('install plugin selection', () {
test('maps prompt indexes against the available plugins', () {
final availablePlugins = [
for (final plugin in FlutterFirePlugins.values)
if (plugin != FlutterFirePlugins.dynamicLinks) plugin,
];

expect(pluginsFromSelectionIndexes(availablePlugins, [9, 10, 13]), [
FlutterFirePlugins.inAppMessaging,
FlutterFirePlugins.messaging,
FlutterFirePlugins.remoteConfig,
]);
});
});

group('install version arguments', () {
final parser = ArgParser()
..addOption('version')
..addFlag('only-pubspec-plugins', negatable: false);

test('accepts a positional version with options', () {
final results = parser.parse(['4.17.1', '--only-pubspec-plugins']);

expect(bomVersionFromArguments(results), '4.17.1');
});

test('accepts the command version option', () {
final results = parser.parse(['--version', '4.17.1']);

expect(bomVersionFromArguments(results), '4.17.1');
});

test(
'only treats a standalone global version flag as a CLI version request',
() {
expect(isCliVersionRequest(['--version']), isTrue);
expect(isCliVersionRequest(['-v']), isTrue);
expect(
isCliVersionRequest(['install', '--version', '4.17.1']),
isFalse,
);
},
);
});
}
Loading