Allow disabling experimental commands, devices on stable branch (#30153)
diff --git a/packages/flutter_tools/lib/src/commands/build_web.dart b/packages/flutter_tools/lib/src/commands/build_web.dart index 42ce098..0bb0d9b 100644 --- a/packages/flutter_tools/lib/src/commands/build_web.dart +++ b/packages/flutter_tools/lib/src/commands/build_web.dart
@@ -32,6 +32,9 @@ bool get hidden => true; @override + bool get isExperimental => true; + + @override final String description = '(EXPERIMENTAL) build a web application bundle.'; @override
diff --git a/packages/flutter_tools/lib/src/desktop.dart b/packages/flutter_tools/lib/src/desktop.dart index 153e2fb..e1af669 100644 --- a/packages/flutter_tools/lib/src/desktop.dart +++ b/packages/flutter_tools/lib/src/desktop.dart
@@ -3,11 +3,12 @@ // found in the LICENSE file. import 'base/platform.dart'; +import 'version.dart'; // Only launch or display desktop embedding devices if // `FLUTTER_DESKTOP_EMBEDDING` environment variable is set to true. bool get flutterDesktopEnabled { _flutterDesktopEnabled ??= platform.environment['FLUTTER_DESKTOP_EMBEDDING']?.toLowerCase() == 'true'; - return _flutterDesktopEnabled; + return _flutterDesktopEnabled && !FlutterVersion.instance.isStable; } bool _flutterDesktopEnabled;
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart index 4341b1d..dd84802 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart
@@ -27,6 +27,7 @@ import '../globals.dart'; import '../project.dart'; import '../usage.dart'; +import '../version.dart'; import 'flutter_command_runner.dart'; export '../cache.dart' show DevelopmentArtifact; @@ -464,6 +465,11 @@ } } + /// Whether this feature should not be usable on stable branches. + /// + /// Defaults to false, meaning it is usable. + bool get isExperimental => false; + /// Additional usage values to be sent with the usage ping. Future<Map<String, String>> get usageValues async => const <String, String>{}; @@ -635,6 +641,12 @@ @protected @mustCallSuper Future<void> validateCommand() async { + // If we're on a stable branch, then don't allow the usage of + // "experimental" features. + if (isExperimental && FlutterVersion.instance.isStable) { + throwToolExit('Experimental feature $name is not supported on stable branches'); + } + if (_requiresPubspecYaml && !PackageMap.isUsingCustomPackagesPath) { // Don't expect a pubspec.yaml file if the user passed in an explicit .packages file path. if (!fs.isFileSync('pubspec.yaml')) {
diff --git a/packages/flutter_tools/lib/src/version.dart b/packages/flutter_tools/lib/src/version.dart index 3df1df0..d571f37 100644 --- a/packages/flutter_tools/lib/src/version.dart +++ b/packages/flutter_tools/lib/src/version.dart
@@ -32,6 +32,11 @@ return _repositoryUrl; } + /// Whether we are currently on the stable branch. + bool get isStable { + return getBranchName() == 'stable'; + } + static const Set<String> officialChannels = <String>{ 'master', 'dev',
diff --git a/packages/flutter_tools/lib/src/web/web_device.dart b/packages/flutter_tools/lib/src/web/web_device.dart index 4b34393..fd78729 100644 --- a/packages/flutter_tools/lib/src/web/web_device.dart +++ b/packages/flutter_tools/lib/src/web/web_device.dart
@@ -13,6 +13,7 @@ import '../device.dart'; import '../globals.dart'; import '../project.dart'; +import '../version.dart'; import '../web/compile.dart'; ChromeLauncher get chromeLauncher => context[ChromeLauncher]; @@ -21,7 +22,7 @@ /// environment variable is set to true. bool get flutterWebEnabled { _flutterWebEnabled = platform.environment['FLUTTER_WEB']?.toLowerCase() == 'true'; - return _flutterWebEnabled; + return _flutterWebEnabled && !FlutterVersion.instance.isStable; } bool _flutterWebEnabled;
diff --git a/packages/flutter_tools/test/runner/flutter_command_test.dart b/packages/flutter_tools/test/runner/flutter_command_test.dart index e1cfc2a..e91b95b 100644 --- a/packages/flutter_tools/test/runner/flutter_command_test.dart +++ b/packages/flutter_tools/test/runner/flutter_command_test.dart
@@ -7,6 +7,7 @@ import 'package:flutter_tools/src/usage.dart'; import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/runner/flutter_command.dart'; +import 'package:flutter_tools/src/version.dart'; import 'package:mockito/mockito.dart'; import '../src/common.dart'; @@ -155,4 +156,43 @@ }); }); + + group('Experimental commands', () { + final MockVersion stableVersion = MockVersion(); + final MockVersion betaVersion = MockVersion(); + final FakeCommand fakeCommand = FakeCommand(); + when(stableVersion.isStable).thenReturn(true); + when(betaVersion.isStable).thenReturn(false); + + testUsingContext('Can be disabled on stable branch', () async { + expect(() => fakeCommand.run(), throwsA(isA<ToolExit>())); + }, overrides: <Type, Generator>{ + FlutterVersion: () => stableVersion, + }); + + testUsingContext('Works normally on regular branches', () async { + expect(fakeCommand.run(), completes); + }, overrides: <Type, Generator>{ + FlutterVersion: () => betaVersion, + }); + }); } + + +class FakeCommand extends FlutterCommand { + @override + String get description => null; + + @override + String get name => 'fake'; + + @override + bool get isExperimental => true; + + @override + Future<FlutterCommandResult> runCommand() async { + return null; + } +} + +class MockVersion extends Mock implements FlutterVersion {}
diff --git a/packages/flutter_tools/test/src/context.dart b/packages/flutter_tools/test/src/context.dart index d89d322..7203676 100644 --- a/packages/flutter_tools/test/src/context.dart +++ b/packages/flutter_tools/test/src/context.dart
@@ -304,7 +304,10 @@ } } -class MockFlutterVersion extends Mock implements FlutterVersion {} +class MockFlutterVersion extends Mock implements FlutterVersion { + @override + bool get isStable => false; +} class MockClock extends Mock implements SystemClock {}