Unverified Commit 9c7a9e77 authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Give channel descriptions in `flutter channel`, use branch instead of upstream...

Give channel descriptions in `flutter channel`, use branch instead of upstream for channel name (#126936)

## How we determine the channel name

Historically, we used the current branch's upstream to figure out the current channel name. I have no idea why. I traced it back to https://github.com/flutter/flutter/pull/446/files where @abarth implement this and I reviewed that PR and left no comment on it at the time.

I think this is confusing. You can be on a branch and it tells you that your channel is different. That seems weird.

This PR changes the logic to uses the current branch as the channel name.

## How we display channels

The main reason this PR exists is to add channel descriptions to the `flutter channel` list:

```
ianh@burmese:~/dev/flutter/packages/flutter_tools$ flutter channel
Flutter channels:
  master (tip of tree, for contributors)
  main (tip of tree, follows master channel)
  beta (updated monthly, recommended for experienced users)
  stable (updated quarterly, for new users and for production app releases)
* foo_bar

Currently not on an official channel.
ianh@burmese:~/dev/flutter/packages/flutter_tools$
```

## Other changes

I made a few other changes while I was at it:

* If you're not on an official channel, we used to imply `--show-all`, but now we don't, we just show the official channels plus yours. This avoids flooding the screen in the case the user is on a weird channel and just wants to know what channel they're on.
* I made the tool more consistent about how it handles unofficial branches. Now it's always `[user branch]`.
* I slightly adjusted how unknown versions are rendered so it's clearer the version is unknown rather than just having the word "Unknown" floating in the output without context.
* Simplified some of the code.
* Made some of the tests more strict (checking all output rather than just some aspects of it).
* Changed the MockFlutterVersion to implement the FlutterVersion API more strictly.
* I made sure we escape the output to `.metadata` to avoid potential injection bugs (previously we just inlined the version and channel name verbatim with no escaping, which is super sketchy).
* Tweaked the help text for the `downgrade` command to be clearer.
* Removed some misleading text in some error messages.
* Made the `.metadata` generator consistent with the template file.
* Removed some obsolete code to do with the `dev` branch.

## Reviewer notes

I'm worried that there are implications to some of these changes that I am not aware of, so please don't assume I know what I'm doing when reviewing this code. :-)
parent 25d2f90a
......@@ -21,7 +21,7 @@ class UserMessages {
// Messages used in FlutterValidator
String flutterStatusInfo(String? channel, String? version, String os, String locale) =>
'Channel ${channel ?? 'unknown'}, ${version ?? 'Unknown'}, on $os, locale $locale';
'Channel ${channel ?? 'unknown'}, ${version ?? 'unknown version'}, on $os, locale $locale';
String flutterVersion(String version, String channel, String flutterRoot) =>
'Flutter version $version on channel $channel at $flutterRoot';
String get flutterUnknownChannel =>
......
......@@ -53,13 +53,12 @@ class ChannelCommand extends FlutterCommand {
Future<void> _listChannels({ required bool showAll, required bool verbose }) async {
// Beware: currentBranch could contain PII. See getBranchName().
final String currentChannel = globals.flutterVersion.channel;
final String currentChannel = globals.flutterVersion.channel; // limited to known branch names
assert(kOfficialChannels.contains(currentChannel) || kObsoleteBranches.containsKey(currentChannel) || currentChannel == kUserBranch, 'potential PII leak in channel name: "$currentChannel"');
final String currentBranch = globals.flutterVersion.getBranchName();
final Set<String> seenUnofficialChannels = <String>{};
final List<String> rawOutput = <String>[];
showAll = showAll || currentChannel != currentBranch;
globals.printStatus('Flutter channels:');
final int result = await globals.processUtils.stream(
<String>['git', 'branch', '-r'],
......@@ -74,8 +73,7 @@ class ChannelCommand extends FlutterCommand {
throwToolExit('List channels failed: $result$details', exitCode: result);
}
final List<String> officialChannels = kOfficialChannels.toList();
final List<bool> availableChannels = List<bool>.filled(officialChannels.length, false);
final Set<String> availableChannels = <String>{};
for (final String line in rawOutput) {
final List<String> split = line.split('/');
......@@ -84,27 +82,25 @@ class ChannelCommand extends FlutterCommand {
continue;
}
final String branch = split[1];
if (split.length > 1) {
final int index = officialChannels.indexOf(branch);
if (index != -1) { // Mark all available channels official channels from output
availableChannels[index] = true;
} else if (showAll && !seenUnofficialChannels.contains(branch)) {
// add other branches to seenUnofficialChannels if --all flag is given (to print later)
seenUnofficialChannels.add(branch);
}
if (kOfficialChannels.contains(branch)) {
availableChannels.add(branch);
} else if (showAll) {
seenUnofficialChannels.add(branch);
}
}
bool currentChannelIsOfficial = false;
// print all available official channels in sorted manner
for (int i = 0; i < officialChannels.length; i++) {
for (final String channel in kOfficialChannels) {
// only print non-missing channels
if (availableChannels[i]) {
if (availableChannels.contains(channel)) {
String currentIndicator = ' ';
if (officialChannels[i] == currentChannel) {
if (channel == currentChannel) {
currentIndicator = '*';
currentChannelIsOfficial = true;
}
globals.printStatus('$currentIndicator ${officialChannels[i]}');
globals.printStatus('$currentIndicator $channel (${kChannelDescriptions[channel]})');
}
}
......@@ -117,9 +113,12 @@ class ChannelCommand extends FlutterCommand {
globals.printStatus(' $branch');
}
}
} else if (!currentChannelIsOfficial) {
globals.printStatus('* $currentBranch');
}
if (currentChannel == 'unknown') {
if (!currentChannelIsOfficial) {
assert(currentChannel == kUserBranch, 'Current channel is "$currentChannel", which is not an official branch. (Current branch is "$currentBranch".)');
globals.printStatus('');
globals.printStatus('Currently not on an official channel.');
}
......
......@@ -407,8 +407,8 @@ abstract class CreateBase extends FlutterCommand {
'iosLanguage': iosLanguage,
'hasIosDevelopmentTeam': iosDevelopmentTeam != null && iosDevelopmentTeam.isNotEmpty,
'iosDevelopmentTeam': iosDevelopmentTeam ?? '',
'flutterRevision': globals.flutterVersion.frameworkRevision,
'flutterChannel': globals.flutterVersion.channel,
'flutterRevision': escapeYamlString(globals.flutterVersion.frameworkRevision),
'flutterChannel': escapeYamlString(globals.flutterVersion.getBranchName()), // may contain PII
'ios': ios,
'android': android,
'web': web,
......@@ -571,10 +571,11 @@ abstract class CreateBase extends FlutterCommand {
final FlutterProjectMetadata metadata = FlutterProjectMetadata.explicit(
file: metadataFile,
versionRevision: globals.flutterVersion.frameworkRevision,
versionChannel: globals.flutterVersion.channel,
versionChannel: globals.flutterVersion.getBranchName(), // may contain PII
projectType: projectType,
migrateConfig: MigrateConfig(),
logger: globals.logger);
logger: globals.logger,
);
metadata.populate(
platforms: platformsForMigrateConfig,
projectDirectory: directory,
......
......@@ -47,15 +47,15 @@ class DowngradeCommand extends FlutterCommand {
'working-directory',
hide: !verboseHelp,
help: 'Override the downgrade working directory. '
'This is only intended to enable integration testing of the tool itself.'
'This is only intended to enable integration testing of the tool itself. '
'It allows one to use the flutter tool from one checkout to downgrade a '
'different checkout.'
);
argParser.addFlag(
'prompt',
defaultsTo: true,
hide: !verboseHelp,
help: 'Show the downgrade prompt. '
'The ability to disable this using "--no-prompt" is only provided for '
'integration testing of the tool itself.'
help: 'Show the downgrade prompt.'
);
}
......@@ -99,8 +99,8 @@ class DowngradeCommand extends FlutterCommand {
final Channel? channel = getChannelForName(currentChannel);
if (channel == null) {
throwToolExit(
'Flutter is not currently on a known channel. Use "flutter channel <name>" '
'to switch to an official channel.',
'Flutter is not currently on a known channel. '
'Use "flutter channel" to switch to an official channel. '
);
}
final PersistentToolState persistentToolState = _persistentToolState!;
......@@ -153,13 +153,14 @@ class DowngradeCommand extends FlutterCommand {
} on ProcessException catch (error) {
throwToolExit(
'Unable to downgrade Flutter: The tool could not update to the version '
'$humanReadableVersion. This may be due to git not being installed or an '
'internal error. Please ensure that git is installed on your computer and '
'retry again.\nError: $error.'
'$humanReadableVersion.\n'
'Error: $error'
);
}
try {
await processUtils.run(
// The `--` bit (because it's followed by nothing) means that we don't actually change
// anything in the working tree, which avoids the need to first go into detached HEAD mode.
<String>['git', 'checkout', currentChannel, '--'],
throwOnError: true,
workingDirectory: workingDirectory,
......@@ -167,9 +168,8 @@ class DowngradeCommand extends FlutterCommand {
} on ProcessException catch (error) {
throwToolExit(
'Unable to downgrade Flutter: The tool could not switch to the channel '
'$currentChannel. This may be due to git not being installed or an '
'internal error. Please ensure that git is installed on your computer '
'and retry again.\nError: $error.'
'$currentChannel.\n'
'Error: $error'
);
}
await FlutterVersion.resetFlutterVersionFreshnessCheck();
......
......@@ -577,14 +577,14 @@ class FlutterValidator extends DoctorValidator {
ValidationMessage _getFlutterVersionMessage(String frameworkVersion, String versionChannel, String flutterRoot) {
String flutterVersionMessage = _userMessages.flutterVersion(frameworkVersion, versionChannel, flutterRoot);
// The tool sets the channel as "unknown", if the current branch is on a
// "detached HEAD" state or doesn't have an upstream, and sets the
// frameworkVersion as "0.0.0-unknown" if "git describe" on HEAD doesn't
// produce an expected format to be parsed for the frameworkVersion.
if (versionChannel != 'unknown' && frameworkVersion != '0.0.0-unknown') {
// The tool sets the channel as kUserBranch, if the current branch is on a
// "detached HEAD" state, doesn't have an upstream, or is on a user branch,
// and sets the frameworkVersion as "0.0.0-unknown" if "git describe" on
// HEAD doesn't produce an expected format to be parsed for the frameworkVersion.
if (versionChannel != kUserBranch && frameworkVersion != '0.0.0-unknown') {
return ValidationMessage(flutterVersionMessage);
}
if (versionChannel == 'unknown') {
if (versionChannel == kUserBranch) {
flutterVersionMessage = '$flutterVersionMessage\n${_userMessages.flutterUnknownChannel}';
}
if (frameworkVersion == '0.0.0-unknown') {
......
......@@ -8,6 +8,7 @@ import 'base/file_system.dart';
import 'base/logger.dart';
import 'base/utils.dart';
import 'project.dart';
import 'template.dart';
import 'version.dart';
enum FlutterProjectType implements CliEnum {
......@@ -172,11 +173,11 @@ class FlutterProjectMetadata {
# 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.
# This file should be version controlled and should not be manually edited.
version:
revision: $_versionRevision
channel: $_versionChannel
revision: ${escapeYamlString(_versionRevision ?? '')}
channel: ${escapeYamlString(_versionChannel ?? kUserBranch)}
project_type: ${projectType == null ? '' : projectType!.cliName}
${migrateConfig.getOutputFileString()}''';
......
......@@ -300,9 +300,6 @@ CustomDevicesConfig get customDevicesConfig => context.get<CustomDevicesConfig>(
PreRunValidator get preRunValidator => context.get<PreRunValidator>() ?? const NoOpPreRunValidator();
// TODO(fujino): Migrate to 'main' https://github.com/flutter/flutter/issues/95041
const String kDefaultFrameworkChannel = 'master';
// Used to build RegExp instances which can detect the VM service message.
final RegExp kVMServiceMessageRegExp = RegExp(r'The Dart VM service is listening on ((http|//)[a-zA-Z0-9:/=_\-\.\[\]]+)');
......
......@@ -375,3 +375,24 @@ String _escapeKotlinKeywords(String androidIdentifier) {
).toList();
return correctedSegments.join('.');
}
String escapeYamlString(String value) {
final StringBuffer result = StringBuffer();
result.write('"');
for (final int rune in value.runes) {
result.write(
switch (rune) {
0x00 => r'\0',
0x09 => r'\t',
0x0A => r'\n',
0x0D => r'\r',
0x22 => r'\"',
0x5C => r'\\',
< 0x20 => '\\x${rune.toRadixString(16).padLeft(2, "0")}',
_ => String.fromCharCode(rune),
}
);
}
result.write('"');
return result.toString();
}
......@@ -22,6 +22,9 @@ const String _unknownFrameworkVersion = '0.0.0-unknown';
/// See `man gitrevisions` for more information.
const String kGitTrackingUpstream = '@{upstream}';
/// Replacement name when the branch is user-specific.
const String kUserBranch = '[user-branch]';
/// This maps old branch names to the names of branches that replaced them.
///
/// For example, in 2021 we deprecated the "dev" channel and transitioned "dev"
......@@ -40,12 +43,24 @@ enum Channel {
// Beware: Keep order in accordance with stability
const Set<String> kOfficialChannels = <String>{
globals.kDefaultFrameworkChannel,
'master',
'main',
'beta',
'stable',
};
const Map<String, String> kChannelDescriptions = <String, String>{
'master': 'latest development branch, for contributors',
'main': 'latest development branch, follows master channel',
'beta': 'updated monthly, recommended for experienced users',
'stable': 'updated quarterly, for new users and for production app releases',
};
const Set<String> kDevelopmentChannels = <String>{
'master',
'main',
};
/// Retrieve a human-readable name for a given [channel].
///
/// Requires [kOfficialChannels] to be correctly ordered.
......@@ -101,16 +116,7 @@ class FlutterVersion {
String? _repositoryUrl;
String? get repositoryUrl {
final String _ = channel;
return _repositoryUrl;
}
String? _channel;
/// The channel is the upstream branch.
/// `master`, `dev`, `beta`, `stable`; or old ones, like `alpha`, `hackathon`, ...
String get channel {
String? channel = _channel;
if (channel == null) {
if (_repositoryUrl == null) {
final String gitChannel = _runGit(
'git rev-parse --abbrev-ref --symbolic $kGitTrackingUpstream',
globals.processUtils,
......@@ -124,14 +130,16 @@ class FlutterVersion {
globals.processUtils,
_workingDirectory,
);
channel = gitChannel.substring(slash + 1);
} else if (gitChannel.isEmpty) {
channel = 'unknown';
} else {
channel = gitChannel;
}
_channel = channel;
}
return _repositoryUrl;
}
/// The channel is the current branch if we recognize it, or "[user-branch]" (kUserBranch).
/// `master`, `beta`, `stable`; or old ones, like `alpha`, `hackathon`, `dev`, ...
String get channel {
final String channel = getBranchName(redactUnknownBranches: true);
assert(kOfficialChannels.contains(channel) || kObsoleteBranches.containsKey(channel) || channel == kUserBranch, 'Potential PII leak in channel name: "$channel"');
return channel;
}
......@@ -296,16 +304,16 @@ class FlutterVersion {
/// Return the branch name.
///
/// If [redactUnknownBranches] is true and the branch is unknown,
/// the branch name will be returned as `'[user-branch]'`.
/// the branch name will be returned as `'[user-branch]'` ([kUserBranch]).
String getBranchName({ bool redactUnknownBranches = false }) {
_branch ??= () {
final String branch = _runGit('git rev-parse --abbrev-ref HEAD', globals.processUtils);
return branch == 'HEAD' ? channel : branch;
final String branch = _runGit('git symbolic-ref --short HEAD', globals.processUtils, _workingDirectory);
return branch == 'HEAD' ? '' : branch;
}();
if (redactUnknownBranches || _branch!.isEmpty) {
// Only return the branch names we know about; arbitrary branch names might contain PII.
if (!kOfficialChannels.contains(_branch) && !kObsoleteBranches.containsKey(_branch)) {
return '[user-branch]';
return kUserBranch;
}
}
return _branch!;
......@@ -619,7 +627,7 @@ String _runSync(List<String> command, { bool lenient = true }) {
return '';
}
String _runGit(String command, ProcessUtils processUtils, [String? workingDirectory]) {
String _runGit(String command, ProcessUtils processUtils, String? workingDirectory) {
return processUtils.runSync(
command.split(' '),
workingDirectory: workingDirectory ?? Cache.flutterRoot,
......@@ -709,8 +717,8 @@ class GitTagVersion {
String gitRef = 'HEAD'
}) {
if (fetchTags) {
final String channel = _runGit('git rev-parse --abbrev-ref HEAD', processUtils, workingDirectory);
if (channel == 'dev' || channel == 'beta' || channel == 'stable') {
final String channel = _runGit('git symbolic-ref --short HEAD', processUtils, workingDirectory);
if (!kDevelopmentChannels.contains(channel) && kOfficialChannels.contains(channel)) {
globals.printTrace('Skipping request to fetchTags - on well known channel $channel.');
} else {
final String flutterGit = platform.environment['FLUTTER_GIT_URL'] ?? 'https://github.com/flutter/flutter.git';
......@@ -918,8 +926,6 @@ class VersionFreshnessValidator {
return const Duration(days: 365 ~/ 2); // Six months
case 'beta':
return const Duration(days: 7 * 8); // Eight weeks
case 'dev':
return const Duration(days: 7 * 4); // Four weeks
default:
return const Duration(days: 7 * 3); // Three weeks
}
......
......@@ -41,7 +41,7 @@ void main() {
});
testUsingContext('Downgrade exits on unknown channel', () async {
final FakeFlutterVersion fakeFlutterVersion = FakeFlutterVersion();
final FakeFlutterVersion fakeFlutterVersion = FakeFlutterVersion(branch: 'WestSideStory'); // an unknown branch
fileSystem.currentDirectory.childFile('.flutter_tool_state')
.writeAsStringSync('{"last-active-master-version":"invalid"}');
final DowngradeCommand command = DowngradeCommand(
......@@ -58,7 +58,7 @@ void main() {
});
testUsingContext('Downgrade exits on no recorded version', () async {
final FakeFlutterVersion fakeFlutterVersion = FakeFlutterVersion(channel: 'beta');
final FakeFlutterVersion fakeFlutterVersion = FakeFlutterVersion(branch: 'beta');
fileSystem.currentDirectory.childFile('.flutter_tool_state')
.writeAsStringSync('{"last-active-master-version":"abcd"}');
final DowngradeCommand command = DowngradeCommand(
......@@ -86,7 +86,7 @@ void main() {
});
testUsingContext('Downgrade exits on unknown recorded version', () async {
final FakeFlutterVersion fakeFlutterVersion = FakeFlutterVersion(channel: 'master');
final FakeFlutterVersion fakeFlutterVersion = FakeFlutterVersion();
fileSystem.currentDirectory.childFile('.flutter_tool_state')
.writeAsStringSync('{"last-active-master-version":"invalid"}');
final DowngradeCommand command = DowngradeCommand(
......@@ -110,7 +110,7 @@ void main() {
});
testUsingContext('Downgrade prompts for user input when terminal is attached - y', () async {
final FakeFlutterVersion fakeFlutterVersion = FakeFlutterVersion(channel: 'master');
final FakeFlutterVersion fakeFlutterVersion = FakeFlutterVersion();
stdio.hasTerminal = true;
fileSystem.currentDirectory.childFile('.flutter_tool_state')
.writeAsStringSync('{"last-active-master-version":"g6b00b5e88"}');
......@@ -131,7 +131,7 @@ void main() {
});
testUsingContext('Downgrade prompts for user input when terminal is attached - n', () async {
final FakeFlutterVersion fakeFlutterVersion = FakeFlutterVersion(channel: 'master');
final FakeFlutterVersion fakeFlutterVersion = FakeFlutterVersion();
stdio.hasTerminal = true;
fileSystem.currentDirectory.childFile('.flutter_tool_state')
.writeAsStringSync('{"last-active-master-version":"g6b00b5e88"}');
......@@ -152,7 +152,7 @@ void main() {
});
testUsingContext('Downgrade does not prompt when there is no terminal', () async {
final FakeFlutterVersion fakeFlutterVersion = FakeFlutterVersion(channel: 'master');
final FakeFlutterVersion fakeFlutterVersion = FakeFlutterVersion();
stdio.hasTerminal = false;
fileSystem.currentDirectory.childFile('.flutter_tool_state')
.writeAsStringSync('{"last-active-master-version":"g6b00b5e88"}');
......@@ -174,7 +174,7 @@ void main() {
});
testUsingContext('Downgrade performs correct git commands', () async {
final FakeFlutterVersion fakeFlutterVersion = FakeFlutterVersion(channel: 'master');
final FakeFlutterVersion fakeFlutterVersion = FakeFlutterVersion();
stdio.hasTerminal = false;
fileSystem.currentDirectory.childFile('.flutter_tool_state')
.writeAsStringSync('{"last-active-master-version":"g6b00b5e88"}');
......
......@@ -114,7 +114,7 @@ void main() {
expect(logger.statusText, contains("Transitioning from 'dev' to 'beta'..."));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
FlutterVersion: () => FakeFlutterVersion(channel: 'dev'),
FlutterVersion: () => FakeFlutterVersion(branch: 'dev'),
Logger: () => logger,
ProcessManager: () => processManager,
});
......@@ -197,7 +197,7 @@ void main() {
);
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
FlutterVersion: () => FakeFlutterVersion(channel: 'master', frameworkVersion: startingTag, engineRevision: 'engine'),
FlutterVersion: () => FakeFlutterVersion(frameworkVersion: startingTag, engineRevision: 'engine'),
Logger: () => logger,
ProcessManager: () => processManager,
});
......@@ -264,7 +264,7 @@ void main() {
);
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
FlutterVersion: () => FakeFlutterVersion(channel: 'beta', frameworkVersion: startingTag, engineRevision: 'engine'),
FlutterVersion: () => FakeFlutterVersion(branch: 'beta', frameworkVersion: startingTag, engineRevision: 'engine'),
Logger: () => logger,
ProcessManager: () => processManager,
});
......
......@@ -78,7 +78,7 @@ void main() {
projectDir = tempDir.childDirectory('flutter_project');
fakeFlutterVersion = FakeFlutterVersion(
frameworkRevision: frameworkRevision,
channel: frameworkChannel,
branch: frameworkChannel,
);
fakeProcessManager = FakeProcessManager.empty();
mockStdio = FakeStdio();
......@@ -1269,8 +1269,8 @@ void main() {
expectExists(versionPath);
final String version = globals.fs.file(globals.fs.path.join(projectDir.path, versionPath)).readAsStringSync();
expect(version, contains('version:'));
expect(version, contains('revision: 12345678'));
expect(version, contains('channel: omega'));
expect(version, contains('revision: "12345678"'));
expect(version, contains('channel: "omega"'));
// IntelliJ metadata
final String intelliJSdkMetadataPath = globals.fs.path.join('.idea', 'libraries', 'Dart_SDK.xml');
......@@ -1349,8 +1349,8 @@ void main() {
expectExists(versionPath);
final String version = globals.fs.file(globals.fs.path.join(projectDir.path, versionPath)).readAsStringSync();
expect(version, contains('version:'));
expect(version, contains('revision: 12345678'));
expect(version, contains('channel: omega'));
expect(version, contains('revision: "12345678"'));
expect(version, contains('channel: "omega"'));
// IntelliJ metadata
final String intelliJSdkMetadataPath = globals.fs.path.join('.idea', 'libraries', 'Dart_SDK.xml');
......
......@@ -46,7 +46,7 @@ void main() {
});
testUsingContext('throws on unknown tag, official branch, noforce', () async {
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel: 'beta');
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(branch: 'beta');
const String upstreamRevision = '';
final FakeFlutterVersion latestVersion = FakeFlutterVersion(frameworkRevision: upstreamRevision);
fakeCommandRunner.remoteVersion = latestVersion;
......@@ -66,7 +66,7 @@ void main() {
});
testUsingContext('throws tool exit with uncommitted changes', () async {
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel: 'beta');
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(branch: 'beta');
const String upstreamRevision = '';
final FakeFlutterVersion latestVersion = FakeFlutterVersion(frameworkRevision: upstreamRevision);
fakeCommandRunner.remoteVersion = latestVersion;
......@@ -89,7 +89,7 @@ void main() {
testUsingContext("Doesn't continue on known tag, beta branch, no force, already up-to-date", () async {
const String revision = 'abc123';
final FakeFlutterVersion latestVersion = FakeFlutterVersion(frameworkRevision: revision);
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel: 'beta', frameworkRevision: revision);
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(branch: 'beta', frameworkRevision: revision);
fakeCommandRunner.alreadyUpToDate = true;
fakeCommandRunner.remoteVersion = latestVersion;
......@@ -116,7 +116,7 @@ void main() {
const String upstreamVersion = '4.5.6';
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(
channel: 'beta',
branch: 'beta',
frameworkRevision: revision,
frameworkRevisionShort: revision,
frameworkVersion: version,
......@@ -287,7 +287,7 @@ void main() {
const String upstreamVersion = '4.5.6';
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(
channel: 'beta',
branch: 'beta',
frameworkRevision: revision,
frameworkVersion: version,
);
......@@ -348,7 +348,7 @@ void main() {
testUsingContext('does not throw on unknown tag, official branch, force', () async {
fakeCommandRunner.remoteVersion = FakeFlutterVersion(frameworkRevision: '1234');
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel: 'beta');
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(branch: 'beta');
final Future<FlutterCommandResult> result = fakeCommandRunner.runCommand(
force: true,
......@@ -366,7 +366,7 @@ void main() {
});
testUsingContext('does not throw tool exit with uncommitted changes and force', () async {
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel: 'beta');
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(branch: 'beta');
fakeCommandRunner.remoteVersion = FakeFlutterVersion(frameworkRevision: '1234');
fakeCommandRunner.willHaveUncommittedChanges = true;
......@@ -386,7 +386,7 @@ void main() {
});
testUsingContext("Doesn't throw on known tag, beta branch, no force", () async {
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel: 'beta');
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(branch: 'beta');
fakeCommandRunner.remoteVersion = FakeFlutterVersion(frameworkRevision: '1234');
final Future<FlutterCommandResult> result = fakeCommandRunner.runCommand(
......
......@@ -13,6 +13,7 @@ import 'package:flutter_tools/src/version.dart';
import '../src/common.dart';
import '../src/context.dart';
import '../src/fake_process_manager.dart';
import '../src/fakes.dart' show FakeFlutterVersion;
import '../src/test_flutter_command_runner.dart';
void main() {
......@@ -29,7 +30,16 @@ void main() {
Future<void> simpleChannelTest(List<String> args) async {
fakeProcessManager.addCommands(const <FakeCommand>[
FakeCommand(command: <String>['git', 'branch', '-r'], stdout: ' branch-1\n branch-2'),
FakeCommand(
command: <String>['git', 'branch', '-r'],
stdout:
' origin/branch-1\n'
' origin/branch-2\n'
' origin/master\n'
' origin/main\n'
' origin/stable\n'
' origin/beta',
),
]);
final ChannelCommand command = ChannelCommand();
final CommandRunner<void> runner = createTestCommandRunner(command);
......@@ -75,11 +85,13 @@ void main() {
await runner.run(<String>['channel']);
expect(fakeProcessManager, hasNoRemainingExpectations);
expect(testLogger.errorText, hasLength(0));
// format the status text for a simpler assertion.
final Iterable<String> rows = testLogger.statusText
.split('\n')
.map((String line) => line.substring(2)); // remove '* ' or ' ' from output
expect(rows, containsAllInOrder(kOfficialChannels));
expect(testLogger.statusText,
'Flutter channels:\n'
'* master (latest development branch, for contributors)\n'
' main (latest development branch, follows master channel)\n'
' beta (updated monthly, recommended for experienced users)\n'
' stable (updated quarterly, for new users and for production app releases)\n',
);
// clear buffer for next process
testLogger.clear();
......@@ -99,13 +111,14 @@ void main() {
await runner.run(<String>['channel']);
expect(fakeProcessManager, hasNoRemainingExpectations);
expect(rows, containsAllInOrder(kOfficialChannels));
expect(testLogger.errorText, hasLength(0));
// format the status text for a simpler assertion.
final Iterable<String> rows2 = testLogger.statusText
.split('\n')
.map((String line) => line.substring(2)); // remove '* ' or ' ' from output
expect(rows2, containsAllInOrder(kOfficialChannels));
expect(testLogger.statusText,
'Flutter channels:\n'
'* master (latest development branch, for contributors)\n'
' main (latest development branch, follows master channel)\n'
' beta (updated monthly, recommended for experienced users)\n'
' stable (updated quarterly, for new users and for production app releases)\n',
);
// clear buffer for next process
testLogger.clear();
......@@ -114,10 +127,11 @@ void main() {
fakeProcessManager.addCommand(
const FakeCommand(
command: <String>['git', 'branch', '-r'],
stdout: 'origin/beta\n'
stdout: 'origin/master\n'
'origin/dependabot/bundler\n'
'origin/v1.4.5-hotfixes\n'
'origin/stable\n',
'origin/stable\n'
'origin/beta\n',
),
);
......@@ -158,18 +172,45 @@ void main() {
expect(fakeProcessManager, hasNoRemainingExpectations);
expect(testLogger.errorText, hasLength(0));
expect(testLogger.statusText,
'Flutter channels:\n'
'* beta (updated monthly, recommended for experienced users)\n'
' stable (updated quarterly, for new users and for production app releases)\n'
);
}, overrides: <Type, Generator>{
ProcessManager: () => fakeProcessManager,
FileSystem: () => MemoryFileSystem.test(),
FlutterVersion: () => FakeFlutterVersion(branch: 'beta'),
});
// format the status text for a simpler assertion.
final Iterable<String> rows = testLogger.statusText
.split('\n')
.map((String line) => line.trim())
.where((String line) => line.isNotEmpty)
.skip(1); // remove `Flutter channels:` line
testUsingContext('handles custom branches', () async {
fakeProcessManager.addCommand(
const FakeCommand(
command: <String>['git', 'branch', '-r'],
stdout: 'origin/beta\n'
'origin/stable\n'
'origin/foo',
),
);
final ChannelCommand command = ChannelCommand();
final CommandRunner<void> runner = createTestCommandRunner(command);
await runner.run(<String>['channel']);
expect(rows, <String>['beta', 'stable', 'Currently not on an official channel.']);
expect(fakeProcessManager, hasNoRemainingExpectations);
expect(testLogger.errorText, hasLength(0));
expect(testLogger.statusText,
'Flutter channels:\n'
' beta (updated monthly, recommended for experienced users)\n'
' stable (updated quarterly, for new users and for production app releases)\n'
'* foo\n'
'\n'
'Currently not on an official channel.\n',
);
}, overrides: <Type, Generator>{
ProcessManager: () => fakeProcessManager,
FileSystem: () => MemoryFileSystem.test(),
FlutterVersion: () => FakeFlutterVersion(branch: 'foo'),
});
testUsingContext('removes duplicates', () async {
......@@ -189,18 +230,15 @@ void main() {
expect(fakeProcessManager, hasNoRemainingExpectations);
expect(testLogger.errorText, hasLength(0));
// format the status text for a simpler assertion.
final Iterable<String> rows = testLogger.statusText
.split('\n')
.map((String line) => line.trim())
.where((String line) => line.isNotEmpty)
.skip(1); // remove `Flutter channels:` line
expect(rows, <String>['beta', 'stable', 'Currently not on an official channel.']);
expect(testLogger.statusText,
'Flutter channels:\n'
'* beta (updated monthly, recommended for experienced users)\n'
' stable (updated quarterly, for new users and for production app releases)\n'
);
}, overrides: <Type, Generator>{
ProcessManager: () => fakeProcessManager,
FileSystem: () => MemoryFileSystem.test(),
FlutterVersion: () => FakeFlutterVersion(branch: 'beta'),
});
testUsingContext('can switch channels', () async {
......
......@@ -33,7 +33,7 @@ void main() {
FeatureFlags createFlags(String channel) {
return FlutterFeatureFlags(
flutterVersion: FakeFlutterVersion(channel: channel),
flutterVersion: FakeFlutterVersion(branch: channel),
config: testConfig,
platform: platform,
);
......
......@@ -34,7 +34,7 @@ void main() {
'downloaded and exits with code 1', () async {
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(
frameworkVersion: '1.0.0',
channel: 'beta',
branch: 'beta',
);
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
final Artifacts artifacts = Artifacts.test();
......@@ -78,7 +78,7 @@ void main() {
testWithoutContext('FlutterValidator shows an error message if Rosetta is needed', () async {
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(
frameworkVersion: '1.0.0',
channel: 'beta',
branch: 'beta',
);
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
final Artifacts artifacts = Artifacts.test();
......@@ -121,7 +121,7 @@ void main() {
testWithoutContext('FlutterValidator does not run gen_snapshot binary check if it is not already downloaded', () async {
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(
frameworkVersion: '1.0.0',
channel: 'beta',
branch: 'beta',
);
final FlutterValidator flutterValidator = FlutterValidator(
platform: FakePlatform(
......@@ -174,7 +174,7 @@ void main() {
testWithoutContext('FlutterValidator shows mirrors on pub and flutter cloud storage', () async {
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(
frameworkVersion: '1.0.0',
channel: 'beta',
branch: 'beta',
);
final Platform platform = FakePlatform(
operatingSystem: 'windows',
......@@ -218,7 +218,7 @@ void main() {
),
flutterVersion: () => FakeFlutterVersion(
frameworkVersion: '1.0.0',
channel: 'beta'
branch: 'beta'
),
devToolsVersion: () => '2.8.0',
userMessages: UserMessages(),
......@@ -247,8 +247,8 @@ void main() {
final FlutterValidator flutterValidator = FlutterValidator(
platform: FakePlatform(localeName: 'en_US.UTF-8'),
flutterVersion: () => FakeFlutterVersion(
branch: 'unknown',
frameworkVersion: '1.0.0',
// channel is unknown by default
),
devToolsVersion: () => '2.8.0',
userMessages: UserMessages(),
......@@ -261,10 +261,10 @@ void main() {
expect(await flutterValidator.validate(), _matchDoctorValidation(
validationType: ValidationType.partial,
statusInfo: 'Channel unknown, 1.0.0, on Linux, locale en_US.UTF-8',
statusInfo: 'Channel [user-branch], 1.0.0, on Linux, locale en_US.UTF-8',
messages: containsAll(<ValidationMessage>[
const ValidationMessage.hint(
'Flutter version 1.0.0 on channel unknown at /sdk/flutter\n'
'Flutter version 1.0.0 on channel [user-branch] at /sdk/flutter\n'
'Currently on an unknown channel. Run `flutter channel` to switch to an official channel.\n'
"If that doesn't fix the issue, reinstall Flutter by following instructions at https://flutter.dev/docs/get-started/install."
),
......@@ -281,7 +281,7 @@ void main() {
platform: FakePlatform(localeName: 'en_US.UTF-8'),
flutterVersion: () => FakeFlutterVersion(
frameworkVersion: '0.0.0-unknown',
channel: 'beta',
branch: 'beta',
),
devToolsVersion: () => '2.8.0',
userMessages: UserMessages(),
......@@ -315,7 +315,7 @@ void main() {
platform: FakePlatform(localeName: 'en_US.UTF-8'),
flutterVersion: () => FakeFlutterVersion(
frameworkVersion: '1.0.0',
channel: 'beta'
branch: 'beta'
),
devToolsVersion: () => '2.8.0',
userMessages: UserMessages(),
......@@ -338,7 +338,7 @@ void main() {
platform: FakePlatform(localeName: 'en_US.UTF-8'),
flutterVersion: () => FakeFlutterVersion(
frameworkVersion: '1.0.0',
channel: 'beta',
branch: 'beta',
repositoryUrl: 'https://githubmirror.com/flutter.git'
),
devToolsVersion: () => '2.8.0',
......@@ -372,7 +372,7 @@ void main() {
platform: FakePlatform(localeName: 'en_US.UTF-8'),
flutterVersion: () => FakeFlutterVersion(
frameworkVersion: '1.0.0',
channel: 'beta',
branch: 'beta',
repositoryUrl: null,
),
devToolsVersion: () => '2.8.0',
......@@ -406,7 +406,7 @@ void main() {
platform: FakePlatform(localeName: 'en_US.UTF-8'),
flutterVersion: () => FakeFlutterVersion(
frameworkVersion: '1.0.0',
channel: 'beta'
branch: 'beta'
),
devToolsVersion: () => '2.8.0',
userMessages: UserMessages(),
......@@ -435,7 +435,7 @@ void main() {
platform: FakePlatform(localeName: 'en_US.UTF-8'),
flutterVersion: () => FakeFlutterVersion(
frameworkVersion: '1.0.0',
channel: 'beta'
branch: 'beta'
),
devToolsVersion: () => '2.8.0',
userMessages: UserMessages(),
......@@ -472,7 +472,7 @@ void main() {
platform: FakePlatform(operatingSystem: 'windows', localeName: 'en_US.UTF-8'),
flutterVersion: () => FakeFlutterVersion(
frameworkVersion: '1.0.0',
channel: 'beta'
branch: 'beta'
),
devToolsVersion: () => '2.8.0',
userMessages: UserMessages(),
......@@ -513,7 +513,7 @@ void main() {
platform: FakePlatform(operatingSystem: 'windows', localeName: 'en_US.UTF-8'),
flutterVersion: () => FakeFlutterVersion(
frameworkVersion: '1.0.0',
channel: 'beta'
branch: 'beta'
),
devToolsVersion: () => '2.8.0',
userMessages: UserMessages(),
......@@ -546,7 +546,7 @@ void main() {
platform: FakePlatform(localeName: 'en_US.UTF-8'),
flutterVersion: () => FakeFlutterVersion(
frameworkVersion: '1.0.0',
channel: 'beta'
branch: 'beta'
),
devToolsVersion: () => '2.8.0',
userMessages: UserMessages(),
......@@ -580,7 +580,7 @@ void main() {
platform: FakePlatform(localeName: 'en_US.UTF-8'),
flutterVersion: () => FakeFlutterVersion(
frameworkVersion: '1.0.0',
channel: 'beta'
branch: 'beta'
),
devToolsVersion: () => '2.8.0',
userMessages: UserMessages(),
......
......@@ -194,6 +194,23 @@ void main() {
expect(logger.statusText, isEmpty);
});
});
testWithoutContext('escapeYamlString', () {
expect(escapeYamlString(''), r'""');
expect(escapeYamlString('\x00\n\r\t\b'), r'"\0\n\r\t\x08"');
expect(escapeYamlString('test'), r'"test"');
expect(escapeYamlString('test\n test'), r'"test\n test"');
expect(escapeYamlString('\x00\x01\x02\x0c\x19\xab'), r'"\0\x01\x02\x0c\x19«"');
expect(escapeYamlString('"'), r'"\""');
expect(escapeYamlString(r'\'), r'"\\"');
expect(escapeYamlString('[user branch]'), r'"[user branch]"');
expect(escapeYamlString('main'), r'"main"');
expect(escapeYamlString('TEST_BRANCH'), r'"TEST_BRANCH"');
expect(escapeYamlString(' '), r'" "');
expect(escapeYamlString(' \n '), r'" \n "');
expect(escapeYamlString('""'), r'"\"\""');
expect(escapeYamlString('"\x01\u{0263A}\u{1F642}'), r'"\"\x01☺🙂"');
});
}
class FakeTemplateRenderer extends TemplateRenderer {
......
......@@ -16,6 +16,7 @@ import 'package:test/fake.dart';
import '../src/common.dart';
import '../src/context.dart';
import '../src/fake_process_manager.dart';
import '../src/fakes.dart' show FakeFlutterVersion;
final SystemClock _testClock = SystemClock.fixed(DateTime(2015));
final DateTime _stampUpToDate = _testClock.ago(VersionFreshnessValidator.checkAgeConsideredUpToDate ~/ 2);
......@@ -67,6 +68,10 @@ void main() {
command: <String>['git', 'describe', '--match', '*.*.*', '--long', '--tags', '1234abcd'],
stdout: '0.1.2-3-1234abcd',
),
FakeCommand(
command: const <String>['git', 'symbolic-ref', '--short', 'HEAD'],
stdout: channel,
),
FakeCommand(
command: const <String>['git', 'rev-parse', '--abbrev-ref', '--symbolic', '@{upstream}'],
stdout: 'origin/$channel',
......@@ -94,10 +99,6 @@ void main() {
command: const <String>['git', '-c', 'log.showSignature=false', 'log', 'HEAD', '-n', '1', '--pretty=format:%ad', '--date=iso'],
stdout: getChannelUpToDateVersion().toString(),
),
FakeCommand(
command: const <String>['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
stdout: channel,
),
]);
final FlutterVersion flutterVersion = globals.flutterVersion;
......@@ -129,7 +130,7 @@ void main() {
});
testWithoutContext('prints nothing when Flutter installation looks out-of-date but is actually up-to-date', () async {
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel: channel);
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(branch: channel);
final BufferLogger logger = BufferLogger.test();
final VersionCheckStamp stamp = VersionCheckStamp(
lastTimeVersionWasChecked: _stampOutOfDate,
......@@ -150,7 +151,7 @@ void main() {
});
testWithoutContext('does not ping server when version stamp is up-to-date', () async {
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel: channel);
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(branch: channel);
final BufferLogger logger = BufferLogger.test();
final VersionCheckStamp stamp = VersionCheckStamp(
lastTimeVersionWasChecked: _stampUpToDate,
......@@ -172,7 +173,7 @@ void main() {
});
testWithoutContext('does not print warning if printed recently', () async {
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel: channel);
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(branch: channel);
final BufferLogger logger = BufferLogger.test();
final VersionCheckStamp stamp = VersionCheckStamp(
lastTimeVersionWasChecked: _stampUpToDate,
......@@ -194,7 +195,7 @@ void main() {
});
testWithoutContext('pings server when version stamp is missing', () async {
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel: channel);
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(branch: channel);
final BufferLogger logger = BufferLogger.test();
cache.versionStamp = '{}';
......@@ -212,7 +213,7 @@ void main() {
});
testWithoutContext('pings server when version stamp is out-of-date', () async {
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel: channel);
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(branch: channel);
final BufferLogger logger = BufferLogger.test();
final VersionCheckStamp stamp = VersionCheckStamp(
lastTimeVersionWasChecked: _stampOutOfDate,
......@@ -233,7 +234,7 @@ void main() {
});
testWithoutContext('does not print warning when unable to connect to server if not out of date', () async {
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel: channel);
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(branch: channel);
final BufferLogger logger = BufferLogger.test();
cache.versionStamp = '{}';
......@@ -250,7 +251,7 @@ void main() {
});
testWithoutContext('prints warning when unable to connect to server if really out of date', () async {
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel: channel);
final FakeFlutterVersion flutterVersion = FakeFlutterVersion(branch: channel);
final BufferLogger logger = BufferLogger.test();
final VersionCheckStamp stamp = VersionCheckStamp(
lastTimeVersionWasChecked: _stampOutOfDate,
......@@ -329,7 +330,7 @@ void main() {
if (flutterGitUrl != null) 'FLUTTER_GIT_URL': flutterGitUrl,
});
return VersionUpstreamValidator(
version: FakeFlutterVersion(repositoryUrl: versionUpstreamUrl, channel: 'master'),
version: FakeFlutterVersion(repositoryUrl: versionUpstreamUrl),
platform: testPlatform,
).run();
}
......@@ -413,17 +414,13 @@ void main() {
stdout: '0.1.2-3-1234abcd',
),
const FakeCommand(
command: <String>['git', 'rev-parse', '--abbrev-ref', '--symbolic', '@{upstream}'],
stdout: 'feature-branch',
),
const FakeCommand(
command: <String>['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
command: <String>['git', 'symbolic-ref', '--short', 'HEAD'],
stdout: 'feature-branch',
),
]);
final FlutterVersion flutterVersion = globals.flutterVersion;
expect(flutterVersion.channel, 'feature-branch');
expect(flutterVersion.channel, '[user-branch]');
expect(flutterVersion.getVersionString(), 'feature-branch/1234abcd');
expect(flutterVersion.getBranchName(), 'feature-branch');
expect(flutterVersion.getVersionString(redactUnknownBranches: true), '[user-branch]/1234abcd');
......@@ -455,7 +452,7 @@ void main() {
expect(gitTagVersion.devVersion, null);
expect(gitTagVersion.devPatch, null);
// Dev channel
// Beta channel
gitTagVersion = GitTagVersion.parse('1.2.3-4.5.pre');
expect(gitTagVersion.frameworkVersionFor(hash), '1.2.3-4.5.pre');
expect(gitTagVersion.gitTag, '1.2.3-4.5.pre');
......@@ -468,7 +465,7 @@ void main() {
expect(gitTagVersion.devVersion, null);
expect(gitTagVersion.devPatch, null);
// new tag release format, dev channel
// new tag release format, beta channel
gitTagVersion = GitTagVersion.parse('1.2.3-4.5.pre-0-g$hash');
expect(gitTagVersion.frameworkVersionFor(hash), '1.2.3-4.5.pre');
expect(gitTagVersion.gitTag, '1.2.3-4.5.pre');
......@@ -521,13 +518,13 @@ void main() {
expect(gitTagVersion.frameworkVersionFor('abcd1234'), stableTag);
});
testUsingContext('determine favors stable tag over dev tag if both identify HEAD', () {
testUsingContext('determine favors stable tag over beta tag if both identify HEAD', () {
const String stableTag = '1.2.3';
final FakeProcessManager fakeProcessManager = FakeProcessManager.list(
<FakeCommand>[
const FakeCommand(
command: <String>['git', 'tag', '--points-at', 'HEAD'],
// This tests the unlikely edge case where a dev release made it to stable without any cherry picks
// This tests the unlikely edge case where a beta release made it to stable without any cherry picks
stdout: '1.2.3-6.0.pre\n$stableTag',
),
],
......@@ -589,11 +586,11 @@ void main() {
expect(fakeProcessManager, hasNoRemainingExpectations);
});
testUsingContext('determine does not fetch tags on dev/stable/beta', () {
testUsingContext('determine does not fetch tags on beta', () {
final FakeProcessManager fakeProcessManager = FakeProcessManager.list(<FakeCommand>[
const FakeCommand(
command: <String>['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
stdout: 'dev',
command: <String>['git', 'symbolic-ref', '--short', 'HEAD'],
stdout: 'beta',
),
const FakeCommand(
command: <String>['git', 'tag', '--points-at', 'HEAD'],
......@@ -616,7 +613,7 @@ void main() {
testUsingContext('determine calls fetch --tags on master', () {
final FakeProcessManager fakeProcessManager = FakeProcessManager.list(<FakeCommand>[
const FakeCommand(
command: <String>['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
command: <String>['git', 'symbolic-ref', '--short', 'HEAD'],
stdout: 'master',
),
const FakeCommand(
......@@ -643,7 +640,7 @@ void main() {
testUsingContext('determine uses overridden git url', () {
final FakeProcessManager fakeProcessManager = FakeProcessManager.list(<FakeCommand>[
const FakeCommand(
command: <String>['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
command: <String>['git', 'symbolic-ref', '--short', 'HEAD'],
stdout: 'master',
),
const FakeCommand(
......@@ -701,13 +698,3 @@ class FakeCache extends Fake implements Cache {
}
}
}
class FakeFlutterVersion extends Fake implements FlutterVersion {
FakeFlutterVersion({required this.channel, this.repositoryUrl});
@override
final String channel;
@override
final String? repositoryUrl;
}
......@@ -11,7 +11,7 @@ import 'package:flutter_tools/src/base/terminal.dart';
import '../src/common.dart';
import 'test_utils.dart';
const String _kInitialVersion = 'v1.9.1';
const String _kInitialVersion = '3.0.0';
const String _kBranch = 'beta';
final Stdio stdio = Stdio();
......@@ -80,6 +80,7 @@ void main() {
printOnFailure('Step 4 - upgrade to the newest $_kBranch');
// This should update the persistent tool state with the sha for HEAD
// This is probably a source of flakes as it mutates system-global state.
exitCode = await processUtils.stream(<String>[
flutterBin,
'upgrade',
......@@ -93,7 +94,7 @@ void main() {
'git',
'describe',
'--match',
'v*.*.*',
'*.*.*',
'--long',
'--tags',
], workingDirectory: testDirectory.path);
......@@ -114,7 +115,7 @@ void main() {
'git',
'describe',
'--match',
'v*.*.*',
'*.*.*',
'--long',
'--tags',
], workingDirectory: testDirectory.path);
......
......@@ -324,7 +324,7 @@ class FakeBotDetector implements BotDetector {
class FakeFlutterVersion implements FlutterVersion {
FakeFlutterVersion({
this.channel = 'unknown',
this.branch = 'master',
this.dartSdkVersion = '12',
this.devToolsVersion = '2.8.0',
this.engineRevision = 'abcdefghijklmnopqrstuvwxyz',
......@@ -338,6 +338,8 @@ class FakeFlutterVersion implements FlutterVersion {
this.gitTagVersion = const GitTagVersion.unknown(),
});
final String branch;
bool get didFetchTagsAndUpdate => _didFetchTagsAndUpdate;
bool _didFetchTagsAndUpdate = false;
......@@ -345,7 +347,12 @@ class FakeFlutterVersion implements FlutterVersion {
bool _didCheckFlutterVersionFreshness = false;
@override
final String channel;
String get channel {
if (kOfficialChannels.contains(branch) || kObsoleteBranches.containsKey(branch)) {
return branch;
}
return kUserBranch;
}
@override
final String devToolsVersion;
......@@ -398,7 +405,10 @@ class FakeFlutterVersion implements FlutterVersion {
@override
String getBranchName({bool redactUnknownBranches = false}) {
return 'master';
if (!redactUnknownBranches || kOfficialChannels.contains(branch) || kObsoleteBranches.containsKey(branch)) {
return branch;
}
return kUserBranch;
}
@override
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment