Unverified Commit 861fe0a2 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

Ensure precache --web works on dev branch (#42289)

parent 3ff51c74
...@@ -16,21 +16,25 @@ import 'base/net.dart'; ...@@ -16,21 +16,25 @@ import 'base/net.dart';
import 'base/os.dart'; import 'base/os.dart';
import 'base/platform.dart'; import 'base/platform.dart';
import 'base/process.dart'; import 'base/process.dart';
import 'features.dart';
import 'globals.dart'; import 'globals.dart';
/// A tag for a set of development artifacts that need to be cached. /// A tag for a set of development artifacts that need to be cached.
class DevelopmentArtifact { class DevelopmentArtifact {
const DevelopmentArtifact._(this.name, {this.unstable = false}); const DevelopmentArtifact._(this.name, {this.unstable = false, this.feature});
/// The name of the artifact. /// The name of the artifact.
/// ///
/// This should match the flag name in precache.dart /// This should match the flag name in precache.dart
final String name; final String name;
/// Whether this artifact should be unavailable on stable branches. /// Whether this artifact should be unavailable on master branch only.
final bool unstable; final bool unstable;
/// A feature to control the visibility of this artifact.
final Feature feature;
/// Artifacts required for Android development. /// Artifacts required for Android development.
static const DevelopmentArtifact androidGenSnapshot = DevelopmentArtifact._('android_gen_snapshot'); static const DevelopmentArtifact androidGenSnapshot = DevelopmentArtifact._('android_gen_snapshot');
static const DevelopmentArtifact androidMaven = DevelopmentArtifact._('android_maven'); static const DevelopmentArtifact androidMaven = DevelopmentArtifact._('android_maven');
...@@ -41,7 +45,7 @@ class DevelopmentArtifact { ...@@ -41,7 +45,7 @@ class DevelopmentArtifact {
static const DevelopmentArtifact iOS = DevelopmentArtifact._('ios'); static const DevelopmentArtifact iOS = DevelopmentArtifact._('ios');
/// Artifacts required for web development. /// Artifacts required for web development.
static const DevelopmentArtifact web = DevelopmentArtifact._('web', unstable: true); static const DevelopmentArtifact web = DevelopmentArtifact._('web', feature: flutterWebFeature);
/// Artifacts required for desktop macOS. /// Artifacts required for desktop macOS.
static const DevelopmentArtifact macOS = DevelopmentArtifact._('macos', unstable: true); static const DevelopmentArtifact macOS = DevelopmentArtifact._('macos', unstable: true);
...@@ -75,6 +79,9 @@ class DevelopmentArtifact { ...@@ -75,6 +79,9 @@ class DevelopmentArtifact {
universal, universal,
flutterRunner, flutterRunner,
]; ];
@override
String toString() => 'Artifact($name, $unstable)';
} }
/// A wrapper around the `bin/cache/` directory. /// A wrapper around the `bin/cache/` directory.
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'dart:async'; import 'dart:async';
import '../cache.dart'; import '../cache.dart';
import '../features.dart';
import '../globals.dart'; import '../globals.dart';
import '../runner/flutter_command.dart'; import '../runner/flutter_command.dart';
import '../version.dart'; import '../version.dart';
...@@ -65,6 +66,9 @@ class PrecacheCommand extends FlutterCommand { ...@@ -65,6 +66,9 @@ class PrecacheCommand extends FlutterCommand {
if (!FlutterVersion.instance.isMaster && artifact.unstable) { if (!FlutterVersion.instance.isMaster && artifact.unstable) {
continue; continue;
} }
if (artifact.feature != null && !featureFlags.isEnabled(artifact.feature)) {
continue;
}
if (argResults[artifact.name]) { if (argResults[artifact.name]) {
requiredArtifacts.add(artifact); requiredArtifacts.add(artifact);
} }
......
...@@ -17,7 +17,7 @@ FeatureFlags get featureFlags => context.get<FeatureFlags>(); ...@@ -17,7 +17,7 @@ FeatureFlags get featureFlags => context.get<FeatureFlags>();
/// The interface used to determine if a particular [Feature] is enabled. /// The interface used to determine if a particular [Feature] is enabled.
/// ///
/// The rest of the tools code should use this class instead of looking up /// The rest of the tools code should use this class instead of looking up
/// features directly. To faciliate rolls to google3 and other clients, all /// features directly. To facilitate rolls to google3 and other clients, all
/// flags should be provided with a default implementation here. Clients that /// flags should be provided with a default implementation here. Clients that
/// use this class should extent instead of implement, so that new flags are /// use this class should extent instead of implement, so that new flags are
/// picked up automatically. /// picked up automatically.
...@@ -25,22 +25,24 @@ class FeatureFlags { ...@@ -25,22 +25,24 @@ class FeatureFlags {
const FeatureFlags(); const FeatureFlags();
/// Whether flutter desktop for linux is enabled. /// Whether flutter desktop for linux is enabled.
bool get isLinuxEnabled => _isEnabled(flutterLinuxDesktopFeature); bool get isLinuxEnabled => isEnabled(flutterLinuxDesktopFeature);
/// Whether flutter desktop for macOS is enabled. /// Whether flutter desktop for macOS is enabled.
bool get isMacOSEnabled => _isEnabled(flutterMacOSDesktopFeature); bool get isMacOSEnabled => isEnabled(flutterMacOSDesktopFeature);
/// Whether flutter web is enabled. /// Whether flutter web is enabled.
bool get isWebEnabled => _isEnabled(flutterWebFeature); bool get isWebEnabled => isEnabled(flutterWebFeature);
/// Whether flutter desktop for Windows is enabled. /// Whether flutter desktop for Windows is enabled.
bool get isWindowsEnabled => _isEnabled(flutterWindowsDesktopFeature); bool get isWindowsEnabled => isEnabled(flutterWindowsDesktopFeature);
/// Whether the new Android embedding is enabled. /// Whether the new Android embedding is enabled.
bool get isNewAndroidEmbeddingEnabled => _isEnabled(flutterNewAndroidEmbeddingFeature); bool get isNewAndroidEmbeddingEnabled => isEnabled(flutterNewAndroidEmbeddingFeature);
// Calculate whether a particular feature is enabled for the current channel. /// Whether a particular feature is enabled for the current channel.
static bool _isEnabled(Feature feature) { ///
/// Prefer using one of the specific getters above instead of this API.
bool isEnabled(Feature feature) {
final String currentChannel = FlutterVersion.instance.channel; final String currentChannel = FlutterVersion.instance.channel;
final FeatureChannelSetting featureSetting = feature.getSettingForChannel(currentChannel); final FeatureChannelSetting featureSetting = feature.getSettingForChannel(currentChannel);
if (!featureSetting.available) { if (!featureSetting.available) {
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/precache.dart'; import 'package:flutter_tools/src/commands/precache.dart';
import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart'; import 'package:flutter_tools/src/runner/flutter_command.dart';
import 'package:flutter_tools/src/version.dart'; import 'package:flutter_tools/src/version.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
...@@ -11,151 +12,183 @@ import 'package:mockito/mockito.dart'; ...@@ -11,151 +12,183 @@ import 'package:mockito/mockito.dart';
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/context.dart'; import '../../src/context.dart';
import '../../src/mocks.dart'; import '../../src/mocks.dart';
import '../../src/testbed.dart';
void main() { void main() {
group('precache', () { MockCache cache;
final MockCache cache = MockCache(); Set<DevelopmentArtifact> artifacts;
Set<DevelopmentArtifact> artifacts; MockFlutterVersion flutterVersion;
MockFlutterVersion masterFlutterVersion;
setUp(() {
cache = MockCache();
// Release lock between test cases.
Cache.releaseLockEarly();
when(cache.isUpToDate()).thenReturn(false); when(cache.isUpToDate()).thenReturn(false);
when(cache.updateAll(any)).thenAnswer((Invocation invocation) { when(cache.updateAll(any)).thenAnswer((Invocation invocation) {
artifacts = invocation.positionalArguments.first; artifacts = invocation.positionalArguments.first;
return Future<void>.value(null); return Future<void>.value(null);
}); });
flutterVersion = MockFlutterVersion();
when(flutterVersion.isMaster).thenReturn(false);
masterFlutterVersion = MockFlutterVersion();
when(masterFlutterVersion.isMaster).thenReturn(true);
});
testUsingContext('Adds artifact flags to requested artifacts', () async { testUsingContext('precache downloads web artifacts on dev branch when feature is enabled.', () async {
final PrecacheCommand command = PrecacheCommand(); final PrecacheCommand command = PrecacheCommand();
applyMocksToCommand(command); applyMocksToCommand(command);
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(const <String>['precache', '--web', '--no-android', '--no-ios']);
const <String>[
'precache',
'--ios',
'--android',
'--web',
'--macos',
'--linux',
'--windows',
'--fuchsia',
'--flutter_runner',
],
);
expect(artifacts, unorderedEquals(<DevelopmentArtifact>{
DevelopmentArtifact.universal,
DevelopmentArtifact.iOS,
DevelopmentArtifact.androidGenSnapshot,
DevelopmentArtifact.androidMaven,
DevelopmentArtifact.androidInternalBuild,
DevelopmentArtifact.web,
DevelopmentArtifact.macOS,
DevelopmentArtifact.linux,
DevelopmentArtifact.windows,
DevelopmentArtifact.fuchsia,
DevelopmentArtifact.flutterRunner,
}));
}, overrides: <Type, Generator>{
Cache: () => cache,
});
testUsingContext('Expands android artifacts when the android flag is used', () async { expect(artifacts, unorderedEquals(<DevelopmentArtifact>{
// Release lock between test cases. DevelopmentArtifact.universal,
Cache.releaseLockEarly(); DevelopmentArtifact.web,
DevelopmentArtifact.androidGenSnapshot,
DevelopmentArtifact.androidMaven,
}));
}, overrides: <Type, Generator>{
Cache: () => cache,
FeatureFlags: () => TestFeatureFlags(isWebEnabled: true),
});
final PrecacheCommand command = PrecacheCommand(); testUsingContext('precache does not download web artifacts on dev branch when feature is enabled.', () async {
applyMocksToCommand(command); final PrecacheCommand command = PrecacheCommand();
await createTestCommandRunner(command).run( applyMocksToCommand(command);
const <String>[ await createTestCommandRunner(command).run(const <String>['precache', '--web', '--no-android', '--no-ios']);
'precache',
'--no-ios',
'--android',
],
);
expect(artifacts, unorderedEquals(<DevelopmentArtifact>{
DevelopmentArtifact.universal,
DevelopmentArtifact.androidGenSnapshot,
DevelopmentArtifact.androidMaven,
DevelopmentArtifact.androidInternalBuild,
}));
}, overrides: <Type, Generator>{
Cache: () => cache,
});
testUsingContext('Adds artifact flags to requested android artifacts', () async { expect(artifacts, unorderedEquals(<DevelopmentArtifact>{
// Release lock between test cases. DevelopmentArtifact.universal,
Cache.releaseLockEarly(); DevelopmentArtifact.androidGenSnapshot,
DevelopmentArtifact.androidMaven,
}));
}, overrides: <Type, Generator>{
Cache: () => cache,
FeatureFlags: () => TestFeatureFlags(isWebEnabled: false),
});
final PrecacheCommand command = PrecacheCommand(); testUsingContext('precache adds artifact flags to requested artifacts', () async {
applyMocksToCommand(command); final PrecacheCommand command = PrecacheCommand();
await createTestCommandRunner(command).run( applyMocksToCommand(command);
const <String>[ await createTestCommandRunner(command).run(
'precache', const <String>[
'--no-ios', 'precache',
'--android_gen_snapshot', '--ios',
'--android_maven', '--android',
'--android_internal_build', '--web',
], '--macos',
); '--linux',
expect(artifacts, unorderedEquals(<DevelopmentArtifact>{ '--windows',
DevelopmentArtifact.universal, '--fuchsia',
DevelopmentArtifact.androidGenSnapshot, '--flutter_runner',
DevelopmentArtifact.androidMaven, ],
DevelopmentArtifact.androidInternalBuild, );
})); expect(artifacts, unorderedEquals(<DevelopmentArtifact>{
}, overrides: <Type, Generator>{ DevelopmentArtifact.universal,
Cache: () => cache, DevelopmentArtifact.iOS,
}); DevelopmentArtifact.androidGenSnapshot,
DevelopmentArtifact.androidMaven,
DevelopmentArtifact.androidInternalBuild,
DevelopmentArtifact.web,
DevelopmentArtifact.macOS,
DevelopmentArtifact.linux,
DevelopmentArtifact.windows,
DevelopmentArtifact.fuchsia,
DevelopmentArtifact.flutterRunner,
}));
}, overrides: <Type, Generator>{
Cache: () => cache,
FeatureFlags: () => TestFeatureFlags(isWebEnabled: true),
FlutterVersion: () => masterFlutterVersion,
});
final MockFlutterVersion flutterVersion = MockFlutterVersion(); testUsingContext('precache expands android artifacts when the android flag is used', () async {
when(flutterVersion.isMaster).thenReturn(false); final PrecacheCommand command = PrecacheCommand();
applyMocksToCommand(command);
await createTestCommandRunner(command).run(
const <String>[
'precache',
'--no-ios',
'--android',
],
);
expect(artifacts, unorderedEquals(<DevelopmentArtifact>{
DevelopmentArtifact.universal,
DevelopmentArtifact.androidGenSnapshot,
DevelopmentArtifact.androidMaven,
DevelopmentArtifact.androidInternalBuild,
}));
}, overrides: <Type, Generator>{
Cache: () => cache,
});
testUsingContext('Adds artifact flags to requested artifacts on stable', () async { testUsingContext('precache adds artifact flags to requested android artifacts', () async {
// Release lock between test cases. final PrecacheCommand command = PrecacheCommand();
Cache.releaseLockEarly(); applyMocksToCommand(command);
final PrecacheCommand command = PrecacheCommand(); await createTestCommandRunner(command).run(
applyMocksToCommand(command); const <String>[
await createTestCommandRunner(command).run( 'precache',
const <String>[ '--no-ios',
'precache', '--android_gen_snapshot',
'--ios', '--android_maven',
'--android_gen_snapshot', '--android_internal_build',
'--android_maven', ],
'--android_internal_build', );
'--web', expect(artifacts, unorderedEquals(<DevelopmentArtifact>{
'--macos', DevelopmentArtifact.universal,
'--linux', DevelopmentArtifact.androidGenSnapshot,
'--windows', DevelopmentArtifact.androidMaven,
'--fuchsia', DevelopmentArtifact.androidInternalBuild,
'--flutter_runner', }));
], }, overrides: <Type, Generator>{
); Cache: () => cache,
expect(artifacts, unorderedEquals(<DevelopmentArtifact>{ });
DevelopmentArtifact.universal,
DevelopmentArtifact.iOS, testUsingContext('precache adds artifact flags to requested artifacts on stable', () async {
DevelopmentArtifact.androidGenSnapshot, final PrecacheCommand command = PrecacheCommand();
DevelopmentArtifact.androidMaven, applyMocksToCommand(command);
DevelopmentArtifact.androidInternalBuild, await createTestCommandRunner(command).run(
})); const <String>[
}, overrides: <Type, Generator>{ 'precache',
Cache: () => cache, '--ios',
FlutterVersion: () => flutterVersion, '--android_gen_snapshot',
}); '--android_maven',
testUsingContext('Downloads artifacts when --force is provided', () async { '--android_internal_build',
when(cache.isUpToDate()).thenReturn(true); '--web',
// Release lock between test cases. '--macos',
Cache.releaseLockEarly(); '--linux',
final PrecacheCommand command = PrecacheCommand(); '--windows',
applyMocksToCommand(command); '--fuchsia',
await createTestCommandRunner(command).run(const <String>['precache', '--force']); '--flutter_runner',
expect(artifacts, unorderedEquals(<DevelopmentArtifact>{ ],
DevelopmentArtifact.universal, );
DevelopmentArtifact.iOS, expect(artifacts, unorderedEquals(<DevelopmentArtifact>{
DevelopmentArtifact.androidGenSnapshot, DevelopmentArtifact.universal,
DevelopmentArtifact.androidMaven, DevelopmentArtifact.iOS,
DevelopmentArtifact.androidInternalBuild, DevelopmentArtifact.androidGenSnapshot,
})); DevelopmentArtifact.androidMaven,
}, overrides: <Type, Generator>{ DevelopmentArtifact.androidInternalBuild,
Cache: () => cache, }));
FlutterVersion: () => flutterVersion, }, overrides: <Type, Generator>{
}); Cache: () => cache,
FlutterVersion: () => flutterVersion,
FeatureFlags: () => TestFeatureFlags(isWebEnabled: false),
});
testUsingContext('precache downloads artifacts when --force is provided', () async {
when(cache.isUpToDate()).thenReturn(true);
final PrecacheCommand command = PrecacheCommand();
applyMocksToCommand(command);
await createTestCommandRunner(command).run(const <String>['precache', '--force']);
expect(artifacts, unorderedEquals(<DevelopmentArtifact>{
DevelopmentArtifact.universal,
DevelopmentArtifact.iOS,
DevelopmentArtifact.androidGenSnapshot,
DevelopmentArtifact.androidMaven,
DevelopmentArtifact.androidInternalBuild,
}));
}, overrides: <Type, Generator>{
Cache: () => cache,
FlutterVersion: () => flutterVersion,
}); });
} }
......
...@@ -209,7 +209,7 @@ void main() { ...@@ -209,7 +209,7 @@ void main() {
}); });
test('Unstable artifacts', () { test('Unstable artifacts', () {
expect(DevelopmentArtifact.web.unstable, true); expect(DevelopmentArtifact.web.unstable, false);
expect(DevelopmentArtifact.linux.unstable, true); expect(DevelopmentArtifact.linux.unstable, true);
expect(DevelopmentArtifact.macOS.unstable, true); expect(DevelopmentArtifact.macOS.unstable, true);
expect(DevelopmentArtifact.windows.unstable, true); expect(DevelopmentArtifact.windows.unstable, true);
......
...@@ -712,6 +712,23 @@ class TestFeatureFlags implements FeatureFlags { ...@@ -712,6 +712,23 @@ class TestFeatureFlags implements FeatureFlags {
@override @override
final bool isNewAndroidEmbeddingEnabled; final bool isNewAndroidEmbeddingEnabled;
@override
bool isEnabled(Feature feature) {
switch (feature) {
case flutterWebFeature:
return isWebEnabled;
case flutterLinuxDesktopFeature:
return isLinuxEnabled;
case flutterMacOSDesktopFeature:
return isMacOSEnabled;
case flutterWindowsDesktopFeature:
return isWindowsEnabled;
case flutterNewAndroidEmbeddingFeature:
return isNewAndroidEmbeddingEnabled;
}
return false;
}
} }
class ThrowingPub implements Pub { class ThrowingPub implements Pub {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment