MigrateConfig and migrate integration testing base#99092
MigrateConfig and migrate integration testing base#99092fluttergithubbot merged 36 commits intoflutter:masterfrom
Conversation
f48f1d5 to
cdbe0c8
Compare
There was a problem hiding this comment.
to clarify, will flutter create . include a .migrate_config file in the app's root directory?
There was a problem hiding this comment.
is there any issue with using the existing .metadata file for the root project directory, and rename .migrate_config as .metadata for the platform directories?
Migrate is adding a few entries to the dictionary, I'm not sure if we need a dedicated file.
There was a problem hiding this comment.
the existing .metadata file is being managed via templates, while the migrate_config is being managed by the MigrateConfig class. It is possible to merge the two of course, but we would also have to add it to each platform and handle the case where we need to modify it contrary to what the template would generate.
There was a problem hiding this comment.
And yes, flutter create will create the .migrate_config file in the root as well as each platform dir.
There was a problem hiding this comment.
the existing .metadata file is being managed via templates, while the migrate_config is being managed by the MigrateConfig class.
That sounds good. The .metadata file was created with these goals in mind:
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
It sounds like the use cases of .migrate_config should be covered by this file. Any thoughts?
There was a problem hiding this comment.
I agree that we shouldnt have too many metadata files. I'll see if we can merge the existing .metadata file with the .migrate_config file. Though the new version of .metadata will probably no longer be a read-only template generated file anymore.
There was a problem hiding this comment.
Here is a proposed extended .metadata file. This unifies separate config files in each platform dir to one single migrate section in the root .metadata file to remain consistent with the existing metadata tracking system. Since this file will now be owned by the tool, we can easily update the values in it as new platforms are added/edited.
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled.
version:
revision: {{flutterRevision}}
channel: {{flutterChannel}}
project_type: app
# Tracks metadata for the flutter migrate command
migrate:
platforms:
- platform: android
createRevision: fj19vkla9vnlka9vni3n808v3nch8cd
baseRevision: 93kf9v3njfa90vnidfjvn39nvi3vnie
- platform: ios
createRevision: fj19vkla9vnlka9vni3n808v3nch8cd
baseRevision: 93kf9v3njfa90vnidfjvn39nvi3vnie
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanagedFiles:
- lib/file1/etc.dart
- android/my_file.java
There was a problem hiding this comment.
the only minor comment is to maybe use a noun for consistency, so migrate -> migration
There was a problem hiding this comment.
I might go through the whole tools repo and unify references to the different platforms into a single enum. We currently have a few different ways of id-ing platforms already.
There was a problem hiding this comment.
I'd prefer an enum; if not, it doesn't seem like the String? platform arg should be nullable?
There was a problem hiding this comment.
why would a consumer of this API avoid passing the platform?
There was a problem hiding this comment.
this can be avoided if an enum is used instead. I believe Dart will enforce all cases in the enum to be handled in the switch statement. If that's not true, I've been doing too much golang on the side then :)
There was a problem hiding this comment.
this seems like a utility that belongs in FlutterProject. A method that provides all the supported platforms.
There was a problem hiding this comment.
I'll be moving this into a utility class in the next PR where I handle all of this. I'd prefer to not replicate all the error handling here temporarily as it will be removed very soon.
There was a problem hiding this comment.
projectPath sounds like the app's project path, but this is the directory where Flutter is installed
There was a problem hiding this comment.
Nope, this doc is correct. The fallback here is for when the migration config doesn't know the revision, so we try to parse it out of .metadata and other means.
There was a problem hiding this comment.
We have this, but it needs to be run on a Mac with Xcode installed.
flutter/packages/flutter_tools/lib/src/macos/cocoapods.dart
Lines 246 to 249 in 320d2cf
I'm guessing this needs to work on all platforms, like if you ran this on Windows you would still want the ios directory migrated.
A user could rename AppDelegate.swift but they likely wouldn't.
There was a problem hiding this comment.
Yes. All platform compatibility is important. I can try to include a few more fallback checks if that is something that could help with robustness.
There was a problem hiding this comment.
does it need to be in the app's directory? could it use the temp directory instead?
There was a problem hiding this comment.
The intention of this working dir is to be easily accessible and obvious. Putting it in a temp or hidden away folder makes it hard for developers to enter and work with the files inside.
There was a problem hiding this comment.
What about .migration? Some context: https://unix.stackexchange.com/a/21867
There was a problem hiding this comment.
I specifically don't want this directory hidden as it is meant to be accessed by the developer as part of the migration process. Also, just calling it migrate may not be sufficiently clear that it is meant to be modified/edited/viewed as part of migration imo.
There was a problem hiding this comment.
does the tool also support Flutter modules?
There was a problem hiding this comment.
But if the future if/when we do, it would be nice to have this already in the .gitignore to allow for better backwards compatibility.
There was a problem hiding this comment.
should this support the glob pattern? for example: lib/**/*.dart seems reasonable to me.
There was a problem hiding this comment.
Is there a lib we typically use to support this? It seems we support just simple directories and file URIs in pubspec.yaml
There was a problem hiding this comment.
is this file test data or code that runs as part of the test?
There was a problem hiding this comment.
This runs as part of the test to set up the environment/sample app.
There was a problem hiding this comment.
I was under the impression that this was test data since it's under a directory named test_data
Could it be moved to a different directory?
There was a problem hiding this comment.
This generates/gets the test fixtures, which is consistent with what the other files in this directory do.
There was a problem hiding this comment.
ok. This seems like a different pattern. Usually test data doesn't contain code that is executed to generate test data or fixtures.
There was a problem hiding this comment.
Not in the way the current project class is designed. The directory is only known once we call setUpIn(), which must be called first before any of the other getters/methods are valid. We track the appPath here because some of the getters are dynamically filled with the CIPD downloaded contents.
There was a problem hiding this comment.
Can you pull these into locals, it's used right above here:
androidPlatform: templateContext['android'] as bool ?? falseand to update the gradle properties.
There was a problem hiding this comment.
When would this need to be specified?
There was a problem hiding this comment.
This is used in the other half of the feature where create is called programmatically to create an app to diff against. We want to specify this so that the metadata around the revisions is using the app's metadata, not creating brand new metadata as a regular create run would do.
There was a problem hiding this comment.
If this only supposed to be called re-entrantly, let's make it hide: true and specify in the help text this is not supposed to be called by users.
There was a problem hiding this comment.
Turns out test/general.shard/args_test.dart: Help for command line arguments is consistently styled and complete enforces that options are not permanently hidden. The description advising not to use the flag should be sufficient.
There was a problem hiding this comment.
hide: !verboseHelp seems correct.
flutter/packages/flutter_tools/test/general.shard/args_test.dart
Lines 67 to 69 in 3e43c3e
There was a problem hiding this comment.
Instead of "revision" maybe more specific "Flutter SDK git commit hash" or something like that @christopherfujino
There was a problem hiding this comment.
Use Object? in null safe files, not dynamic.
There was a problem hiding this comment.
| unmanagedFiles: _kDefaultUnmanagedFiles[platform] != null ? _kDefaultUnmanagedFiles[platform]! : <String>[], | |
| unmanagedFiles: _kDefaultUnmanagedFiles[platform] ?? <String>[], |
There was a problem hiding this comment.
Use flutterVersion.frameworkRevision?
There was a problem hiding this comment.
Let me validate if flutterVersion.frameworkRevision always produces the form that I need.
There was a problem hiding this comment.
Changed to use FlutterVersion!
There was a problem hiding this comment.
Refactor your new code to not use the global context variables, these should all pass with testWithoutContext.
There was a problem hiding this comment.
FlutterProject in project.dart seems to be using globals.projectFactory and I'd prefer to leave this refactoring for a different PR. I've made the tests that can be context free context free.
There was a problem hiding this comment.
Gotcha, yeah do what you can, and avoid it where possible in new code. There's still a bunch of tricky ones still hanging out.
There was a problem hiding this comment.
I don't think we should be downloading cipd packages in a tools integration test. It should probably be its own test shard, with the cipd package dependency set up in the ci.yaml? @christopherfujino
There was a problem hiding this comment.
yeah, if a test requires a cipd dependency, it should be specified in the ci.yaml: https://github.com/flutter/flutter/blob/master/.ci.yaml#L174 and then the actual downloading specified in a recipe module
There was a problem hiding this comment.
The way this has to be tested requires frequent setup and teardown of a sample app, and the recipes+deps system is not designed to support this case efficiently. I would need to frequently re-get the cipd deps and the recipes gets deps once at the beginning.
I could host the vanilla sample apps somewhere else and avoid CIPD. The choice to use CIPD is to avoid having to check in entire vanilla apps as test fixtures.
There was a problem hiding this comment.
We already check in quite a few test apps, I say we just check it in. This way also if the app needs to be fixed, it's easy to find.
There was a problem hiding this comment.
I checked in a test fixture app for multidex which is a much smaller mini-app, and even that needed to get hosted files such as icon images and stuff.
The test apps required for this must be full apps, which can get quite large. Also, due to the nature of this feature, I intend to eventually branch out to test between many full apps created by different historic flutter versions. Checking in multiple full flutter apps is not sustainable, which is why I turned to hosting on cipd. I could shift the host to github if that makes more sense. I'm not sure if github will appreciate the test infra traffic though, and git makes it much harder to cherrypick individual app fixtures by version and would likely need to be in separate repos to be efficient.
There was a problem hiding this comment.
Sorry, I missed this message. I'll file a tracking issue for discussion on the approach to this.
There was a problem hiding this comment.
nit:
/// The Flutter SDK revision this platform was created by.
There was a problem hiding this comment.
nit: /// The Flutter SDK revision this platform was last migrated by.
There was a problem hiding this comment.
when would the revision be unknown?
There was a problem hiding this comment.
Legacy apps may not have this information available as it was created before we tracked it, in which case we use a fallback revision
There was a problem hiding this comment.
can this be a bit more programmatic (i.e. easier to extend)? Something like:
final validations = <String, Type>{
'platform': String,
'unmanagedFiles': YamlList,
};
bool isValid = true;
for (final entry in validations.entries) {
if (map[entry.key].runtimeType != entry.value) {
isValid = false;
logger.printError('The value of key ${entry.key} was expected to be ${entry.value} but was ${map[entry.key].runtimeType}');
break;
}
}
return isValid;| _versionYaml = versionYaml; | ||
| bool get isEmpty => platformConfigs.isEmpty && (unmanagedFiles.isEmpty || unmanagedFiles == _kDefaultUnmanagedFiles); | ||
|
|
||
| /// Parses the project for all supported platforms and populates the MigrateConfig |
There was a problem hiding this comment.
| /// Parses the project for all supported platforms and populates the MigrateConfig | |
| /// Parses the project for all supported platforms and populates the [MigrateConfig] |
| import 'dart:io'; | ||
| // import 'package:flutter_tools/src/base/io.dart'; | ||
| import 'package:file/file.dart'; | ||
| // import 'package:flutter_tools/src/globals.dart' as globals; |
There was a problem hiding this comment.
are these commented out intentionally?
zanderso
left a comment
There was a problem hiding this comment.
Out of courtesy to the reviewers, please give a gentle ping when a final pass to give lgtm is needed. In particular, I'd like to see an lgtm from @christopherfujino on future PRs in this area that add large bits of new functionality to the tool, in particular #100284.
| await processManager.run(<String>[ | ||
| 'git', | ||
| 'clone', | ||
| 'https://chromium.googlesource.com/chromium/tools/depot_tools', |
There was a problem hiding this comment.
DBC
This should be pinned, and it should do a shallow clone.
There was a problem hiding this comment.
For context: #100254
We already have infrastructure for downloading CIPD artifacts for tests
This PR is a subset of #95708
This adds MigrateConfig, which handles tracking migration metadata by writing a
.migrate_configfile in each platform directory.Each migrate config file tracks the initial create revision, base revision (revision that the app was last successfully migrated with), the platform the file is addressing, and a list of files and directories that should be unmanaged by the migration tool.
This PR also adds the core migrate_project.dart to enable integration testing of the tool. The testing framework downloads copies of fully generated apps off of CIPD.
Resolves #95360