mirror of
https://github.com/flutter/packages.git
synced 2025-06-11 07:07:51 +08:00

`filter-packages-to` didn't correctly the handle the case where the set of target packages is empty, meaning that all packages should be tested. This broke it for cases such as changing a CI configuration file, making the filter not take effect.
1410 lines
50 KiB
Dart
1410 lines
50 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 '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/package_command.dart';
|
|
import 'package:git/git.dart';
|
|
import 'package:mockito/annotations.dart';
|
|
import 'package:mockito/mockito.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
import '../mocks.dart';
|
|
import '../util.dart';
|
|
import 'package_command_test.mocks.dart';
|
|
|
|
@GenerateMocks(<Type>[GitDir])
|
|
void main() {
|
|
late RecordingProcessRunner processRunner;
|
|
late SamplePackageCommand command;
|
|
late CommandRunner<void> runner;
|
|
late FileSystem fileSystem;
|
|
late MockPlatform mockPlatform;
|
|
late Directory packagesDir;
|
|
late Directory thirdPartyPackagesDir;
|
|
|
|
setUp(() {
|
|
fileSystem = MemoryFileSystem();
|
|
mockPlatform = MockPlatform();
|
|
packagesDir = createPackagesDirectory(fileSystem: fileSystem);
|
|
thirdPartyPackagesDir = packagesDir.parent
|
|
.childDirectory('third_party')
|
|
.childDirectory('packages');
|
|
|
|
final MockGitDir gitDir = MockGitDir();
|
|
when(gitDir.runCommand(any, throwOnError: anyNamed('throwOnError')))
|
|
.thenAnswer((Invocation invocation) {
|
|
final List<String> arguments =
|
|
invocation.positionalArguments[0]! as List<String>;
|
|
// 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();
|
|
command = SamplePackageCommand(
|
|
packagesDir,
|
|
processRunner: processRunner,
|
|
platform: mockPlatform,
|
|
gitDir: gitDir,
|
|
);
|
|
runner =
|
|
CommandRunner<void>('common_command', 'Test for common functionality');
|
|
runner.addCommand(command);
|
|
});
|
|
|
|
group('plugin iteration', () {
|
|
test('all plugins from file system', () async {
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir);
|
|
final RepositoryPackage plugin2 =
|
|
createFakePlugin('plugin2', packagesDir);
|
|
await runCapturingPrint(runner, <String>['sample']);
|
|
expect(command.plugins,
|
|
unorderedEquals(<String>[plugin1.path, plugin2.path]));
|
|
});
|
|
|
|
test('includes both plugins and packages', () async {
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir);
|
|
final RepositoryPackage plugin2 =
|
|
createFakePlugin('plugin2', packagesDir);
|
|
final RepositoryPackage package3 =
|
|
createFakePackage('package3', packagesDir);
|
|
final RepositoryPackage package4 =
|
|
createFakePackage('package4', packagesDir);
|
|
await runCapturingPrint(runner, <String>['sample']);
|
|
expect(
|
|
command.plugins,
|
|
unorderedEquals(<String>[
|
|
plugin1.path,
|
|
plugin2.path,
|
|
package3.path,
|
|
package4.path,
|
|
]));
|
|
});
|
|
|
|
test('includes packages without source', () async {
|
|
final RepositoryPackage package =
|
|
createFakePackage('package', packagesDir);
|
|
package.libDirectory.deleteSync(recursive: true);
|
|
|
|
await runCapturingPrint(runner, <String>['sample']);
|
|
expect(
|
|
command.plugins,
|
|
unorderedEquals(<String>[
|
|
package.path,
|
|
]));
|
|
});
|
|
|
|
test('all plugins includes third_party/packages', () async {
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir);
|
|
final RepositoryPackage plugin2 =
|
|
createFakePlugin('plugin2', packagesDir);
|
|
final RepositoryPackage plugin3 =
|
|
createFakePlugin('plugin3', thirdPartyPackagesDir);
|
|
await runCapturingPrint(runner, <String>['sample']);
|
|
expect(command.plugins,
|
|
unorderedEquals(<String>[plugin1.path, plugin2.path, plugin3.path]));
|
|
});
|
|
|
|
test('--packages limits packages', () async {
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir);
|
|
createFakePlugin('plugin2', packagesDir);
|
|
createFakePackage('package3', packagesDir);
|
|
final RepositoryPackage package4 =
|
|
createFakePackage('package4', packagesDir);
|
|
await runCapturingPrint(
|
|
runner, <String>['sample', '--packages=plugin1,package4']);
|
|
expect(
|
|
command.plugins,
|
|
unorderedEquals(<String>[
|
|
plugin1.path,
|
|
package4.path,
|
|
]));
|
|
});
|
|
|
|
test('--plugins acts as an alias to --packages', () async {
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir);
|
|
createFakePlugin('plugin2', packagesDir);
|
|
createFakePackage('package3', packagesDir);
|
|
final RepositoryPackage package4 =
|
|
createFakePackage('package4', packagesDir);
|
|
await runCapturingPrint(
|
|
runner, <String>['sample', '--plugins=plugin1,package4']);
|
|
expect(
|
|
command.plugins,
|
|
unorderedEquals(<String>[
|
|
plugin1.path,
|
|
package4.path,
|
|
]));
|
|
});
|
|
|
|
test('exclude packages when packages flag is specified', () async {
|
|
createFakePlugin('plugin1', packagesDir);
|
|
final RepositoryPackage plugin2 =
|
|
createFakePlugin('plugin2', packagesDir);
|
|
await runCapturingPrint(runner, <String>[
|
|
'sample',
|
|
'--packages=plugin1,plugin2',
|
|
'--exclude=plugin1'
|
|
]);
|
|
expect(command.plugins, unorderedEquals(<String>[plugin2.path]));
|
|
});
|
|
|
|
test("exclude packages when packages flag isn't specified", () async {
|
|
createFakePlugin('plugin1', packagesDir);
|
|
createFakePlugin('plugin2', packagesDir);
|
|
await runCapturingPrint(
|
|
runner, <String>['sample', '--exclude=plugin1,plugin2']);
|
|
expect(command.plugins, unorderedEquals(<String>[]));
|
|
});
|
|
|
|
test('exclude federated plugins when packages flag is specified', () async {
|
|
createFakePlugin('plugin1', packagesDir.childDirectory('federated'));
|
|
final RepositoryPackage plugin2 =
|
|
createFakePlugin('plugin2', packagesDir);
|
|
await runCapturingPrint(runner, <String>[
|
|
'sample',
|
|
'--packages=federated/plugin1,plugin2',
|
|
'--exclude=federated/plugin1'
|
|
]);
|
|
expect(command.plugins, unorderedEquals(<String>[plugin2.path]));
|
|
});
|
|
|
|
test('exclude entire federated plugins when packages flag is specified',
|
|
() async {
|
|
createFakePlugin('plugin1', packagesDir.childDirectory('federated'));
|
|
final RepositoryPackage plugin2 =
|
|
createFakePlugin('plugin2', packagesDir);
|
|
await runCapturingPrint(runner, <String>[
|
|
'sample',
|
|
'--packages=federated/plugin1,plugin2',
|
|
'--exclude=federated'
|
|
]);
|
|
expect(command.plugins, unorderedEquals(<String>[plugin2.path]));
|
|
});
|
|
|
|
test('exclude accepts config files', () async {
|
|
createFakePlugin('plugin1', packagesDir);
|
|
final File configFile = packagesDir.childFile('exclude.yaml');
|
|
configFile.writeAsStringSync('- plugin1');
|
|
|
|
await runCapturingPrint(runner, <String>[
|
|
'sample',
|
|
'--packages=plugin1',
|
|
'--exclude=${configFile.path}'
|
|
]);
|
|
expect(command.plugins, unorderedEquals(<String>[]));
|
|
});
|
|
|
|
test('filter-packages-to accepts config files', () async {
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir);
|
|
createFakePlugin('plugin2', packagesDir);
|
|
final File configFile = packagesDir.childFile('exclude.yaml');
|
|
configFile.writeAsStringSync('- plugin1');
|
|
|
|
await runCapturingPrint(runner, <String>[
|
|
'sample',
|
|
'--packages=plugin1,plugin2',
|
|
'--filter-packages-to=${configFile.path}'
|
|
]);
|
|
expect(command.plugins, unorderedEquals(<String>[plugin1.path]));
|
|
});
|
|
|
|
test(
|
|
'explicitly specifying the plugin (group) name of a federated plugin '
|
|
'should include all plugins in the group', () async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] = <FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: '''
|
|
packages/plugin1/plugin1/plugin1.dart
|
|
''')),
|
|
];
|
|
final Directory pluginGroup = packagesDir.childDirectory('plugin1');
|
|
final RepositoryPackage appFacingPackage =
|
|
createFakePlugin('plugin1', pluginGroup);
|
|
final RepositoryPackage platformInterfacePackage =
|
|
createFakePlugin('plugin1_platform_interface', pluginGroup);
|
|
final RepositoryPackage implementationPackage =
|
|
createFakePlugin('plugin1_web', pluginGroup);
|
|
|
|
await runCapturingPrint(
|
|
runner, <String>['sample', '--base-sha=main', '--packages=plugin1']);
|
|
|
|
expect(
|
|
command.plugins,
|
|
unorderedEquals(<String>[
|
|
appFacingPackage.path,
|
|
platformInterfacePackage.path,
|
|
implementationPackage.path
|
|
]));
|
|
});
|
|
|
|
test(
|
|
'specifying the app-facing package of a federated plugin using its '
|
|
'fully qualified name should include only that package', () async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] = <FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: '''
|
|
packages/plugin1/plugin1/plugin1.dart
|
|
''')),
|
|
];
|
|
final Directory pluginGroup = packagesDir.childDirectory('plugin1');
|
|
final RepositoryPackage appFacingPackage =
|
|
createFakePlugin('plugin1', pluginGroup);
|
|
createFakePlugin('plugin1_platform_interface', pluginGroup);
|
|
createFakePlugin('plugin1_web', pluginGroup);
|
|
|
|
await runCapturingPrint(runner,
|
|
<String>['sample', '--base-sha=main', '--packages=plugin1/plugin1']);
|
|
|
|
expect(command.plugins, unorderedEquals(<String>[appFacingPackage.path]));
|
|
});
|
|
|
|
test(
|
|
'specifying a package of a federated plugin by its name should '
|
|
'include only that package', () async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] = <FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: '''
|
|
packages/plugin1/plugin1/plugin1.dart
|
|
''')),
|
|
];
|
|
final Directory pluginGroup = packagesDir.childDirectory('plugin1');
|
|
|
|
createFakePlugin('plugin1', pluginGroup);
|
|
final RepositoryPackage platformInterfacePackage =
|
|
createFakePlugin('plugin1_platform_interface', pluginGroup);
|
|
createFakePlugin('plugin1_web', pluginGroup);
|
|
|
|
await runCapturingPrint(runner, <String>[
|
|
'sample',
|
|
'--base-sha=main',
|
|
'--packages=plugin1_platform_interface'
|
|
]);
|
|
|
|
expect(command.plugins,
|
|
unorderedEquals(<String>[platformInterfacePackage.path]));
|
|
});
|
|
|
|
test('returns subpackages after the enclosing package', () async {
|
|
final SamplePackageCommand localCommand = SamplePackageCommand(
|
|
packagesDir,
|
|
processRunner: processRunner,
|
|
platform: mockPlatform,
|
|
gitDir: MockGitDir(),
|
|
includeSubpackages: true,
|
|
);
|
|
final CommandRunner<void> localRunner =
|
|
CommandRunner<void>('common_command', 'subpackage testing');
|
|
localRunner.addCommand(localCommand);
|
|
|
|
final RepositoryPackage package =
|
|
createFakePackage('apackage', packagesDir);
|
|
|
|
await runCapturingPrint(localRunner, <String>['sample']);
|
|
expect(
|
|
localCommand.plugins,
|
|
containsAllInOrder(<String>[
|
|
package.path,
|
|
getExampleDir(package).path,
|
|
]));
|
|
});
|
|
|
|
group('conflicting package selection', () {
|
|
test('does not allow --packages with --run-on-changed-packages',
|
|
() async {
|
|
Error? commandError;
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'sample',
|
|
'--run-on-changed-packages',
|
|
'--packages=plugin1',
|
|
], errorHandler: (Error e) {
|
|
commandError = e;
|
|
});
|
|
|
|
expect(commandError, isA<ToolExit>());
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Only one of the package selection arguments')
|
|
]));
|
|
});
|
|
|
|
test('does not allow --packages with --packages-for-branch', () async {
|
|
Error? commandError;
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'sample',
|
|
'--packages-for-branch',
|
|
'--packages=plugin1',
|
|
], errorHandler: (Error e) {
|
|
commandError = e;
|
|
});
|
|
|
|
expect(commandError, isA<ToolExit>());
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Only one of the package selection arguments')
|
|
]));
|
|
});
|
|
|
|
test('does not allow --packages with --current-package', () async {
|
|
Error? commandError;
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'sample',
|
|
'--current-package',
|
|
'--packages=plugin1',
|
|
], errorHandler: (Error e) {
|
|
commandError = e;
|
|
});
|
|
|
|
expect(commandError, isA<ToolExit>());
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Only one of the package selection arguments')
|
|
]));
|
|
});
|
|
|
|
test(
|
|
'does not allow --run-on-changed-packages with --packages-for-branch',
|
|
() async {
|
|
Error? commandError;
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'sample',
|
|
'--packages-for-branch',
|
|
'--packages=plugin1',
|
|
], errorHandler: (Error e) {
|
|
commandError = e;
|
|
});
|
|
|
|
expect(commandError, isA<ToolExit>());
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Only one of the package selection arguments')
|
|
]));
|
|
});
|
|
});
|
|
|
|
group('current-package', () {
|
|
test('throws when run from outside of the packages directory', () async {
|
|
fileSystem.currentDirectory = packagesDir.parent;
|
|
|
|
Error? commandError;
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'sample',
|
|
'--current-package',
|
|
], errorHandler: (Error e) {
|
|
commandError = e;
|
|
});
|
|
|
|
expect(commandError, isA<ToolExit>());
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('--current-package can only be used within a repository '
|
|
'package or package group')
|
|
]));
|
|
});
|
|
|
|
test('throws when run directly in the packages directory', () async {
|
|
fileSystem.currentDirectory = packagesDir;
|
|
|
|
Error? commandError;
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'sample',
|
|
'--current-package',
|
|
], errorHandler: (Error e) {
|
|
commandError = e;
|
|
});
|
|
|
|
expect(commandError, isA<ToolExit>());
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('--current-package can only be used within a repository '
|
|
'package or package group')
|
|
]));
|
|
});
|
|
|
|
test('runs on a package when run from the package directory', () async {
|
|
final RepositoryPackage package =
|
|
createFakePlugin('a_package', packagesDir);
|
|
createFakePlugin('another_package', packagesDir);
|
|
fileSystem.currentDirectory = package.directory;
|
|
|
|
await runCapturingPrint(
|
|
runner, <String>['sample', '--current-package']);
|
|
|
|
expect(command.plugins, unorderedEquals(<String>[package.path]));
|
|
});
|
|
|
|
test('runs only app-facing package of a federated plugin', () async {
|
|
const String pluginName = 'foo';
|
|
final Directory groupDir = packagesDir.childDirectory(pluginName);
|
|
final RepositoryPackage package =
|
|
createFakePlugin(pluginName, groupDir);
|
|
createFakePlugin('${pluginName}_someplatform', groupDir);
|
|
createFakePackage('${pluginName}_platform_interface', groupDir);
|
|
fileSystem.currentDirectory = package.directory;
|
|
|
|
await runCapturingPrint(
|
|
runner, <String>['sample', '--current-package']);
|
|
|
|
expect(command.plugins, unorderedEquals(<String>[package.path]));
|
|
});
|
|
|
|
test('runs on a package when run from a package example directory',
|
|
() async {
|
|
final RepositoryPackage package = createFakePlugin(
|
|
'a_package', packagesDir,
|
|
examples: <String>['a', 'b', 'c']);
|
|
createFakePlugin('another_package', packagesDir);
|
|
fileSystem.currentDirectory = package.getExamples().first.directory;
|
|
|
|
await runCapturingPrint(
|
|
runner, <String>['sample', '--current-package']);
|
|
|
|
expect(command.plugins, unorderedEquals(<String>[package.path]));
|
|
});
|
|
|
|
test('runs on a package group when run from the group directory',
|
|
() async {
|
|
final Directory pluginGroup = packagesDir.childDirectory('a_plugin');
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('a_plugin_foo', pluginGroup);
|
|
final RepositoryPackage plugin2 =
|
|
createFakePlugin('a_plugin_bar', pluginGroup);
|
|
createFakePlugin('unrelated_plugin', packagesDir);
|
|
fileSystem.currentDirectory = pluginGroup;
|
|
|
|
await runCapturingPrint(
|
|
runner, <String>['sample', '--current-package']);
|
|
|
|
expect(command.plugins,
|
|
unorderedEquals(<String>[plugin1.path, plugin2.path]));
|
|
});
|
|
});
|
|
|
|
group('test run-on-changed-packages', () {
|
|
test('all plugins should be tested if there are no changes.', () async {
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir);
|
|
final RepositoryPackage plugin2 =
|
|
createFakePlugin('plugin2', packagesDir);
|
|
await runCapturingPrint(runner,
|
|
<String>['sample', '--base-sha=main', '--run-on-changed-packages']);
|
|
|
|
expect(command.plugins,
|
|
unorderedEquals(<String>[plugin1.path, plugin2.path]));
|
|
});
|
|
|
|
test(
|
|
'all plugins should be tested if there are no plugin related changes.',
|
|
() async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: 'AUTHORS')),
|
|
];
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir);
|
|
final RepositoryPackage plugin2 =
|
|
createFakePlugin('plugin2', packagesDir);
|
|
await runCapturingPrint(runner,
|
|
<String>['sample', '--base-sha=main', '--run-on-changed-packages']);
|
|
|
|
expect(command.plugins,
|
|
unorderedEquals(<String>[plugin1.path, plugin2.path]));
|
|
});
|
|
|
|
test('all plugins should be tested if .cirrus.yml changes.', () async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: '''
|
|
.cirrus.yml
|
|
packages/plugin1/CHANGELOG
|
|
''')),
|
|
];
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir);
|
|
final RepositoryPackage plugin2 =
|
|
createFakePlugin('plugin2', packagesDir);
|
|
|
|
final List<String> output = await runCapturingPrint(runner,
|
|
<String>['sample', '--base-sha=main', '--run-on-changed-packages']);
|
|
|
|
expect(command.plugins,
|
|
unorderedEquals(<String>[plugin1.path, plugin2.path]));
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for all packages, since a file has changed '
|
|
'that could affect the entire repository.')
|
|
]));
|
|
});
|
|
|
|
test('all plugins should be tested if .ci.yaml changes', () async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: '''
|
|
.ci.yaml
|
|
packages/plugin1/CHANGELOG
|
|
''')),
|
|
];
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir);
|
|
final RepositoryPackage plugin2 =
|
|
createFakePlugin('plugin2', packagesDir);
|
|
final List<String> output = await runCapturingPrint(runner,
|
|
<String>['sample', '--base-sha=main', '--run-on-changed-packages']);
|
|
|
|
expect(command.plugins,
|
|
unorderedEquals(<String>[plugin1.path, plugin2.path]));
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for all packages, since a file has changed '
|
|
'that could affect the entire repository.')
|
|
]));
|
|
});
|
|
|
|
test('all plugins should be tested if anything in .ci/ changes',
|
|
() async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: '''
|
|
.ci/Dockerfile
|
|
packages/plugin1/CHANGELOG
|
|
''')),
|
|
];
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir);
|
|
final RepositoryPackage plugin2 =
|
|
createFakePlugin('plugin2', packagesDir);
|
|
final List<String> output = await runCapturingPrint(runner,
|
|
<String>['sample', '--base-sha=main', '--run-on-changed-packages']);
|
|
|
|
expect(command.plugins,
|
|
unorderedEquals(<String>[plugin1.path, plugin2.path]));
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for all packages, since a file has changed '
|
|
'that could affect the entire repository.')
|
|
]));
|
|
});
|
|
|
|
test('all plugins should be tested if anything in script/ changes.',
|
|
() async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: '''
|
|
script/tool_runner.sh
|
|
packages/plugin1/CHANGELOG
|
|
''')),
|
|
];
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir);
|
|
final RepositoryPackage plugin2 =
|
|
createFakePlugin('plugin2', packagesDir);
|
|
final List<String> output = await runCapturingPrint(runner,
|
|
<String>['sample', '--base-sha=main', '--run-on-changed-packages']);
|
|
|
|
expect(command.plugins,
|
|
unorderedEquals(<String>[plugin1.path, plugin2.path]));
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for all packages, since a file has changed '
|
|
'that could affect the entire repository.')
|
|
]));
|
|
});
|
|
|
|
test('all plugins should be tested if the root analysis options change.',
|
|
() async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: '''
|
|
analysis_options.yaml
|
|
packages/plugin1/CHANGELOG
|
|
''')),
|
|
];
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir);
|
|
final RepositoryPackage plugin2 =
|
|
createFakePlugin('plugin2', packagesDir);
|
|
final List<String> output = await runCapturingPrint(runner,
|
|
<String>['sample', '--base-sha=main', '--run-on-changed-packages']);
|
|
|
|
expect(command.plugins,
|
|
unorderedEquals(<String>[plugin1.path, plugin2.path]));
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for all packages, since a file has changed '
|
|
'that could affect the entire repository.')
|
|
]));
|
|
});
|
|
|
|
test('all plugins should be tested if formatting options change.',
|
|
() async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: '''
|
|
.clang-format
|
|
packages/plugin1/CHANGELOG
|
|
''')),
|
|
];
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir);
|
|
final RepositoryPackage plugin2 =
|
|
createFakePlugin('plugin2', packagesDir);
|
|
final List<String> output = await runCapturingPrint(runner,
|
|
<String>['sample', '--base-sha=main', '--run-on-changed-packages']);
|
|
|
|
expect(command.plugins,
|
|
unorderedEquals(<String>[plugin1.path, plugin2.path]));
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for all packages, since a file has changed '
|
|
'that could affect the entire repository.')
|
|
]));
|
|
});
|
|
|
|
test('Only changed plugin should be tested.', () async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: 'packages/plugin1/plugin1.dart')),
|
|
];
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir);
|
|
createFakePlugin('plugin2', packagesDir);
|
|
final List<String> output = await runCapturingPrint(runner,
|
|
<String>['sample', '--base-sha=main', '--run-on-changed-packages']);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains(
|
|
'Running for all packages that have diffs relative to "main"'),
|
|
]));
|
|
|
|
expect(command.plugins, unorderedEquals(<String>[plugin1.path]));
|
|
});
|
|
|
|
test('multiple files in one plugin should also test the plugin',
|
|
() async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: '''
|
|
packages/plugin1/plugin1.dart
|
|
packages/plugin1/ios/plugin1.m
|
|
''')),
|
|
];
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir);
|
|
createFakePlugin('plugin2', packagesDir);
|
|
await runCapturingPrint(runner,
|
|
<String>['sample', '--base-sha=main', '--run-on-changed-packages']);
|
|
|
|
expect(command.plugins, unorderedEquals(<String>[plugin1.path]));
|
|
});
|
|
|
|
test('multiple plugins changed should test all the changed plugins',
|
|
() async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: '''
|
|
packages/plugin1/plugin1.dart
|
|
packages/plugin2/ios/plugin2.m
|
|
''')),
|
|
];
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir);
|
|
final RepositoryPackage plugin2 =
|
|
createFakePlugin('plugin2', packagesDir);
|
|
createFakePlugin('plugin3', packagesDir);
|
|
await runCapturingPrint(runner,
|
|
<String>['sample', '--base-sha=main', '--run-on-changed-packages']);
|
|
|
|
expect(command.plugins,
|
|
unorderedEquals(<String>[plugin1.path, plugin2.path]));
|
|
});
|
|
|
|
test(
|
|
'multiple plugins inside the same plugin group changed should output the plugin group name',
|
|
() async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: '''
|
|
packages/plugin1/plugin1/plugin1.dart
|
|
packages/plugin1/plugin1_platform_interface/plugin1_platform_interface.dart
|
|
packages/plugin1/plugin1_web/plugin1_web.dart
|
|
''')),
|
|
];
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir.childDirectory('plugin1'));
|
|
createFakePlugin('plugin2', packagesDir);
|
|
createFakePlugin('plugin3', packagesDir);
|
|
await runCapturingPrint(runner,
|
|
<String>['sample', '--base-sha=main', '--run-on-changed-packages']);
|
|
|
|
expect(command.plugins, unorderedEquals(<String>[plugin1.path]));
|
|
});
|
|
|
|
test(
|
|
'changing one plugin in a federated group should only include that plugin',
|
|
() async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: '''
|
|
packages/plugin1/plugin1/plugin1.dart
|
|
''')),
|
|
];
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir.childDirectory('plugin1'));
|
|
createFakePlugin('plugin1_platform_interface',
|
|
packagesDir.childDirectory('plugin1'));
|
|
createFakePlugin('plugin1_web', packagesDir.childDirectory('plugin1'));
|
|
await runCapturingPrint(runner,
|
|
<String>['sample', '--base-sha=main', '--run-on-changed-packages']);
|
|
|
|
expect(command.plugins, unorderedEquals(<String>[plugin1.path]));
|
|
});
|
|
|
|
test('honors --exclude flag', () async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: '''
|
|
packages/plugin1/plugin1.dart
|
|
packages/plugin2/ios/plugin2.m
|
|
packages/plugin3/plugin3.dart
|
|
''')),
|
|
];
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir.childDirectory('plugin1'));
|
|
createFakePlugin('plugin2', packagesDir);
|
|
createFakePlugin('plugin3', packagesDir);
|
|
await runCapturingPrint(runner, <String>[
|
|
'sample',
|
|
'--exclude=plugin2,plugin3',
|
|
'--base-sha=main',
|
|
'--run-on-changed-packages'
|
|
]);
|
|
|
|
expect(command.plugins, unorderedEquals(<String>[plugin1.path]));
|
|
});
|
|
|
|
test('honors --filter-packages-to flag', () async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: '''
|
|
packages/plugin1/plugin1.dart
|
|
packages/plugin2/ios/plugin2.m
|
|
packages/plugin3/plugin3.dart
|
|
''')),
|
|
];
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir.childDirectory('plugin1'));
|
|
createFakePlugin('plugin2', packagesDir);
|
|
createFakePlugin('plugin3', packagesDir);
|
|
await runCapturingPrint(runner, <String>[
|
|
'sample',
|
|
'--filter-packages-to=plugin1',
|
|
'--base-sha=main',
|
|
'--run-on-changed-packages'
|
|
]);
|
|
|
|
expect(command.plugins, unorderedEquals(<String>[plugin1.path]));
|
|
});
|
|
|
|
test(
|
|
'honors --filter-packages-to flag when a file is changed that makes '
|
|
'all packages potentially changed', () async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: '''
|
|
.ci.yaml
|
|
''')),
|
|
];
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir.childDirectory('plugin1'));
|
|
createFakePlugin('plugin2', packagesDir);
|
|
createFakePlugin('plugin3', packagesDir);
|
|
await runCapturingPrint(runner, <String>[
|
|
'sample',
|
|
'--filter-packages-to=plugin1',
|
|
'--base-sha=main',
|
|
'--run-on-changed-packages'
|
|
]);
|
|
|
|
expect(command.plugins, unorderedEquals(<String>[plugin1.path]));
|
|
});
|
|
|
|
test('--filter-packages-to handles federated plugin groups', () async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: '''
|
|
packages/a_plugin/a_plugin/lib/foo.dart
|
|
packages/a_plugin/a_plugin_impl/lib/foo.dart
|
|
packages/a_plugin/a_plugin_platform_interface/lib/foo.dart
|
|
''')),
|
|
];
|
|
final Directory groupDir = packagesDir.childDirectory('a_plugin');
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('a_plugin', groupDir);
|
|
final RepositoryPackage plugin2 =
|
|
createFakePlugin('a_plugin_impl', groupDir);
|
|
final RepositoryPackage plugin3 =
|
|
createFakePlugin('a_plugin_platform_interface', groupDir);
|
|
await runCapturingPrint(runner, <String>[
|
|
'sample',
|
|
'--filter-packages-to=a_plugin',
|
|
'--base-sha=main',
|
|
'--run-on-changed-packages'
|
|
]);
|
|
|
|
expect(
|
|
command.plugins,
|
|
unorderedEquals(
|
|
<String>[plugin1.path, plugin2.path, plugin3.path]));
|
|
});
|
|
|
|
test('--filter-packages-to and --exclude work together', () async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: '''
|
|
.ci.yaml
|
|
''')),
|
|
];
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir.childDirectory('plugin1'));
|
|
createFakePlugin('plugin2', packagesDir);
|
|
createFakePlugin('plugin3', packagesDir);
|
|
await runCapturingPrint(runner, <String>[
|
|
'sample',
|
|
'--filter-packages-to=plugin1,plugin2',
|
|
'--exclude=plugin2',
|
|
'--base-sha=main',
|
|
'--run-on-changed-packages'
|
|
]);
|
|
|
|
expect(command.plugins, unorderedEquals(<String>[plugin1.path]));
|
|
});
|
|
});
|
|
|
|
group('test run-on-dirty-packages', () {
|
|
test('no packages should be tested if there are no changes.', () async {
|
|
createFakePackage('a_package', packagesDir);
|
|
await runCapturingPrint(
|
|
runner, <String>['sample', '--run-on-dirty-packages']);
|
|
|
|
expect(command.plugins, unorderedEquals(<String>[]));
|
|
});
|
|
|
|
test(
|
|
'no packages should be tested if there are no plugin related changes.',
|
|
() async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: 'AUTHORS')),
|
|
];
|
|
createFakePackage('a_package', packagesDir);
|
|
await runCapturingPrint(
|
|
runner, <String>['sample', '--run-on-dirty-packages']);
|
|
|
|
expect(command.plugins, unorderedEquals(<String>[]));
|
|
});
|
|
|
|
test('no packages should be tested even if special repo files change.',
|
|
() async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: '''
|
|
.cirrus.yml
|
|
.ci.yaml
|
|
.ci/Dockerfile
|
|
.clang-format
|
|
analysis_options.yaml
|
|
script/tool_runner.sh
|
|
''')),
|
|
];
|
|
createFakePackage('a_package', packagesDir);
|
|
await runCapturingPrint(
|
|
runner, <String>['sample', '--run-on-dirty-packages']);
|
|
|
|
expect(command.plugins, unorderedEquals(<String>[]));
|
|
});
|
|
|
|
test('Only changed packages should be tested.', () async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(
|
|
MockProcess(stdout: 'packages/a_package/lib/a_package.dart')),
|
|
];
|
|
final RepositoryPackage packageA =
|
|
createFakePackage('a_package', packagesDir);
|
|
createFakePlugin('b_package', packagesDir);
|
|
final List<String> output = await runCapturingPrint(
|
|
runner, <String>['sample', '--run-on-dirty-packages']);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains(
|
|
'Running for all packages that have uncommitted changes'),
|
|
]));
|
|
|
|
expect(command.plugins, unorderedEquals(<String>[packageA.path]));
|
|
});
|
|
|
|
test('multiple packages changed should test all the changed packages',
|
|
() async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: '''
|
|
packages/a_package/lib/a_package.dart
|
|
packages/b_package/lib/src/foo.dart
|
|
''')),
|
|
];
|
|
final RepositoryPackage packageA =
|
|
createFakePackage('a_package', packagesDir);
|
|
final RepositoryPackage packageB =
|
|
createFakePackage('b_package', packagesDir);
|
|
createFakePackage('c_package', packagesDir);
|
|
await runCapturingPrint(
|
|
runner, <String>['sample', '--run-on-dirty-packages']);
|
|
|
|
expect(command.plugins,
|
|
unorderedEquals(<String>[packageA.path, packageB.path]));
|
|
});
|
|
|
|
test('honors --exclude flag', () async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: '''
|
|
packages/a_package/lib/a_package.dart
|
|
packages/b_package/lib/src/foo.dart
|
|
''')),
|
|
];
|
|
final RepositoryPackage packageA =
|
|
createFakePackage('a_package', packagesDir);
|
|
createFakePackage('b_package', packagesDir);
|
|
createFakePackage('c_package', packagesDir);
|
|
await runCapturingPrint(runner, <String>[
|
|
'sample',
|
|
'--exclude=b_package',
|
|
'--run-on-dirty-packages'
|
|
]);
|
|
|
|
expect(command.plugins, unorderedEquals(<String>[packageA.path]));
|
|
});
|
|
});
|
|
});
|
|
|
|
group('--packages-for-branch', () {
|
|
test('only tests changed packages relative to the merge base on a branch',
|
|
() async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] = <FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: 'packages/plugin1/plugin1.dart')),
|
|
];
|
|
processRunner.mockProcessesForExecutable['git-rev-parse'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: 'a-branch')),
|
|
];
|
|
processRunner.mockProcessesForExecutable['git-merge-base'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(exitCode: 1), <String>['--is-ancestor']),
|
|
FakeProcessInfo(MockProcess(stdout: 'abc123'),
|
|
<String>['--fork-point']), // finding merge base
|
|
];
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir);
|
|
createFakePlugin('plugin2', packagesDir);
|
|
|
|
final List<String> output = await runCapturingPrint(
|
|
runner, <String>['sample', '--packages-for-branch']);
|
|
|
|
expect(command.plugins, unorderedEquals(<String>[plugin1.path]));
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('--packages-for-branch: running on branch "a-branch"'),
|
|
contains(
|
|
'Running for all packages that have diffs relative to "abc123"'),
|
|
]));
|
|
// Ensure that it's diffing against the merge-base.
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
contains(
|
|
const ProcessCall(
|
|
'git-diff', <String>['--name-only', 'abc123', 'HEAD'], null),
|
|
));
|
|
});
|
|
|
|
test('only tests changed packages relative to the previous commit on main',
|
|
() async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] = <FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: 'packages/plugin1/plugin1.dart')),
|
|
];
|
|
processRunner.mockProcessesForExecutable['git-rev-parse'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: 'main')),
|
|
];
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir);
|
|
createFakePlugin('plugin2', packagesDir);
|
|
|
|
final List<String> output = await runCapturingPrint(
|
|
runner, <String>['sample', '--packages-for-branch']);
|
|
|
|
expect(command.plugins, unorderedEquals(<String>[plugin1.path]));
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('--packages-for-branch: running on default branch.'),
|
|
contains(
|
|
'--packages-for-branch: using parent commit as the diff base'),
|
|
contains(
|
|
'Running for all packages that have diffs relative to "HEAD~"'),
|
|
]));
|
|
// Ensure that it's diffing against the prior commit.
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
contains(
|
|
const ProcessCall(
|
|
'git-diff', <String>['--name-only', 'HEAD~', 'HEAD'], null),
|
|
));
|
|
});
|
|
|
|
test(
|
|
'only tests changed packages relative to the previous commit if '
|
|
'running on a specific hash from main', () async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] = <FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: 'packages/plugin1/plugin1.dart')),
|
|
];
|
|
processRunner.mockProcessesForExecutable['git-rev-parse'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: 'HEAD')),
|
|
];
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir);
|
|
createFakePlugin('plugin2', packagesDir);
|
|
|
|
final List<String> output = await runCapturingPrint(
|
|
runner, <String>['sample', '--packages-for-branch']);
|
|
|
|
expect(command.plugins, unorderedEquals(<String>[plugin1.path]));
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains(
|
|
'--packages-for-branch: running on a commit from default branch.'),
|
|
contains(
|
|
'--packages-for-branch: using parent commit as the diff base'),
|
|
contains(
|
|
'Running for all packages that have diffs relative to "HEAD~"'),
|
|
]));
|
|
// Ensure that it's diffing against the prior commit.
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
contains(
|
|
const ProcessCall(
|
|
'git-diff', <String>['--name-only', 'HEAD~', 'HEAD'], null),
|
|
));
|
|
});
|
|
|
|
test(
|
|
'only tests changed packages relative to the previous commit if '
|
|
'running on a specific hash from origin/main', () async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] = <FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: 'packages/plugin1/plugin1.dart')),
|
|
];
|
|
processRunner.mockProcessesForExecutable['git-rev-parse'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: 'HEAD')),
|
|
];
|
|
processRunner.mockProcessesForExecutable['git-merge-base'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(exitCode: 128), <String>[
|
|
'--is-ancestor',
|
|
'HEAD',
|
|
'main'
|
|
]), // Fail with a non-1 exit code for 'main'
|
|
FakeProcessInfo(MockProcess(), <String>[
|
|
'--is-ancestor',
|
|
'HEAD',
|
|
'origin/main'
|
|
]), // Succeed for the variant.
|
|
];
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir);
|
|
createFakePlugin('plugin2', packagesDir);
|
|
|
|
final List<String> output = await runCapturingPrint(
|
|
runner, <String>['sample', '--packages-for-branch']);
|
|
|
|
expect(command.plugins, unorderedEquals(<String>[plugin1.path]));
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains(
|
|
'--packages-for-branch: running on a commit from default branch.'),
|
|
contains(
|
|
'--packages-for-branch: using parent commit as the diff base'),
|
|
contains(
|
|
'Running for all packages that have diffs relative to "HEAD~"'),
|
|
]));
|
|
// Ensure that it's diffing against the prior commit.
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
contains(
|
|
const ProcessCall(
|
|
'git-diff', <String>['--name-only', 'HEAD~', 'HEAD'], null),
|
|
));
|
|
});
|
|
|
|
test(
|
|
'only tests changed packages relative to the previous commit on master',
|
|
() async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] = <FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: 'packages/plugin1/plugin1.dart')),
|
|
];
|
|
processRunner.mockProcessesForExecutable['git-rev-parse'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: 'master')),
|
|
];
|
|
final RepositoryPackage plugin1 =
|
|
createFakePlugin('plugin1', packagesDir);
|
|
createFakePlugin('plugin2', packagesDir);
|
|
|
|
final List<String> output = await runCapturingPrint(
|
|
runner, <String>['sample', '--packages-for-branch']);
|
|
|
|
expect(command.plugins, unorderedEquals(<String>[plugin1.path]));
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('--packages-for-branch: running on default branch.'),
|
|
contains(
|
|
'--packages-for-branch: using parent commit as the diff base'),
|
|
contains(
|
|
'Running for all packages that have diffs relative to "HEAD~"'),
|
|
]));
|
|
// Ensure that it's diffing against the prior commit.
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
contains(
|
|
const ProcessCall(
|
|
'git-diff', <String>['--name-only', 'HEAD~', 'HEAD'], null),
|
|
));
|
|
});
|
|
|
|
test('throws if getting the branch fails', () async {
|
|
processRunner.mockProcessesForExecutable['git-diff'] = <FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(stdout: 'packages/plugin1/plugin1.dart')),
|
|
];
|
|
processRunner.mockProcessesForExecutable['git-rev-parse'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(exitCode: 1)),
|
|
];
|
|
|
|
Error? commandError;
|
|
final List<String> output = await runCapturingPrint(
|
|
runner, <String>['sample', '--packages-for-branch'],
|
|
errorHandler: (Error e) {
|
|
commandError = e;
|
|
});
|
|
|
|
expect(commandError, isA<ToolExit>());
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Unable to determine branch'),
|
|
]));
|
|
});
|
|
});
|
|
|
|
group('sharding', () {
|
|
test('distributes evenly when evenly divisible', () async {
|
|
final List<List<RepositoryPackage>> expectedShards =
|
|
<List<RepositoryPackage>>[
|
|
<RepositoryPackage>[
|
|
createFakePackage('package1', packagesDir),
|
|
createFakePackage('package2', packagesDir),
|
|
createFakePackage('package3', packagesDir),
|
|
],
|
|
<RepositoryPackage>[
|
|
createFakePackage('package4', packagesDir),
|
|
createFakePackage('package5', packagesDir),
|
|
createFakePackage('package6', packagesDir),
|
|
],
|
|
<RepositoryPackage>[
|
|
createFakePackage('package7', packagesDir),
|
|
createFakePackage('package8', packagesDir),
|
|
createFakePackage('package9', packagesDir),
|
|
],
|
|
];
|
|
|
|
for (int i = 0; i < expectedShards.length; ++i) {
|
|
final SamplePackageCommand localCommand = SamplePackageCommand(
|
|
packagesDir,
|
|
processRunner: processRunner,
|
|
platform: mockPlatform,
|
|
gitDir: MockGitDir(),
|
|
);
|
|
final CommandRunner<void> localRunner =
|
|
CommandRunner<void>('common_command', 'Shard testing');
|
|
localRunner.addCommand(localCommand);
|
|
|
|
await runCapturingPrint(localRunner, <String>[
|
|
'sample',
|
|
'--shardIndex=$i',
|
|
'--shardCount=3',
|
|
]);
|
|
expect(
|
|
localCommand.plugins,
|
|
unorderedEquals(expectedShards[i]
|
|
.map((RepositoryPackage package) => package.path)
|
|
.toList()));
|
|
}
|
|
});
|
|
|
|
test('distributes as evenly as possible when not evenly divisible',
|
|
() async {
|
|
final List<List<RepositoryPackage>> expectedShards =
|
|
<List<RepositoryPackage>>[
|
|
<RepositoryPackage>[
|
|
createFakePackage('package1', packagesDir),
|
|
createFakePackage('package2', packagesDir),
|
|
createFakePackage('package3', packagesDir),
|
|
],
|
|
<RepositoryPackage>[
|
|
createFakePackage('package4', packagesDir),
|
|
createFakePackage('package5', packagesDir),
|
|
createFakePackage('package6', packagesDir),
|
|
],
|
|
<RepositoryPackage>[
|
|
createFakePackage('package7', packagesDir),
|
|
createFakePackage('package8', packagesDir),
|
|
],
|
|
];
|
|
|
|
for (int i = 0; i < expectedShards.length; ++i) {
|
|
final SamplePackageCommand localCommand = SamplePackageCommand(
|
|
packagesDir,
|
|
processRunner: processRunner,
|
|
platform: mockPlatform,
|
|
gitDir: MockGitDir(),
|
|
);
|
|
final CommandRunner<void> localRunner =
|
|
CommandRunner<void>('common_command', 'Shard testing');
|
|
localRunner.addCommand(localCommand);
|
|
|
|
await runCapturingPrint(localRunner, <String>[
|
|
'sample',
|
|
'--shardIndex=$i',
|
|
'--shardCount=3',
|
|
]);
|
|
expect(
|
|
localCommand.plugins,
|
|
unorderedEquals(expectedShards[i]
|
|
.map((RepositoryPackage package) => package.path)
|
|
.toList()));
|
|
}
|
|
});
|
|
|
|
// In CI (which is the use case for sharding) we often want to run muliple
|
|
// commands on the same set of packages, but the exclusion lists for those
|
|
// commands may be different. In those cases we still want all the commands
|
|
// to operate on a consistent set of plugins.
|
|
//
|
|
// E.g., some commands require running build-examples in a previous step;
|
|
// excluding some plugins from the later step shouldn't change what's tested
|
|
// in each shard, as it may no longer align with what was built.
|
|
test('counts excluded plugins when sharding', () async {
|
|
final List<List<RepositoryPackage>> expectedShards =
|
|
<List<RepositoryPackage>>[
|
|
<RepositoryPackage>[
|
|
createFakePackage('package1', packagesDir),
|
|
createFakePackage('package2', packagesDir),
|
|
createFakePackage('package3', packagesDir),
|
|
],
|
|
<RepositoryPackage>[
|
|
createFakePackage('package4', packagesDir),
|
|
createFakePackage('package5', packagesDir),
|
|
createFakePackage('package6', packagesDir),
|
|
],
|
|
<RepositoryPackage>[
|
|
createFakePackage('package7', packagesDir),
|
|
],
|
|
];
|
|
// These would be in the last shard, but are excluded.
|
|
createFakePackage('package8', packagesDir);
|
|
createFakePackage('package9', packagesDir);
|
|
|
|
for (int i = 0; i < expectedShards.length; ++i) {
|
|
final SamplePackageCommand localCommand = SamplePackageCommand(
|
|
packagesDir,
|
|
processRunner: processRunner,
|
|
platform: mockPlatform,
|
|
gitDir: MockGitDir(),
|
|
);
|
|
final CommandRunner<void> localRunner =
|
|
CommandRunner<void>('common_command', 'Shard testing');
|
|
localRunner.addCommand(localCommand);
|
|
|
|
await runCapturingPrint(localRunner, <String>[
|
|
'sample',
|
|
'--shardIndex=$i',
|
|
'--shardCount=3',
|
|
'--exclude=package8,package9',
|
|
]);
|
|
expect(
|
|
localCommand.plugins,
|
|
unorderedEquals(expectedShards[i]
|
|
.map((RepositoryPackage package) => package.path)
|
|
.toList()));
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
class SamplePackageCommand extends PackageCommand {
|
|
SamplePackageCommand(
|
|
super.packagesDir, {
|
|
super.processRunner,
|
|
super.platform,
|
|
super.gitDir,
|
|
this.includeSubpackages = false,
|
|
});
|
|
|
|
final List<String> plugins = <String>[];
|
|
|
|
final bool includeSubpackages;
|
|
|
|
@override
|
|
final String name = 'sample';
|
|
|
|
@override
|
|
final String description = 'sample command';
|
|
|
|
@override
|
|
Future<void> run() async {
|
|
final Stream<PackageEnumerationEntry> packages = includeSubpackages
|
|
? getTargetPackagesAndSubpackages()
|
|
: getTargetPackages();
|
|
await for (final PackageEnumerationEntry entry in packages) {
|
|
plugins.add(entry.package.path);
|
|
}
|
|
}
|
|
}
|