Commit a66e9569 authored by Prerak Mann's avatar Prerak Mann Committed by Flutter GitHub Bot

sort channels by stability upon running flutter channel (#48427)

parent 10649ac4
......@@ -55,7 +55,7 @@ class ChannelCommand extends FlutterCommand {
// Beware: currentBranch could contain PII. See getBranchName().
final String currentChannel = FlutterVersion.instance.channel;
final String currentBranch = FlutterVersion.instance.getBranchName();
final Set<String> seenChannels = <String>{};
final Set<String> seenUnofficialChannels = <String>{};
final List<String> rawOutput = <String>[];
showAll = showAll || currentChannel != currentBranch;
......@@ -65,25 +65,7 @@ class ChannelCommand extends FlutterCommand {
<String>['git', 'branch', '-r'],
workingDirectory: Cache.flutterRoot,
mapFunction: (String line) {
if (verbose) {
rawOutput.add(line);
}
final List<String> split = line.split('/');
if (split.length < 2) {
return null;
}
final String branchName = split[1];
if (seenChannels.contains(branchName)) {
return null;
}
seenChannels.add(branchName);
if (branchName == currentBranch) {
return '* $branchName';
}
if (!branchName.startsWith('HEAD ') &&
(showAll || FlutterVersion.officialChannels.contains(branchName))) {
return ' $branchName';
}
rawOutput.add(line);
return null;
},
);
......@@ -91,6 +73,47 @@ class ChannelCommand extends FlutterCommand {
final String details = verbose ? '\n${rawOutput.join('\n')}' : '';
throwToolExit('List channels failed: $result$details', exitCode: result);
}
final List<String> officialChannels = FlutterVersion.officialChannels.toList();
final List<bool> availableChannels = List<bool>.filled(officialChannels.length, false);
for (final String line in rawOutput) {
final List<String> split = line.split('/');
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);
}
}
}
// print all available official channels in sorted manner
for (int i = 0; i < officialChannels.length; i++) {
// only print non-missing channels
if (availableChannels[i]) {
String currentIndicator = ' ';
if (officialChannels[i] == currentChannel){
currentIndicator = '*';
}
globals.printStatus('$currentIndicator ${officialChannels[i]}');
}
}
// print all remaining channels if showAll is true
if (showAll) {
for (final String branch in seenUnofficialChannels) {
if (currentBranch == branch) {
globals.printStatus('* $branch');
} else if (!branch.startsWith('HEAD ')) {
globals.printStatus(' $branch');
}
}
}
}
Future<void> _switchChannel(String branchName) {
......
......@@ -39,6 +39,7 @@ class FlutterVersion {
return !<String>['dev', 'beta', 'stable'].contains(branchName);
}
// Beware: Keep order in accordance with stability
static const Set<String> officialChannels = <String>{
'master',
'dev',
......
......@@ -46,6 +46,97 @@ void main() {
await simpleChannelTest(<String>['channel', '-v']);
});
testUsingContext('sorted by stability', () async {
final Process processAll = createMockProcess(
stdout: 'origin/beta\n'
'origin/master\n'
'origin/dev\n'
'origin/stable\n');
final Process processWithExtra = createMockProcess(
stdout: 'origin/beta\n'
'origin/master\n'
'origin/dependabot/bundler\n'
'origin/dev\n'
'origin/v1.4.5-hotfixes\n'
'origin/stable\n');
final Process processWithMissing = createMockProcess(
stdout: 'origin/beta\n'
'origin/dependabot/bundler\n'
'origin/v1.4.5-hotfixes\n'
'origin/stable\n');
final ChannelCommand command = ChannelCommand();
final CommandRunner<void> runner = createTestCommandRunner(command);
when(mockProcessManager.start(
<String>['git', 'branch', '-r'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).thenAnswer((_) => Future<Process>.value(processAll));
await runner.run(<String>['channel']);
verify(mockProcessManager.start(
<String>['git', 'branch', '-r'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).called(1);
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(FlutterVersion.officialChannels));
// clear buffer for next process
testLogger.clear();
when(mockProcessManager.start(
<String>['git', 'branch', '-r'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).thenAnswer((_) => Future<Process>.value(processWithExtra));
await runner.run(<String>['channel']);
verify(mockProcessManager.start(
<String>['git', 'branch', '-r'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).called(1);
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(FlutterVersion.officialChannels));
// clear buffer for next process
testLogger.clear();
when(mockProcessManager.start(
<String>['git', 'branch', '-r'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).thenAnswer((_) => Future<Process>.value(processWithMissing));
await runner.run(<String>['channel']);
verify(mockProcessManager.start(
<String>['git', 'branch', '-r'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).called(1);
expect(testLogger.errorText, hasLength(0));
// check if available official channels are in order of stability
int prev = -1;
int next = -1;
for (final String branch in FlutterVersion.officialChannels) {
next = testLogger.statusText.indexOf(branch);
if (next != -1) {
expect(prev < next, isTrue);
prev = next;
}
}
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
});
testUsingContext('removes duplicates', () async {
final Process process = createMockProcess(
stdout: 'origin/dev\n'
......
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