Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 6 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
56 changes: 33 additions & 23 deletions .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ only_if: $CIRRUS_TAG == ''
env:
CHANNEL: "master" # Default to master when not explicitly set by a task.
PLUGIN_TOOL: "./script/tool/bin/flutter_plugin_tools.dart"
# The base command flags for most tool invocations, handling:
# - running the correct set of packages for the current branch
# - including any sharding that is configured for a task via $PLUGIN_SHARDING
COMMON_TOOL_FLAGS: --packages-for-branch $PLUGIN_SHARDING

tool_setup_template: &TOOL_SETUP_TEMPLATE
tool_setup_script:
Expand Down Expand Up @@ -68,19 +72,19 @@ task:
- cd script/tool
- CIRRUS_BUILD_ID=null pub run test
- name: publishable
version_check_script: ./script/tool_runner.sh version-check
publish_check_script: ./script/tool_runner.sh publish-check
version_check_script: dart $PLUGIN_TOOL version-check $COMMON_TOOL_FLAGS
publish_check_script: dart $PLUGIN_TOOL publish-check $COMMON_TOOL_FLAGS
- name: format
format_script: ./script/tool_runner.sh format --fail-on-change
pubspec_script: ./script/tool_runner.sh pubspec-check
format_script: dart $PLUGIN_TOOL format --fail-on-change $COMMON_TOOL_FLAGS
pubspec_script: dart $PLUGIN_TOOL pubspec-check $COMMON_TOOL_FLAGS
license_script: dart $PLUGIN_TOOL license-check
- name: test
env:
matrix:
CHANNEL: "master"
CHANNEL: "stable"
test_script:
- ./script/tool_runner.sh test
- dart $PLUGIN_TOOL test $COMMON_TOOL_FLAGS
- name: analyze
env:
matrix:
Expand All @@ -90,8 +94,12 @@ task:
- cd script/tool
- dart analyze --fatal-infos
script:
# DO NOT change the custom-analysis argument here without changing the Dart repo.
# DO NOT change anything about this command without changing the
# dart-lang/sdk and flutter/flutter repositories first.
# See the comment in script/configs/custom_analysis.yaml for details.
# This deliberately still uses tool_runner.sh to ensure that changes
# that would cause this command to fail show up here, not in the other
# repositories.
- ./script/tool_runner.sh analyze --custom-analysis=script/configs/custom_analysis.yaml
### Android tasks ###
- name: build_all_plugins_apk
Expand Down Expand Up @@ -126,9 +134,9 @@ task:
CHANNEL: "stable"
build_script:
- flutter config --enable-linux-desktop
- ./script/tool_runner.sh build-examples --linux
- dart $PLUGIN_TOOL build-examples --linux $COMMON_TOOL_FLAGS
drive_script:
- xvfb-run ./script/tool_runner.sh drive-examples --linux
- xvfb-run dart $PLUGIN_TOOL drive-examples --linux $COMMON_TOOL_FLAGS

