mirror of
https://github.com/flutter/packages.git
synced 2025-06-21 15:20:15 +08:00

This removes all of the deprecated plugins from the tree, as well as all references to them. They were being left in the tree only in case they needed critical fixes before the end of this year, when they will become completely unsupported and be officially discontinued on pub.dev. The end of the year is now close enough that such a release is extremely unlikely, and they are causing some maintenance burden (e.g., the tree is currently closed on an out-of-band failure in android_alarm_manager). In the event that we do have to push an emergency fix in the next several weeks, we can either temporarily restore the plugin from git history, or use a branch. Minor related cleanup: - Scanning the repository for remaining references turned up that `image_picker_for_web` and `video_player_for_web` had copypasta'd the package name of its example application from one of the deprecated plugins, so this fixes those names. - Fixes `federation-safety-check` handling of top-level files in unfederated plugins that accidentally tripped federated plugin heuristics. - Fixes `federation-safety-check` handling of deleted plugins, as it was crashing, and tests that. - Fixes `make-deps-path-based` handling of deleted plugins, as it was crashing, and tests that.
416 lines
15 KiB
Dart
416 lines
15 KiB
Dart
// Copyright 2013 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'dart:io' as io;
|
|
|
|
import 'package:args/command_runner.dart';
|
|
import 'package:file/file.dart';
|
|
import 'package:file/memory.dart';
|
|
import 'package:flutter_plugin_tools/src/common/core.dart';
|
|
import 'package:flutter_plugin_tools/src/common/repository_package.dart';
|
|
import 'package:flutter_plugin_tools/src/federation_safety_check_command.dart';
|
|
import 'package:mockito/mockito.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
import 'common/plugin_command_test.mocks.dart';
|
|
import 'mocks.dart';
|
|
import 'util.dart';
|
|
|
|
void main() {
|
|
FileSystem fileSystem;
|
|
late MockPlatform mockPlatform;
|
|
late Directory packagesDir;
|
|
late CommandRunner<void> runner;
|
|
late RecordingProcessRunner processRunner;
|
|
|
|
setUp(() {
|
|
fileSystem = MemoryFileSystem();
|
|
mockPlatform = MockPlatform();
|
|
packagesDir = createPackagesDirectory(fileSystem: fileSystem);
|
|
|
|
final MockGitDir gitDir = MockGitDir();
|
|
when(gitDir.path).thenReturn(packagesDir.parent.path);
|
|
when(gitDir.runCommand(any, throwOnError: anyNamed('throwOnError')))
|
|
.thenAnswer((Invocation invocation) {
|
|
final List<String> arguments =
|
|
invocation.positionalArguments[0]! as List<String>;
|
|
// Route git calls through the process runner, to make mock output
|
|
// consistent with other processes. Attach the first argument to the
|
|
// command to make targeting the mock results easier.
|
|
final String gitCommand = arguments.removeAt(0);
|
|
return processRunner.run('git-$gitCommand', arguments);
|
|
});
|
|
|
|
processRunner = RecordingProcessRunner();
|
|
final FederationSafetyCheckCommand command = FederationSafetyCheckCommand(
|
|
packagesDir,
|
|
processRunner: processRunner,
|
|
platform: mockPlatform,
|
|
gitDir: gitDir);
|
|
|
|
runner = CommandRunner<void>('federation_safety_check_command',
|
|
'Test for $FederationSafetyCheckCommand');
|
|
runner.addCommand(command);
|
|
});
|
|
|
|
test('skips non-plugin packages', () async {
|
|
final Directory package = createFakePackage('foo', packagesDir);
|
|
|
|
final String changedFileOutput = <File>[
|
|
package.childDirectory('lib').childFile('foo.dart'),
|
|
].map((File file) => file.path).join('\n');
|
|
processRunner.mockProcessesForExecutable['git-diff'] = <io.Process>[
|
|
MockProcess(stdout: changedFileOutput),
|
|
];
|
|
|
|
final List<String> output =
|
|
await runCapturingPrint(runner, <String>['federation-safety-check']);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for foo...'),
|
|
contains('Not a plugin'),
|
|
contains('Skipped 1 package(s)'),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('skips unfederated plugins', () async {
|
|
final Directory package = createFakePlugin('foo', packagesDir);
|
|
|
|
final String changedFileOutput = <File>[
|
|
package.childDirectory('lib').childFile('foo.dart'),
|
|
].map((File file) => file.path).join('\n');
|
|
processRunner.mockProcessesForExecutable['git-diff'] = <io.Process>[
|
|
MockProcess(stdout: changedFileOutput),
|
|
];
|
|
|
|
final List<String> output =
|
|
await runCapturingPrint(runner, <String>['federation-safety-check']);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for foo...'),
|
|
contains('Not a federated plugin'),
|
|
contains('Skipped 1 package(s)'),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('skips interface packages', () async {
|
|
final Directory pluginGroupDir = packagesDir.childDirectory('foo');
|
|
final Directory platformInterface =
|
|
createFakePlugin('foo_platform_interface', pluginGroupDir);
|
|
|
|
final String changedFileOutput = <File>[
|
|
platformInterface.childDirectory('lib').childFile('foo.dart'),
|
|
].map((File file) => file.path).join('\n');
|
|
processRunner.mockProcessesForExecutable['git-diff'] = <io.Process>[
|
|
MockProcess(stdout: changedFileOutput),
|
|
];
|
|
|
|
final List<String> output =
|
|
await runCapturingPrint(runner, <String>['federation-safety-check']);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for foo_platform_interface...'),
|
|
contains('Platform interface changes are not validated.'),
|
|
contains('Skipped 1 package(s)'),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('allows changes to just an interface package', () async {
|
|
final Directory pluginGroupDir = packagesDir.childDirectory('foo');
|
|
final Directory platformInterface =
|
|
createFakePlugin('foo_platform_interface', pluginGroupDir);
|
|
createFakePlugin('foo', pluginGroupDir);
|
|
createFakePlugin('foo_ios', pluginGroupDir);
|
|
createFakePlugin('foo_android', pluginGroupDir);
|
|
|
|
final String changedFileOutput = <File>[
|
|
platformInterface.childDirectory('lib').childFile('foo.dart'),
|
|
platformInterface.childFile('pubspec.yaml'),
|
|
].map((File file) => file.path).join('\n');
|
|
processRunner.mockProcessesForExecutable['git-diff'] = <io.Process>[
|
|
MockProcess(stdout: changedFileOutput),
|
|
];
|
|
|
|
final List<String> output =
|
|
await runCapturingPrint(runner, <String>['federation-safety-check']);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for foo/foo...'),
|
|
contains('No Dart changes.'),
|
|
contains('Running for foo_android...'),
|
|
contains('No Dart changes.'),
|
|
contains('Running for foo_ios...'),
|
|
contains('No Dart changes.'),
|
|
contains('Running for foo_platform_interface...'),
|
|
contains('Ran for 3 package(s)'),
|
|
contains('Skipped 1 package(s)'),
|
|
]),
|
|
);
|
|
expect(
|
|
output,
|
|
isNot(contains(<Matcher>[
|
|
contains('No published changes for foo_platform_interface'),
|
|
])),
|
|
);
|
|
});
|
|
|
|
test('allows changes to multiple non-interface packages', () async {
|
|
final Directory pluginGroupDir = packagesDir.childDirectory('foo');
|
|
final Directory appFacing = createFakePlugin('foo', pluginGroupDir);
|
|
final Directory implementation =
|
|
createFakePlugin('foo_bar', pluginGroupDir);
|
|
createFakePlugin('foo_platform_interface', pluginGroupDir);
|
|
|
|
final String changedFileOutput = <File>[
|
|
appFacing.childFile('foo.dart'),
|
|
implementation.childFile('foo.dart'),
|
|
].map((File file) => file.path).join('\n');
|
|
processRunner.mockProcessesForExecutable['git-diff'] = <io.Process>[
|
|
MockProcess(stdout: changedFileOutput),
|
|
];
|
|
|
|
final List<String> output =
|
|
await runCapturingPrint(runner, <String>['federation-safety-check']);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for foo/foo...'),
|
|
contains('No published changes for foo_platform_interface.'),
|
|
contains('Running for foo_bar...'),
|
|
contains('No published changes for foo_platform_interface.'),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test(
|
|
'fails on changes to interface and non-interface packages in the same plugin',
|
|
() async {
|
|
final Directory pluginGroupDir = packagesDir.childDirectory('foo');
|
|
final Directory appFacing = createFakePlugin('foo', pluginGroupDir);
|
|
final Directory implementation =
|
|
createFakePlugin('foo_bar', pluginGroupDir);
|
|
final Directory platformInterface =
|
|
createFakePlugin('foo_platform_interface', pluginGroupDir);
|
|
|
|
final String changedFileOutput = <File>[
|
|
appFacing.childFile('foo.dart'),
|
|
implementation.childFile('foo.dart'),
|
|
platformInterface.childFile('pubspec.yaml'),
|
|
platformInterface.childDirectory('lib').childFile('foo.dart'),
|
|
].map((File file) => file.path).join('\n');
|
|
processRunner.mockProcessesForExecutable['git-diff'] = <io.Process>[
|
|
MockProcess(stdout: changedFileOutput),
|
|
];
|
|
|
|
Error? commandError;
|
|
final List<String> output = await runCapturingPrint(
|
|
runner, <String>['federation-safety-check'], errorHandler: (Error e) {
|
|
commandError = e;
|
|
});
|
|
|
|
expect(commandError, isA<ToolExit>());
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for foo/foo...'),
|
|
contains('Dart changes are not allowed to other packages in foo in the '
|
|
'same PR as changes to public Dart code in foo_platform_interface, '
|
|
'as this can cause accidental breaking changes to be missed by '
|
|
'automated checks. Please split the changes to these two packages '
|
|
'into separate PRs.'),
|
|
contains('Running for foo_bar...'),
|
|
contains('Dart changes are not allowed to other packages in foo'),
|
|
contains('The following packages had errors:'),
|
|
contains('foo/foo:\n'
|
|
' foo_platform_interface changed.'),
|
|
contains('foo_bar:\n'
|
|
' foo_platform_interface changed.'),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('ignores test-only changes to interface packages', () async {
|
|
final Directory pluginGroupDir = packagesDir.childDirectory('foo');
|
|
final Directory appFacing = createFakePlugin('foo', pluginGroupDir);
|
|
final Directory implementation =
|
|
createFakePlugin('foo_bar', pluginGroupDir);
|
|
final Directory platformInterface =
|
|
createFakePlugin('foo_platform_interface', pluginGroupDir);
|
|
|
|
final String changedFileOutput = <File>[
|
|
appFacing.childFile('foo.dart'),
|
|
implementation.childFile('foo.dart'),
|
|
platformInterface.childFile('pubspec.yaml'),
|
|
platformInterface.childDirectory('test').childFile('foo.dart'),
|
|
].map((File file) => file.path).join('\n');
|
|
processRunner.mockProcessesForExecutable['git-diff'] = <io.Process>[
|
|
MockProcess(stdout: changedFileOutput),
|
|
];
|
|
|
|
final List<String> output =
|
|
await runCapturingPrint(runner, <String>['federation-safety-check']);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for foo/foo...'),
|
|
contains('No public code changes for foo_platform_interface.'),
|
|
contains('Running for foo_bar...'),
|
|
contains('No public code changes for foo_platform_interface.'),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('ignores unpublished changes to interface packages', () async {
|
|
final Directory pluginGroupDir = packagesDir.childDirectory('foo');
|
|
final Directory appFacing = createFakePlugin('foo', pluginGroupDir);
|
|
final Directory implementation =
|
|
createFakePlugin('foo_bar', pluginGroupDir);
|
|
final Directory platformInterface =
|
|
createFakePlugin('foo_platform_interface', pluginGroupDir);
|
|
|
|
final String changedFileOutput = <File>[
|
|
appFacing.childFile('foo.dart'),
|
|
implementation.childFile('foo.dart'),
|
|
platformInterface.childFile('pubspec.yaml'),
|
|
platformInterface.childDirectory('lib').childFile('foo.dart'),
|
|
].map((File file) => file.path).join('\n');
|
|
processRunner.mockProcessesForExecutable['git-diff'] = <io.Process>[
|
|
MockProcess(stdout: changedFileOutput),
|
|
];
|
|
// Simulate no change to the version in the interface's pubspec.yaml.
|
|
processRunner.mockProcessesForExecutable['git-show'] = <io.Process>[
|
|
MockProcess(
|
|
stdout: RepositoryPackage(platformInterface)
|
|
.pubspecFile
|
|
.readAsStringSync()),
|
|
];
|
|
|
|
final List<String> output =
|
|
await runCapturingPrint(runner, <String>['federation-safety-check']);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for foo/foo...'),
|
|
contains('No published changes for foo_platform_interface.'),
|
|
contains('Running for foo_bar...'),
|
|
contains('No published changes for foo_platform_interface.'),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('allows things that look like mass changes, with warning', () async {
|
|
final Directory pluginGroupDir = packagesDir.childDirectory('foo');
|
|
final Directory appFacing = createFakePlugin('foo', pluginGroupDir);
|
|
final Directory implementation =
|
|
createFakePlugin('foo_bar', pluginGroupDir);
|
|
final Directory platformInterface =
|
|
createFakePlugin('foo_platform_interface', pluginGroupDir);
|
|
|
|
final Directory otherPlugin1 = createFakePlugin('bar', packagesDir);
|
|
final Directory otherPlugin2 = createFakePlugin('baz', packagesDir);
|
|
|
|
final String changedFileOutput = <File>[
|
|
appFacing.childFile('foo.dart'),
|
|
implementation.childFile('foo.dart'),
|
|
platformInterface.childFile('pubspec.yaml'),
|
|
platformInterface.childDirectory('lib').childFile('foo.dart'),
|
|
otherPlugin1.childFile('bar.dart'),
|
|
otherPlugin2.childFile('baz.dart'),
|
|
].map((File file) => file.path).join('\n');
|
|
processRunner.mockProcessesForExecutable['git-diff'] = <io.Process>[
|
|
MockProcess(stdout: changedFileOutput),
|
|
];
|
|
|
|
final List<String> output =
|
|
await runCapturingPrint(runner, <String>['federation-safety-check']);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for foo/foo...'),
|
|
contains(
|
|
'Ignoring potentially dangerous change, as this appears to be a mass change.'),
|
|
contains('Running for foo_bar...'),
|
|
contains(
|
|
'Ignoring potentially dangerous change, as this appears to be a mass change.'),
|
|
contains('Ran for 2 package(s) (2 with warnings)'),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('handles top-level files that match federated package heuristics',
|
|
() async {
|
|
final Directory plugin = createFakePlugin('foo', packagesDir);
|
|
|
|
final String changedFileOutput = <File>[
|
|
// This should be picked up as a change to 'foo', and not crash.
|
|
plugin.childFile('foo_bar.baz'),
|
|
].map((File file) => file.path).join('\n');
|
|
processRunner.mockProcessesForExecutable['git-diff'] = <io.Process>[
|
|
MockProcess(stdout: changedFileOutput),
|
|
];
|
|
|
|
final List<String> output =
|
|
await runCapturingPrint(runner, <String>['federation-safety-check']);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for foo...'),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('handles deletion of an entire plugin', () async {
|
|
// Simulate deletion, in the form of diffs for packages that don't exist in
|
|
// the filesystem.
|
|
final String changedFileOutput = <File>[
|
|
packagesDir.childDirectory('foo').childFile('pubspec.yaml'),
|
|
packagesDir
|
|
.childDirectory('foo')
|
|
.childDirectory('lib')
|
|
.childFile('foo.dart'),
|
|
packagesDir
|
|
.childDirectory('foo_platform_interface')
|
|
.childFile('pubspec.yaml'),
|
|
packagesDir
|
|
.childDirectory('foo_platform_interface')
|
|
.childDirectory('lib')
|
|
.childFile('foo.dart'),
|
|
packagesDir.childDirectory('foo_web').childFile('pubspec.yaml'),
|
|
packagesDir
|
|
.childDirectory('foo_web')
|
|
.childDirectory('lib')
|
|
.childFile('foo.dart'),
|
|
].map((File file) => file.path).join('\n');
|
|
processRunner.mockProcessesForExecutable['git-diff'] = <io.Process>[
|
|
MockProcess(stdout: changedFileOutput),
|
|
];
|
|
|
|
final List<String> output =
|
|
await runCapturingPrint(runner, <String>['federation-safety-check']);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Ran for 0 package(s)'),
|
|
]),
|
|
);
|
|
});
|
|
}
|