-
Notifications
You must be signed in to change notification settings - Fork 29.8k
[flutter_tools] Skip version freshness check for non-standard remotes #97202
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
fluttergithubbot
merged 7 commits into
flutter:master
from
royarg02:nonstandard-freshness-skip
Mar 22, 2022
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
bb5d51b
Skip version freshness check for non-standard remotes
royarg02 fda2c23
Tests
royarg02 864521d
Review fixes
royarg02 28c9b16
Review fixes #2
royarg02 11e71ba
Remove usage of globals.flutterGit from VersionUpstreamValidator
royarg02 15a75cd
Move flutterGit out of contructor initializer
royarg02 efb5d35
Make VersionUpstreamValidator.run return instead of throw error
royarg02 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -229,74 +229,6 @@ class UpgradeCommandRunner { | |
| } | ||
| } | ||
|
|
||
| /// Checks if the Flutter git repository is tracking a standard remote. | ||
| /// | ||
| /// A "standard remote" is one having the same url as [globals.flutterGit]. | ||
| /// The upgrade process only supports standard remotes. | ||
| /// | ||
| /// Exits tool if the tracking remote is not standard. | ||
| void verifyStandardRemote(FlutterVersion localVersion) { | ||
| // If repositoryUrl of the local version is null, exit | ||
| final String? repositoryUrl = localVersion.repositoryUrl; | ||
| if (repositoryUrl == null) { | ||
| throwToolExit( | ||
| 'Unable to upgrade Flutter: The tool could not determine the remote ' | ||
| 'upstream which is being tracked by the SDK.\n' | ||
| 'Re-install Flutter by going to $_flutterInstallDocs.' | ||
| ); | ||
| } | ||
|
|
||
| // Strip `.git` suffix before comparing the remotes | ||
| final String trackingUrl = stripDotGit(repositoryUrl); | ||
| final String flutterGitUrl = stripDotGit(globals.flutterGit); | ||
|
|
||
| // Exempt the official flutter git SSH remote from this check | ||
| if (trackingUrl == '[email protected]:flutter/flutter') { | ||
| return; | ||
| } | ||
|
|
||
| if (trackingUrl != flutterGitUrl) { | ||
| if (globals.platform.environment.containsKey('FLUTTER_GIT_URL')) { | ||
| // If `FLUTTER_GIT_URL` is set, inform the user to either remove the | ||
| // `FLUTTER_GIT_URL` environment variable or set it to the current | ||
| // tracking remote to continue. | ||
| throwToolExit( | ||
| 'Unable to upgrade Flutter: The Flutter SDK is tracking ' | ||
| '"${localVersion.repositoryUrl}" but "FLUTTER_GIT_URL" is set to ' | ||
| '"${globals.flutterGit}".\n' | ||
| 'Either remove "FLUTTER_GIT_URL" from the environment or set it to ' | ||
| '"${localVersion.repositoryUrl}", and retry. ' | ||
| 'Alternatively, re-install Flutter by going to $_flutterInstallDocs.\n' | ||
| 'If this is intentional, it is recommended to use "git" directly to ' | ||
| 'keep Flutter SDK up-to date.' | ||
| ); | ||
| } | ||
| // If `FLUTTER_GIT_URL` is unset, inform that the user has to set the | ||
| // environment variable to continue. | ||
| throwToolExit( | ||
| 'Unable to upgrade Flutter: The Flutter SDK is tracking a non-standard ' | ||
| 'remote "${localVersion.repositoryUrl}".\n' | ||
| 'Set the environment variable "FLUTTER_GIT_URL" to ' | ||
| '"${localVersion.repositoryUrl}", and retry. ' | ||
| 'Alternatively, re-install Flutter by going to $_flutterInstallDocs.\n' | ||
| 'If this is intentional, it is recommended to use "git" directly to ' | ||
| 'keep Flutter SDK up-to date.' | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| // Strips ".git" suffix from a given string, preferably an url. | ||
| // For example, changes 'https://github.com/flutter/flutter.git' to 'https://github.com/flutter/flutter'. | ||
| // URLs without ".git" suffix will remain unaffected. | ||
| String stripDotGit(String url) { | ||
| final RegExp pattern = RegExp(r'(.*)(\.git)$'); | ||
| final RegExpMatch? match = pattern.firstMatch(url); | ||
| if (match == null) { | ||
| return url; | ||
| } | ||
| return match.group(1)!; | ||
| } | ||
|
|
||
| /// Returns the remote HEAD flutter version. | ||
| /// | ||
| /// Exits tool if HEAD isn't pointing to a branch, or there is no upstream. | ||
|
|
@@ -337,7 +269,17 @@ class UpgradeCommandRunner { | |
| throwToolExit(errorString); | ||
| } | ||
| } | ||
| verifyStandardRemote(localVersion); | ||
| // At this point the current checkout should be on HEAD of a branch having | ||
| // an upstream. Check whether this upstream is "standard". | ||
| final VersionCheckError? error = VersionUpstreamValidator(version: localVersion, platform: globals.platform).run(); | ||
| if (error != null) { | ||
| throwToolExit( | ||
| 'Unable to upgrade Flutter: ' | ||
| '${error.message}\n' | ||
| 'Reinstalling Flutter may fix this issue. Visit $_flutterInstallDocs ' | ||
| 'for instructions.' | ||
| ); | ||
| } | ||
| return FlutterVersion(workingDirectory: workingDirectory, frameworkRevision: revision); | ||
| } | ||
|
|
||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ import 'base/common.dart'; | |
| import 'base/file_system.dart'; | ||
| import 'base/io.dart'; | ||
| import 'base/logger.dart'; | ||
| import 'base/platform.dart'; | ||
| import 'base/process.dart'; | ||
| import 'base/time.dart'; | ||
| import 'cache.dart'; | ||
|
|
@@ -239,11 +240,15 @@ class FlutterVersion { | |
| if (!kOfficialChannels.contains(channel)) { | ||
| return; | ||
| } | ||
| // Don't perform the update check if the tracking remote is not standard. | ||
| if (VersionUpstreamValidator(version: this, platform: globals.platform).run() != null) { | ||
| return; | ||
| } | ||
| DateTime localFrameworkCommitDate; | ||
| try { | ||
| // Don't perform the update check if fetching the latest local commit failed. | ||
| localFrameworkCommitDate = DateTime.parse(_latestGitCommitDate()); | ||
| } on VersionCheckError { | ||
| // Don't perform the update check if the version check failed. | ||
| return; | ||
| } | ||
| final DateTime? latestFlutterCommitDate = await _getLatestAvailableFlutterDate(); | ||
|
|
@@ -405,6 +410,91 @@ class FlutterVersion { | |
| } | ||
| } | ||
|
|
||
| /// Checks if the provided [version] is tracking a standard remote. | ||
| /// | ||
| /// A "standard remote" is one having the same url as(in order of precedence): | ||
| /// * The value of `FLUTTER_GIT_URL` environment variable. | ||
| /// * The HTTPS or SSH url of the Flutter repository as provided by GitHub. | ||
| /// | ||
| /// To initiate the validation check, call [run]. | ||
| /// | ||
| /// This prevents the tool to check for version freshness from the standard | ||
| /// remote but fetch updates from the upstream of current branch/channel, both | ||
| /// of which can be different. | ||
| /// | ||
| /// This also prevents unnecessary freshness check from a forked repo unless the | ||
| /// user explicitly configures the environment to do so. | ||
| class VersionUpstreamValidator { | ||
| VersionUpstreamValidator({ | ||
| required this.version, | ||
| required this.platform, | ||
| }); | ||
|
|
||
| final Platform platform; | ||
| final FlutterVersion version; | ||
|
|
||
| /// Performs the validation against the tracking remote of the [version]. | ||
| /// | ||
| /// Returns [VersionCheckError] if the tracking remote is not standard. | ||
| VersionCheckError? run(){ | ||
| final String? flutterGit = platform.environment['FLUTTER_GIT_URL']; | ||
| final String? repositoryUrl = version.repositoryUrl; | ||
|
|
||
| if (repositoryUrl == null) { | ||
| return VersionCheckError( | ||
| 'The tool could not determine the remote upstream which is being ' | ||
| 'tracked by the SDK.' | ||
| ); | ||
| } | ||
|
|
||
| // Strip `.git` suffix before comparing the remotes | ||
| final List<String> sanitizedStandardRemotes = <String>[ | ||
| if (flutterGit != null) flutterGit, | ||
| 'https://github.com/flutter/flutter.git', | ||
| '[email protected]:flutter/flutter.git', | ||
| ].map((String remote) => stripDotGit(remote)).toList(); | ||
|
|
||
| final String sanitizedRepositoryUrl = stripDotGit(repositoryUrl); | ||
|
|
||
| if (!sanitizedStandardRemotes.contains(sanitizedRepositoryUrl)) { | ||
| if (platform.environment.containsKey('FLUTTER_GIT_URL')) { | ||
| // If `FLUTTER_GIT_URL` is set, inform to either remove the | ||
| // `FLUTTER_GIT_URL` environment variable or set it to the current | ||
| // tracking remote. | ||
| return VersionCheckError( | ||
| 'The Flutter SDK is tracking "$repositoryUrl" but "FLUTTER_GIT_URL" ' | ||
| 'is set to "$flutterGit".\n' | ||
| 'Either remove "FLUTTER_GIT_URL" from the environment or set it to ' | ||
| '"$repositoryUrl". ' | ||
| 'If this is intentional, it is recommended to use "git" directly to ' | ||
| 'manage the SDK.' | ||
| ); | ||
| } | ||
| // If `FLUTTER_GIT_URL` is unset, inform to set the environment variable. | ||
| return VersionCheckError( | ||
| 'The Flutter SDK is tracking a non-standard remote "$repositoryUrl".\n' | ||
| 'Set the environment variable "FLUTTER_GIT_URL" to ' | ||
| '"$repositoryUrl". ' | ||
| 'If this is intentional, it is recommended to use "git" directly to ' | ||
| 'manage the SDK.' | ||
| ); | ||
| } | ||
| return null; | ||
| } | ||
|
|
||
| // Strips ".git" suffix from a given string, preferably an url. | ||
| // For example, changes 'https://github.com/flutter/flutter.git' to 'https://github.com/flutter/flutter'. | ||
| // URLs without ".git" suffix will remain unaffected. | ||
| static final RegExp _patternUrlDotGit = RegExp(r'(.*)(\.git)$'); | ||
| static String stripDotGit(String url) { | ||
| final RegExpMatch? match = _patternUrlDotGit.firstMatch(url); | ||
| if (match == null) { | ||
| return url; | ||
| } | ||
| return match.group(1)!; | ||
| } | ||
| } | ||
|
|
||
| /// Contains data and load/save logic pertaining to Flutter version checks. | ||
| @visibleForTesting | ||
| class VersionCheckStamp { | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -239,130 +239,6 @@ void main() { | |
| Platform: () => fakePlatform, | ||
| }); | ||
|
|
||
| group('verifyStandardRemote', () { | ||
| const String flutterStandardUrlDotGit = 'https://github.com/flutter/flutter.git'; | ||
| const String flutterNonStandardUrlDotGit = 'https://githubmirror.com/flutter/flutter.git'; | ||
| const String flutterStandardSshUrl = '[email protected]:flutter/flutter'; | ||
|
|
||
| testUsingContext('throws toolExit if repository url is null', () async { | ||
| final FakeFlutterVersion flutterVersion = FakeFlutterVersion( | ||
| channel: 'beta', | ||
| repositoryUrl: null, | ||
| ); | ||
|
|
||
| await expectLater( | ||
| () async => realCommandRunner.verifyStandardRemote(flutterVersion), | ||
| throwsToolExit(message: 'Unable to upgrade Flutter: The tool could not ' | ||
| 'determine the remote upstream which is being tracked by the SDK.\n' | ||
| 'Re-install Flutter by going to https://flutter.dev/docs/get-started/install.' | ||
| ), | ||
| ); | ||
| expect(processManager, hasNoRemainingExpectations); | ||
| }, overrides: <Type, Generator> { | ||
| ProcessManager: () => processManager, | ||
| Platform: () => fakePlatform, | ||
| }); | ||
|
|
||
| testUsingContext('does not throw toolExit at standard remote url with FLUTTER_GIT_URL unset', () async { | ||
| final FakeFlutterVersion flutterVersion = FakeFlutterVersion( | ||
| channel: 'beta', | ||
| ); | ||
| expect(() => realCommandRunner.verifyStandardRemote(flutterVersion), returnsNormally); | ||
| expect(processManager, hasNoRemainingExpectations); | ||
| }, overrides: <Type, Generator> { | ||
| ProcessManager: () => processManager, | ||
| Platform: () => fakePlatform, | ||
| }); | ||
|
|
||
| testUsingContext('throws toolExit at non-standard remote url with FLUTTER_GIT_URL unset', () async { | ||
| final FakeFlutterVersion flutterVersion = FakeFlutterVersion( | ||
| channel: 'beta', | ||
| repositoryUrl: flutterNonStandardUrlDotGit, | ||
| ); | ||
|
|
||
| await expectLater( | ||
| () async => realCommandRunner.verifyStandardRemote(flutterVersion), | ||
| throwsToolExit(message: 'Unable to upgrade Flutter: The Flutter SDK ' | ||
| 'is tracking a non-standard remote "$flutterNonStandardUrlDotGit".\n' | ||
| 'Set the environment variable "FLUTTER_GIT_URL" to ' | ||
| '"$flutterNonStandardUrlDotGit", and retry. ' | ||
| 'Alternatively, re-install Flutter by going to ' | ||
| 'https://flutter.dev/docs/get-started/install.\n' | ||
| 'If this is intentional, it is recommended to use "git" directly to ' | ||
| 'keep Flutter SDK up-to date.' | ||
| ), | ||
| ); | ||
| expect(processManager, hasNoRemainingExpectations); | ||
| }, overrides: <Type, Generator> { | ||
| ProcessManager: () => processManager, | ||
| Platform: () => fakePlatform, | ||
| }); | ||
|
|
||
| testUsingContext('does not throw toolExit at non-standard remote url with FLUTTER_GIT_URL set', () async { | ||
| final FakeFlutterVersion flutterVersion = FakeFlutterVersion( | ||
| channel: 'beta', | ||
| repositoryUrl: flutterNonStandardUrlDotGit, | ||
| ); | ||
|
|
||
| expect(() => realCommandRunner.verifyStandardRemote(flutterVersion), returnsNormally); | ||
| expect(processManager, hasNoRemainingExpectations); | ||
| }, overrides: <Type, Generator> { | ||
| ProcessManager: () => processManager, | ||
| Platform: () => fakePlatform..environment = Map<String, String>.unmodifiable(<String, String> { | ||
| 'FLUTTER_GIT_URL': flutterNonStandardUrlDotGit, | ||
| }), | ||
| }); | ||
|
|
||
| testUsingContext('throws toolExit at remote url and FLUTTER_GIT_URL set to different urls', () async { | ||
| final FakeFlutterVersion flutterVersion = FakeFlutterVersion( | ||
| channel: 'beta', | ||
| repositoryUrl: flutterNonStandardUrlDotGit, | ||
| ); | ||
|
|
||
| await expectLater( | ||
| () async => realCommandRunner.verifyStandardRemote(flutterVersion), | ||
| throwsToolExit(message: 'Unable to upgrade Flutter: The Flutter SDK ' | ||
| 'is tracking "$flutterNonStandardUrlDotGit" but "FLUTTER_GIT_URL" ' | ||
| 'is set to "$flutterStandardUrlDotGit".\n' | ||
| 'Either remove "FLUTTER_GIT_URL" from the environment or set it to ' | ||
| '"$flutterNonStandardUrlDotGit", and retry. ' | ||
| 'Alternatively, re-install Flutter by going to ' | ||
| 'https://flutter.dev/docs/get-started/install.\n' | ||
| 'If this is intentional, it is recommended to use "git" directly to ' | ||
| 'keep Flutter SDK up-to date.' | ||
| ), | ||
| ); | ||
| expect(processManager, hasNoRemainingExpectations); | ||
| }, overrides: <Type, Generator> { | ||
| ProcessManager: () => processManager, | ||
| Platform: () => fakePlatform..environment = Map<String, String>.unmodifiable(<String, String> { | ||
| 'FLUTTER_GIT_URL': flutterStandardUrlDotGit, | ||
| }), | ||
| }); | ||
|
|
||
| testUsingContext('exempts standard ssh url from check with FLUTTER_GIT_URL unset', () async { | ||
| final FakeFlutterVersion flutterVersion = FakeFlutterVersion( | ||
| channel: 'beta', | ||
| repositoryUrl: flutterStandardSshUrl, | ||
| ); | ||
|
|
||
| expect(() => realCommandRunner.verifyStandardRemote(flutterVersion), returnsNormally); | ||
| expect(processManager, hasNoRemainingExpectations); | ||
| }, overrides: <Type, Generator> { | ||
| ProcessManager: () => processManager, | ||
| Platform: () => fakePlatform, | ||
| }); | ||
|
|
||
| testUsingContext('stripDotGit removes ".git" suffix if any', () async { | ||
| expect(realCommandRunner.stripDotGit('https://github.com/flutter/flutter.git'), 'https://github.com/flutter/flutter'); | ||
| expect(realCommandRunner.stripDotGit('https://github.com/flutter/flutter'), 'https://github.com/flutter/flutter'); | ||
| expect(realCommandRunner.stripDotGit('[email protected]:flutter/flutter.git'), '[email protected]:flutter/flutter'); | ||
| expect(realCommandRunner.stripDotGit('[email protected]:flutter/flutter'), '[email protected]:flutter/flutter'); | ||
| expect(realCommandRunner.stripDotGit('https://githubmirror.com/flutter/flutter.git.git'), 'https://githubmirror.com/flutter/flutter.git'); | ||
| expect(realCommandRunner.stripDotGit('https://githubmirror.com/flutter/flutter.gitgit'), 'https://githubmirror.com/flutter/flutter.gitgit'); | ||
| }); | ||
| }); | ||
|
|
||
| testUsingContext('git exception during attemptReset throwsToolExit', () async { | ||
| const String revision = 'abc123'; | ||
| const String errorMessage = 'fatal: Could not parse object ´$revision´'; | ||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's a little unusual for the API of this method to be
voidwhile it is the responsibility of the caller to catch aVersionCheckError. Could you instead have this method returnVersionCheckError?and then in the method, instead of throwing, simply return the error.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.