# Heavy-workload Linux tasks.
# These use machines with more CPUs and memory, so will reduce parallelization
Expand Down Expand Up @@ -164,14 +172,15 @@ task:
# TODO(stuartmorgan): See https://github.com/flutter/flutter/issues/24935
- export CIRRUS_CHANGE_MESSAGE=""
- export CIRRUS_COMMIT_MESSAGE=""
- ./script/tool_runner.sh build-examples --apk
- dart $PLUGIN_TOOL build-examples --apk $COMMON_TOOL_FLAGS
lint_script:
# Unsetting CIRRUS_CHANGE_MESSAGE and CIRRUS_COMMIT_MESSAGE as they
# might include non-ASCII characters which makes Gradle crash.
# TODO(stuartmorgan): See https://github.com/flutter/flutter/issues/24935
- export CIRRUS_CHANGE_MESSAGE=""
- export CIRRUS_COMMIT_MESSAGE=""
- ./script/tool_runner.sh lint-android # must come after build-examples
# Must come after build-examples.
- dart $PLUGIN_TOOL lint-android $COMMON_TOOL_FLAGS
native_unit_test_script:
# Unsetting CIRRUS_CHANGE_MESSAGE and CIRRUS_COMMIT_MESSAGE as they
# might include non-ASCII characters which makes Gradle crash.
Expand All @@ -180,7 +189,8 @@ task:
- export CIRRUS_COMMIT_MESSAGE=""
# Native integration tests are handled by firebase-test-lab below, so
# only run unit tests.
- ./script/tool_runner.sh native-test --android --no-integration # must come after apk build
# Must come after build-examples.
- dart $PLUGIN_TOOL native-test --android --no-integration $COMMON_TOOL_FLAGS
firebase_test_lab_script:
# Unsetting CIRRUS_CHANGE_MESSAGE and CIRRUS_COMMIT_MESSAGE as they
# might include non-ASCII characters which makes Gradle crash.
Expand All @@ -189,7 +199,7 @@ task:
- export CIRRUS_COMMIT_MESSAGE=""
- if [[ -n "$GCLOUD_FIREBASE_TESTLAB_KEY" ]]; then
- echo $GCLOUD_FIREBASE_TESTLAB_KEY > ${HOME}/gcloud-service-key.json
- ./script/tool_runner.sh firebase-test-lab --device model=flame,version=29 --device model=starqlteue,version=26 --exclude=script/configs/exclude_integration_android.yaml
- dart $PLUGIN_TOOL firebase-test-lab --device model=flame,version=29 --device model=starqlteue,version=26 --exclude=script/configs/exclude_integration_android.yaml $COMMON_TOOL_FLAGS
- else
- echo "This user does not have permission to run Firebase Test Lab tests."
- fi
Expand All @@ -212,9 +222,9 @@ task:
- dart lib/web_driver_installer.dart chromedriver --install-only
- ./chromedriver/chromedriver --port=4444 &
build_script:
- ./script/tool_runner.sh build-examples --web
- dart $PLUGIN_TOOL build-examples --web $COMMON_TOOL_FLAGS
drive_script:
- ./script/tool_runner.sh drive-examples --web --exclude=script/configs/exclude_integration_web.yaml
- dart $PLUGIN_TOOL drive-examples --web --exclude=script/configs/exclude_integration_web.yaml $COMMON_TOOL_FLAGS

# macOS tasks.
task:
Expand All @@ -224,7 +234,7 @@ task:
### iOS+macOS tasks ***
- name: lint_darwin_plugins
script:
- ./script/tool_runner.sh podspecs
- dart $PLUGIN_TOOL podspecs $COMMON_TOOL_FLAGS
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is really an improvement because now we've introduced the risk of someone forgetting COMMON_TOOL_FLAGS. I looked at the cirrus documentation and it doesn't look like you could make a function like $RUN_PLUGIN_TOOL(podspecs).

If you made the command being run not have to be positional with the presence of a new flag you could extract RUN_PLUGIN_TOOL=dart $PLUGIN_TOOL $COMMON_TOOL_FLAGS --command

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is really an improvement because now we've introduced the risk of someone forgetting COMMON_TOOL_FLAGS.

Yes, I went back and forth on this for the same reason, and didn't see a good solution. The main benefit is that it eliminates the strange setup where tool_runner.sh is reading a magic env variable, and .cirrus.yml sets the magic variable, but it's totally non-obvious in each one in isolation what this variable is.

But I'll just revert this part for now and revisit it later.

If you made the command being run not have to be positional with the presence of a new flag you could extract RUN_PLUGIN_TOOL=dart $PLUGIN_TOOL $COMMON_TOOL_FLAGS --command

I looked into this a bit, and AFAICT allowing flags to be before the command with CommandRunner requires declaring them at different level that has totally different (and much more awkward) affordances for reading the flags. I can probably move just this one flag as a hack, but it seems ugly. Maybe I'll find a better solution when revisiting.

### iOS tasks ###
- name: build_all_plugins_ipa
env:
Expand All @@ -249,16 +259,16 @@ task:
- xcrun simctl list
- xcrun simctl create Flutter-iPhone com.apple.CoreSimulator.SimDeviceType.iPhone-11 com.apple.CoreSimulator.SimRuntime.iOS-14-5 | xargs xcrun simctl boot
build_script:
- ./script/tool_runner.sh build-examples --ios
- dart $PLUGIN_TOOL build-examples --ios $COMMON_TOOL_FLAGS
xcode_analyze_script:
- ./script/tool_runner.sh xcode-analyze --ios
- dart $PLUGIN_TOOL xcode-analyze --ios $COMMON_TOOL_FLAGS
native_test_script:
- ./script/tool_runner.sh native-test --ios --ios-destination "platform=iOS Simulator,name=iPhone 11,OS=latest"
- dart $PLUGIN_TOOL native-test --ios --ios-destination "platform=iOS Simulator,name=iPhone 11,OS=latest" $COMMON_TOOL_FLAGS
drive_script:
# `drive-examples` contains integration tests, which changes the UI of the application.
# This UI change sometimes affects `xctest`.
# So we run `drive-examples` after `native-test`; changing the order will result ci failure.
- ./script/tool_runner.sh drive-examples --ios --exclude=script/configs/exclude_integration_ios.yaml
- dart $PLUGIN_TOOL drive-examples --ios --exclude=script/configs/exclude_integration_ios.yaml $COMMON_TOOL_FLAGS
### macOS desktop tasks ###
- name: build_all_plugins_macos
env:
Expand All @@ -277,10 +287,10 @@ task:
PATH: $PATH:/usr/local/bin
build_script:
- flutter config --enable-macos-desktop
- ./script/tool_runner.sh build-examples --macos
- dart $PLUGIN_TOOL build-examples --macos $COMMON_TOOL_FLAGS
xcode_analyze_script:
- ./script/tool_runner.sh xcode-analyze --macos
- dart $PLUGIN_TOOL xcode-analyze --macos $COMMON_TOOL_FLAGS
native_test_script:
- ./script/tool_runner.sh native-test --macos --exclude=script/configs/exclude_native_macos.yaml
- dart $PLUGIN_TOOL native-test --macos --exclude=script/configs/exclude_native_macos.yaml $COMMON_TOOL_FLAGS
drive_script:
- ./script/tool_runner.sh drive-examples --macos
- dart $PLUGIN_TOOL drive-examples --macos $COMMON_TOOL_FLAGS
6 changes: 4 additions & 2 deletions script/configs/custom_analysis.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
# from a top-level package into more specific packages in order to incrementally
# migrate a federated plugin.
#
# DO NOT move or delete this file without updating
# DO NOT move or delete this file without updating both
# https://github.com/dart-lang/sdk/blob/master/tools/bots/flutter/analyze_flutter_plugins.sh
# which references this file from source, but out-of-repo.
# and
# https://github.com/flutter/flutter/blob/master/dev/bots/test.dart
# which reference this file from source, but out-of-repo.
# Contact stuartmorgan or devoncarew for assistance if necessary.

# TODO(ecosystem): Remove everything from this list. See:
Expand Down
4 changes: 3 additions & 1 deletion script/tool/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## NEXT
## 0.6.0

- Added Android native integration test support to `native-test`.
- Added a new `android-lint` command to lint Android plugin native code.
Expand All @@ -9,6 +9,8 @@
`--no-push-flags`. Releases now always tag and push.
- **Breaking change**: `publish`'s `--package` flag has been replaced with the
`--packages` flag used by most other packages.
- **Breaking change** Passing both `--run-on-changed-packages` and `--packages`
is now an error; previously it the former would be ignored.

## 0.5.0

Expand Down
86 changes: 66 additions & 20 deletions script/tool/lib/src/common/plugin_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// 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 'dart:math';

import 'package:args/command_runner.dart';
Expand Down Expand Up @@ -72,11 +73,18 @@ abstract class PluginCommand extends Command<void> {
);
argParser.addFlag(_runOnChangedPackagesArg,
help: 'Run the command on changed packages/plugins.\n'
'If the $_packagesArg is specified, this flag is ignored.\n'
'If no packages have changed, or if there have been changes that may\n'
'affect all packages, the command runs on all packages.\n'
'The packages excluded with $_excludeArg is also excluded even if changed.\n'
'See $_kBaseSha if a custom base is needed to determine the diff.');
'See $_kBaseSha if a custom base is needed to determine the diff.\n\n'
'Cannot be combined with $_packagesArg.\n');
argParser.addFlag(_packagesForBranchArg,
help:
'This runs on all packages (equivalent to no package selection flag)\n'
'on master, and behaves like --run-on-changed-packages on any other branch.\n\n'
'Cannot be combined with $_packagesArg.\n\n'
'This is intended for use in CI.\n',
hide: true);
argParser.addOption(_kBaseSha,
help: 'The base sha used to determine git diff. \n'
'This is useful when $_runOnChangedPackagesArg is specified.\n'
Expand All @@ -89,6 +97,7 @@ abstract class PluginCommand extends Command<void> {
static const String _shardCountArg = 'shardCount';
static const String _excludeArg = 'exclude';
static const String _runOnChangedPackagesArg = 'run-on-changed-packages';
static const String _packagesForBranchArg = 'packages-for-branch';
static const String _kBaseSha = 'base-sha';

/// The directory containing the plugin packages.
Expand Down Expand Up @@ -266,15 +275,50 @@ abstract class PluginCommand extends Command<void> {
/// is a sibling of the packages directory. This is used for a small number
/// of packages in the flutter/packages repository.
Stream<PackageEnumerationEntry> _getAllPackages() async* {
final Set<String> packageSelectionFlags = <String>{
_packagesArg,
_runOnChangedPackagesArg,
_packagesForBranchArg,
};
if (packageSelectionFlags
.where((String flag) => argResults!.wasParsed(flag))
.length >
1) {
printError('Only one of --$_packagesArg, --$_runOnChangedPackagesArg, or '
'--$_packagesForBranchArg can be provided.');
throw ToolExit(exitInvalidArguments);
}

Set<String> plugins = Set<String>.from(getStringListArg(_packagesArg));

final bool runOnChangedPackages;
if (getBoolArg(_runOnChangedPackagesArg)) {
runOnChangedPackages = true;
} else if (getBoolArg(_packagesForBranchArg)) {
final String? branch = await _getBranch();
if (branch == null) {
printError('Unabled to determine branch; --$_packagesForBranchArg can '
'only be used in a git repository.');
throw ToolExit(exitInvalidArguments);
} else {
runOnChangedPackages = branch != 'master';
// Log the mode for auditing what was intended to run.
print('--$_packagesForBranchArg: running on '
'${runOnChangedPackages ? 'changed' : 'all'} packages');
}
} else {
runOnChangedPackages = false;
}

final Set<String> excludedPluginNames = getExcludedPackageNames();

final bool runOnChangedPackages = getBoolArg(_runOnChangedPackagesArg);
if (plugins.isEmpty &&
runOnChangedPackages &&
!(await _changesRequireFullTest())) {
plugins = await _getChangedPackages();
if (runOnChangedPackages) {
final GitVersionFinder gitVersionFinder = await retrieveVersionFinder();
final List<String> changedFiles =
await gitVersionFinder.getChangedFiles();
if (!_changesRequireFullTest(changedFiles)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit fyi: This would be more efficient as a Stream<String> instead of Future<List<String>>.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I can change it in a follow-up. Neither the API nor the way it's being used are new in this PR, I'm just rearranging the flow a bit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, having looked at the details I'm not clear how it would be more efficient. getChangedFiles is taking the full stdout from git (the process API for the tools aren't stream-based) and splitting it by lines, giving a list. So returning a Stream instead of a List doesn't change anything there.

At this call site I need this list in two places: _changesRequireFullTest and _getChangedPackages. I can't consume the stream twice, so I would need to .toList() it here.

So the difference would be that instead of taking a List and returning it to a caller that needs a List, I would be taking a List, converting it to a Stream, and giving the stream to the caller to immediately turn back to a List. Am I missing a different way of structuring this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, if you are going to cache the result it doesn't make a difference, it's more of an academic change.

Returning a Stream is better because it allows people to process the output while it is being parsed. This is especially helpful when you are working on input from files/pipes. This also means the operation isn't memory bound and if a consumer decides to stop consuming mid-stream resources won't be wasted processing the output that happens after it stops.

It doesn't mean a lick of difference if you cache the results though so you can process it twice.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning a Stream is better because it allows people to process the output while it is being parsed. This is especially helpful when you are working on input from files/pipes.

The supply-side issue here is that the git package doesn't steam git output, it uses run and returns the full output as a String.

plugins = _getChangedPackages(changedFiles);
}
}

final Directory thirdPartyPackagesDirectory = packagesDir.parent
Expand Down Expand Up @@ -374,14 +418,10 @@ abstract class PluginCommand extends Command<void> {
return gitVersionFinder;
}

// Returns packages that have been changed relative to the git base.
Future<Set<String>> _getChangedPackages() async {
final GitVersionFinder gitVersionFinder = await retrieveVersionFinder();

final List<String> allChangedFiles =
await gitVersionFinder.getChangedFiles();
// Returns packages that have been changed given a list of changed files.
Set<String> _getChangedPackages(List<String> changedFiles) {
final Set<String> packages = <String>{};
for (final String path in allChangedFiles) {
for (final String path in changedFiles) {
final List<String> pathComponents = path.split('/');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not introduced in this change, but is it a problem we aren't using pathSeparator here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In practice it's not because this is only ever called with git output, which always uses POSIX paths. I changed this to p.posix.split and added a comment to the method saying that they must be POSIX paths as a quick improvement. (The better, more involved solution would be to use Files rather than Strings.)

final int packagesIndex =
pathComponents.indexWhere((String element) => element == 'packages');
Expand All @@ -398,11 +438,19 @@ abstract class PluginCommand extends Command<void> {
return packages;
}

Future<String?> _getBranch() async {
final io.ProcessResult branchResult = await (await gitDir).runCommand(
<String>['rev-parse', '--abbrev-ref', 'HEAD'],
throwOnError: false);
if (branchResult.exitCode != 0) {
return null;
}
return (branchResult.stdout as String).trim();
}

// Returns true if one or more files changed that have the potential to affect
// any plugin (e.g., CI script changes).
Future<bool> _changesRequireFullTest() async {
final GitVersionFinder gitVersionFinder = await retrieveVersionFinder();

bool _changesRequireFullTest(List<String> changedFiles) {
const List<String> specialFiles = <String>[
'.ci.yaml', // LUCI config.
'.cirrus.yml', // Cirrus config.
Expand All @@ -417,9 +465,7 @@ abstract class PluginCommand extends Command<void> {
// check below is done via string prefixing.
assert(specialDirectories.every((String dir) => dir.endsWith('/')));

final List<String> allChangedFiles =
await gitVersionFinder.getChangedFiles();
return allChangedFiles.any((String path) =>
return changedFiles.any((String path) =>
specialFiles.contains(path) ||
specialDirectories.any((String dir) => path.startsWith(dir)));
}
Expand Down
2 changes: 1 addition & 1 deletion script/tool/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: flutter_plugin_tools
description: Productivity utils for flutter/plugins and flutter/packages
repository: https://github.com/flutter/plugins/tree/master/script/tool
version: 0.5.0
version: 0.6.0

dependencies:
args: ^2.1.0
Expand Down
Loading