flutter/flutter 1.17.0-dev.3.1 cherrypicks (#54131)

* Support old and new git release tag formats (#53715)

* Improve downgrade-upgrade integration test (#53775)

* Fix diagnostics crash in profile mode (#53878)

* Prevent diagnostics crash in profile mode

* Prevent diagnostics crash in profile mode

Co-authored-by: Christopher Fujino <christopherfujino@gmail.com>
Co-authored-by: Ferhat <ferhat@gmail.com>
diff --git a/packages/flutter/lib/src/foundation/diagnostics.dart b/packages/flutter/lib/src/foundation/diagnostics.dart
index 444ec3a..a0c76d9 100644
--- a/packages/flutter/lib/src/foundation/diagnostics.dart
+++ b/packages/flutter/lib/src/foundation/diagnostics.dart
@@ -2937,10 +2937,10 @@
   }
 
   @override
-  String get emptyBodyDescription => kReleaseMode ? '' : builder.emptyBodyDescription;
+  String get emptyBodyDescription => (kReleaseMode || kProfileMode) ? '' : builder.emptyBodyDescription;
 
   @override
-  List<DiagnosticsNode> getProperties() => kReleaseMode ? const <DiagnosticsNode>[] : builder.properties;
+  List<DiagnosticsNode> getProperties() => (kReleaseMode || kProfileMode) ? const <DiagnosticsNode>[] : builder.properties;
 
   @override
   List<DiagnosticsNode> getChildren() {
diff --git a/packages/flutter_tools/lib/src/commands/upgrade.dart b/packages/flutter_tools/lib/src/commands/upgrade.dart
index 021c5d7..3d11dcb 100644
--- a/packages/flutter_tools/lib/src/commands/upgrade.dart
+++ b/packages/flutter_tools/lib/src/commands/upgrade.dart
@@ -131,7 +131,6 @@
       );
     }
     recordState(flutterVersion);
-    await resetChanges(gitTagVersion);
     await upgradeChannel(flutterVersion);
     final bool alreadyUpToDate = await attemptFastForward(flutterVersion);
     if (alreadyUpToDate) {
@@ -219,34 +218,6 @@
     }
   }
 
-  /// Attempts to reset to the last non-hotfix tag.
-  ///
-  /// If the git history is on a hotfix, doing a fast forward will not pick up
-  /// major or minor version upgrades. By resetting to the point before the
-  /// hotfix, doing a git fast forward should succeed.
-  Future<void> resetChanges(GitTagVersion gitTagVersion) async {
-    String tag;
-    if (gitTagVersion == const GitTagVersion.unknown()) {
-      tag = 'v0.0.0';
-    } else {
-      tag = 'v${gitTagVersion.x}.${gitTagVersion.y}.${gitTagVersion.z}';
-    }
-    try {
-      await processUtils.run(
-        <String>['git', 'reset', '--hard', tag],
-        throwOnError: true,
-        workingDirectory: workingDirectory,
-      );
-    } on ProcessException catch (error) {
-      throwToolExit(
-        'Unable to upgrade Flutter: The tool could not update to the version $tag. '
-        '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.'
-      );
-    }
-  }
-
   /// Attempts to upgrade the channel.
   ///
   /// If the user is on a deprecated channel, attempts to migrate them off of
diff --git a/packages/flutter_tools/lib/src/commands/version.dart b/packages/flutter_tools/lib/src/commands/version.dart
index 6282698..6727a46 100644
--- a/packages/flutter_tools/lib/src/commands/version.dart
+++ b/packages/flutter_tools/lib/src/commands/version.dart
@@ -45,14 +45,14 @@
     RunResult runResult;
     try {
       runResult = await processUtils.run(
-        <String>['git', 'tag', '-l', 'v*', '--sort=-creatordate'],
+        <String>['git', 'tag', '-l', '*.*.*', '--sort=-creatordate'],
         throwOnError: true,
         workingDirectory: Cache.flutterRoot,
       );
     } on ProcessException catch (error) {
       throwToolExit(
         'Unable to get the tags. '
-        'This might be due to git not being installed or an internal error'
+        'This is likely due to an internal git error.'
         '\nError: $error.'
       );
     }
@@ -88,8 +88,14 @@
     }
 
     final String version = argResults.rest[0].replaceFirst('v', '');
-    if (!tags.contains('v$version')) {
+    final List<String> matchingTags = tags.where((String tag) => tag.contains(version)).toList();
+    String matchingTag;
+    // TODO(fujino): make this a tool exit and fix tests
+    if (matchingTags.isEmpty) {
       globals.printError('There is no version: $version');
+      matchingTag = version;
+    } else {
+      matchingTag = matchingTags.first.trim();
     }
 
     // check min supported version
@@ -113,7 +119,7 @@
 
     try {
       await processUtils.run(
-        <String>['git', 'checkout', 'v$version'],
+        <String>['git', 'checkout', matchingTag],
         throwOnError: true,
         workingDirectory: Cache.flutterRoot,
       );
diff --git a/packages/flutter_tools/lib/src/version.dart b/packages/flutter_tools/lib/src/version.dart
index 85e4fd7..fa899e1 100644
--- a/packages/flutter_tools/lib/src/version.dart
+++ b/packages/flutter_tools/lib/src/version.dart
@@ -692,14 +692,26 @@
   return revision.length > 10 ? revision.substring(0, 10) : revision;
 }
 
+/// Version of Flutter SDK parsed from git
 class GitTagVersion {
-  const GitTagVersion(this.x, this.y, this.z, this.hotfix, this.commits, this.hash);
+  const GitTagVersion({
+    this.x,
+    this.y,
+    this.z,
+    this.hotfix,
+    this.devVersion,
+    this.devPatch,
+    this.commits,
+    this.hash,
+  });
   const GitTagVersion.unknown()
     : x = null,
       y = null,
       z = null,
       hotfix = null,
       commits = 0,
+      devVersion = null,
+      devPatch = null,
       hash = '';
 
   /// The X in vX.Y.Z.
@@ -720,6 +732,12 @@
   /// The git hash (or an abbreviation thereof) for this commit.
   final String hash;
 
+  /// The N in X.Y.Z-dev.N.M
+  final int devVersion;
+
+  /// The M in X.Y.Z-dev.N.M
+  final int devPatch;
+
   static GitTagVersion determine(ProcessUtils processUtils, {String workingDirectory, bool fetchTags = false}) {
     if (fetchTags) {
       final String channel = _runGit('git rev-parse --abbrev-ref HEAD', processUtils, workingDirectory);
@@ -729,18 +747,73 @@
         _runGit('git fetch $_flutterGit --tags', processUtils, workingDirectory);
       }
     }
-    return parse(_runGit('git describe --match v*.*.* --first-parent --long --tags', processUtils, workingDirectory));
+    // `--match` glob must match old version tag `v1.2.3` and new `1.2.3-dev.4.5`
+    return parse(_runGit('git describe --match *.*.* --first-parent --long --tags', processUtils, workingDirectory));
   }
 
-  static GitTagVersion parse(String version) {
-    final RegExp versionPattern = RegExp(r'^v([0-9]+)\.([0-9]+)\.([0-9]+)(?:\+hotfix\.([0-9]+))?-([0-9]+)-g([a-f0-9]+)$');
+  // TODO(fujino): Deprecate this https://github.com/flutter/flutter/issues/53850
+  /// Check for the release tag format pre-v1.17.0
+  static GitTagVersion parseLegacyVersion(String version) {
+    final RegExp versionPattern = RegExp(
+      r'^v([0-9]+)\.([0-9]+)\.([0-9]+)(?:\+hotfix\.([0-9]+))?-([0-9]+)-g([a-f0-9]+)$');
+
     final List<String> parts = versionPattern.matchAsPrefix(version)?.groups(<int>[1, 2, 3, 4, 5, 6]);
     if (parts == null) {
-      globals.printTrace('Could not interpret results of "git describe": $version');
       return const GitTagVersion.unknown();
     }
     final List<int> parsedParts = parts.take(5).map<int>((String source) => source == null ? null : int.tryParse(source)).toList();
-    return GitTagVersion(parsedParts[0], parsedParts[1], parsedParts[2], parsedParts[3], parsedParts[4], parts[5]);
+    return GitTagVersion(
+      x: parsedParts[0],
+      y: parsedParts[1],
+      z: parsedParts[2],
+      hotfix: parsedParts[3],
+      commits: parsedParts[4],
+      hash: parts[5],
+    );
+  }
+
+  /// Check for the release tag format from v1.17.0 on
+  static GitTagVersion parseVersion(String version) {
+    final RegExp versionPattern = RegExp(
+      r'^([0-9]+)\.([0-9]+)\.([0-9]+)(-dev\.[0-9]+\.[0-9]+)?-([0-9]+)-g([a-f0-9]+)$');
+    final List<String> parts = versionPattern.matchAsPrefix(version)?.groups(<int>[1, 2, 3, 4, 5, 6]);
+    if (parts == null) {
+      return const GitTagVersion.unknown();
+    }
+    final List<int> parsedParts = parts.take(5).map<int>((String source) => source == null ? null : int.tryParse(source)).toList();
+    List<int> devParts = <int>[null, null];
+    if (parts[3] != null) {
+      devParts = RegExp(r'^-dev\.(\d+)\.(\d+)')
+        .matchAsPrefix(parts[3])
+        ?.groups(<int>[1, 2])
+        ?.map<int>(
+          (String source) => source == null ? null : int.tryParse(source)
+        )?.toList() ?? <int>[null, null];
+    }
+    return GitTagVersion(
+      x: parsedParts[0],
+      y: parsedParts[1],
+      z: parsedParts[2],
+      devVersion: devParts[0],
+      devPatch: devParts[1],
+      commits: parsedParts[4],
+      hash: parts[5],
+    );
+  }
+
+  static GitTagVersion parse(String version) {
+    GitTagVersion gitTagVersion;
+
+    gitTagVersion = parseLegacyVersion(version);
+    if (gitTagVersion != const GitTagVersion.unknown()) {
+      return gitTagVersion;
+    }
+    gitTagVersion = parseVersion(version);
+    if (gitTagVersion != const GitTagVersion.unknown()) {
+      return gitTagVersion;
+    }
+    globals.printTrace('Could not interpret results of "git describe": $version');
+    return const GitTagVersion.unknown();
   }
 
   String frameworkVersionFor(String revision) {
diff --git a/packages/flutter_tools/test/commands.shard/hermetic/version_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/version_test.dart
index 711c82a..cdbed86 100644
--- a/packages/flutter_tools/test/commands.shard/hermetic/version_test.dart
+++ b/packages/flutter_tools/test/commands.shard/hermetic/version_test.dart
@@ -42,7 +42,7 @@
         'version',
         '--no-pub',
       ]);
-      expect(testLogger.statusText, equals('v10.0.0\r\nv20.0.0\n'));
+      expect(testLogger.statusText, equals('v10.0.0\r\nv20.0.0\r\n30.0.0-dev.0.0\n'));
     }, overrides: <Type, Generator>{
       ProcessManager: () => MockProcessManager(),
       Stdio: () => mockStdio,
@@ -187,7 +187,7 @@
       await createTestCommandRunner(command).run(<String>[
         'version',
       ]);
-      expect(testLogger.statusText, equals('v10.0.0\r\nv20.0.0\n'));
+      expect(testLogger.statusText, equals('v10.0.0\r\nv20.0.0\r\n30.0.0-dev.0.0\n'));
     }, overrides: <Type, Generator>{
       ProcessManager: () => MockProcessManager(),
       Stdio: () => mockStdio,
@@ -236,7 +236,7 @@
       if (failGitTag) {
         return ProcessResult(0, 1, '', '');
       }
-      return ProcessResult(0, 0, 'v10.0.0\r\nv20.0.0', '');
+      return ProcessResult(0, 0, 'v10.0.0\r\nv20.0.0\r\n30.0.0-dev.0.0', '');
     }
     if (command[0] == 'git' && command[1] == 'checkout') {
       version = command[2] as String;
@@ -259,7 +259,7 @@
       return ProcessResult(0, 0, '000000000000000000000', '');
     }
     if (commandStr ==
-        'git describe --match v*.*.* --first-parent --long --tags') {
+        'git describe --match *.*.* --first-parent --long --tags') {
       if (version.isNotEmpty) {
         return ProcessResult(0, 0, '$version-0-g00000000', '');
       }
diff --git a/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart b/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart
index 8b616c4..150dc26 100644
--- a/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart
+++ b/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart
@@ -29,7 +29,14 @@
     MockProcessManager processManager;
     FakePlatform fakePlatform;
     final MockFlutterVersion flutterVersion = MockFlutterVersion();
-    const GitTagVersion gitTagVersion = GitTagVersion(1, 2, 3, 4, 5, 'asd');
+    const GitTagVersion gitTagVersion = GitTagVersion(
+      x: 1,
+      y: 2,
+      z: 3,
+      hotfix: 4,
+      commits: 5,
+      hash: 'asd',
+    );
     when(flutterVersion.channel).thenReturn('dev');
 
     setUp(() {
@@ -231,7 +238,7 @@
         fakeProcessManager = FakeProcessManager.list(<FakeCommand>[
           const FakeCommand(
             command: <String>[
-              'git', 'describe', '--match', 'v*.*.*', '--first-parent', '--long', '--tags',
+              'git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags',
             ],
             stdout: 'v1.12.16-19-gb45b676af',
           ),
@@ -337,9 +344,6 @@
   Future<bool> hasUncomittedChanges() async => willHaveUncomittedChanges;
 
   @override
-  Future<void> resetChanges(GitTagVersion gitTagVersion) async {}
-
-  @override
   Future<void> upgradeChannel(FlutterVersion flutterVersion) async {}
 
   @override
diff --git a/packages/flutter_tools/test/general.shard/runner/flutter_command_runner_test.dart b/packages/flutter_tools/test/general.shard/runner/flutter_command_runner_test.dart
index 476f245..3779ff8 100644
--- a/packages/flutter_tools/test/general.shard/runner/flutter_command_runner_test.dart
+++ b/packages/flutter_tools/test/general.shard/runner/flutter_command_runner_test.dart
@@ -179,7 +179,7 @@
           workingDirectory: Cache.flutterRoot)).thenReturn(result);
         when(processManager.runSync('git fetch https://github.com/flutter/flutter.git --tags'.split(' '),
           workingDirectory: Cache.flutterRoot)).thenReturn(result);
-        when(processManager.runSync('git describe --match v*.*.* --first-parent --long --tags'.split(' '),
+        when(processManager.runSync('git describe --match *.*.* --first-parent --long --tags'.split(' '),
           workingDirectory: Cache.flutterRoot)).thenReturn(result);
         when(processManager.runSync(FlutterVersion.gitLog('-n 1 --pretty=format:%ad --date=iso'.split(' ')),
           workingDirectory: Cache.flutterRoot)).thenReturn(result);
diff --git a/packages/flutter_tools/test/general.shard/version_test.dart b/packages/flutter_tools/test/general.shard/version_test.dart
index 2a71c5e..83e8cab 100644
--- a/packages/flutter_tools/test/general.shard/version_test.dart
+++ b/packages/flutter_tools/test/general.shard/version_test.dart
@@ -392,24 +392,44 @@
 
   testUsingContext('GitTagVersion', () {
     const String hash = 'abcdef';
-    expect(GitTagVersion.parse('v1.2.3-4-g$hash').frameworkVersionFor(hash), '1.2.4-pre.4');
-    expect(GitTagVersion.parse('v98.76.54-32-g$hash').frameworkVersionFor(hash), '98.76.55-pre.32');
-    expect(GitTagVersion.parse('v10.20.30-0-g$hash').frameworkVersionFor(hash), '10.20.30');
+    GitTagVersion gitTagVersion;
+
+    // legacy tag release format
+    gitTagVersion = GitTagVersion.parse('v1.2.3-4-g$hash');
+    expect(gitTagVersion.frameworkVersionFor(hash), '1.2.4-pre.4');
+    expect(gitTagVersion.devVersion, null);
+    expect(gitTagVersion.devPatch, null);
+
+    // new dev tag release format
+    gitTagVersion = GitTagVersion.parse('1.2.3-dev.4.5-13-g$hash');
+    expect(gitTagVersion.frameworkVersionFor(hash), '1.2.4-pre.13');
+    expect(gitTagVersion.devVersion, 4);
+    expect(gitTagVersion.devPatch, 5);
+
+    // new stable tag release format
+    gitTagVersion = GitTagVersion.parse('1.2.3-13-g$hash');
+    expect(gitTagVersion.frameworkVersionFor(hash), '1.2.4-pre.13');
+    expect(gitTagVersion.devVersion, null);
+    expect(gitTagVersion.devPatch, null);
+
+    expect(GitTagVersion.parse('98.76.54-32-g$hash').frameworkVersionFor(hash), '98.76.55-pre.32');
+    expect(GitTagVersion.parse('10.20.30-0-g$hash').frameworkVersionFor(hash), '10.20.30');
     expect(GitTagVersion.parse('v1.2.3+hotfix.1-4-g$hash').frameworkVersionFor(hash), '1.2.3+hotfix.2-pre.4');
-    expect(GitTagVersion.parse('v7.2.4+hotfix.8-0-g$hash').frameworkVersionFor(hash), '7.2.4+hotfix.8');
     expect(testLogger.traceText, '');
+    expect(GitTagVersion.parse('1.2.3+hotfix.1-4-g$hash').frameworkVersionFor(hash), '0.0.0-unknown');
     expect(GitTagVersion.parse('x1.2.3-4-g$hash').frameworkVersionFor(hash), '0.0.0-unknown');
-    expect(GitTagVersion.parse('v1.0.0-unknown-0-g$hash').frameworkVersionFor(hash), '0.0.0-unknown');
+    expect(GitTagVersion.parse('1.0.0-unknown-0-g$hash').frameworkVersionFor(hash), '0.0.0-unknown');
     expect(GitTagVersion.parse('beta-1-g$hash').frameworkVersionFor(hash), '0.0.0-unknown');
-    expect(GitTagVersion.parse('v1.2.3-4-gx$hash').frameworkVersionFor(hash), '0.0.0-unknown');
+    expect(GitTagVersion.parse('1.2.3-4-gx$hash').frameworkVersionFor(hash), '0.0.0-unknown');
     expect(testLogger.statusText, '');
     expect(testLogger.errorText, '');
     expect(
       testLogger.traceText,
+      'Could not interpret results of "git describe": 1.2.3+hotfix.1-4-gabcdef\n'
       'Could not interpret results of "git describe": x1.2.3-4-gabcdef\n'
-      'Could not interpret results of "git describe": v1.0.0-unknown-0-gabcdef\n'
+      'Could not interpret results of "git describe": 1.0.0-unknown-0-gabcdef\n'
       'Could not interpret results of "git describe": beta-1-gabcdef\n'
-      'Could not interpret results of "git describe": v1.2.3-4-gxabcdef\n',
+      'Could not interpret results of "git describe": 1.2.3-4-gxabcdef\n',
     );
   });
 
@@ -421,7 +441,7 @@
       environment: anyNamed('environment'),
     )).thenReturn(RunResult(ProcessResult(105, 0, '', ''), <String>['git', 'fetch']));
     when(processUtils.runSync(
-      <String>['git', 'describe', '--match', 'v*.*.*', '--first-parent', '--long', '--tags'],
+      <String>['git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags'],
       workingDirectory: anyNamed('workingDirectory'),
       environment: anyNamed('environment'),
     )).thenReturn(RunResult(ProcessResult(106, 0, 'v0.1.2-3-1234abcd', ''), <String>['git', 'describe']));
@@ -439,7 +459,7 @@
       environment: anyNamed('environment'),
     ));
     verify(processUtils.runSync(
-      <String>['git', 'describe', '--match', 'v*.*.*', '--first-parent', '--long', '--tags'],
+      <String>['git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags'],
       workingDirectory: anyNamed('workingDirectory'),
       environment: anyNamed('environment'),
     )).called(1);
@@ -458,7 +478,7 @@
       environment: anyNamed('environment'),
     )).thenReturn(RunResult(ProcessResult(106, 0, '', ''), <String>['git', 'fetch']));
     when(processUtils.runSync(
-      <String>['git', 'describe', '--match', 'v*.*.*', '--first-parent', '--long', '--tags'],
+      <String>['git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags'],
       workingDirectory: anyNamed('workingDirectory'),
       environment: anyNamed('environment'),
     )).thenReturn(RunResult(ProcessResult(107, 0, 'v0.1.2-3-1234abcd', ''), <String>['git', 'describe']));
@@ -476,7 +496,7 @@
       environment: anyNamed('environment'),
     ));
     verify(processUtils.runSync(
-      <String>['git', 'describe', '--match', 'v*.*.*', '--first-parent', '--long', '--tags'],
+      <String>['git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags'],
       workingDirectory: anyNamed('workingDirectory'),
       environment: anyNamed('environment'),
     )).called(1);
@@ -495,7 +515,7 @@
       environment: anyNamed('environment'),
     )).thenReturn(RunResult(ProcessResult(109, 0, '', ''), <String>['git', 'fetch']));
     when(processUtils.runSync(
-      <String>['git', 'describe', '--match', 'v*.*.*', '--first-parent', '--long', '--tags'],
+      <String>['git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags'],
       workingDirectory: anyNamed('workingDirectory'),
       environment: anyNamed('environment'),
     )).thenReturn(RunResult(ProcessResult(110, 0, 'v0.1.2-3-1234abcd', ''), <String>['git', 'describe']));
@@ -513,7 +533,7 @@
       environment: anyNamed('environment'),
     )).called(1);
     verify(processUtils.runSync(
-      <String>['git', 'describe', '--match', 'v*.*.*', '--first-parent', '--long', '--tags'],
+      <String>['git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags'],
       workingDirectory: anyNamed('workingDirectory'),
       environment: anyNamed('environment'),
     )).called(1);
@@ -634,7 +654,7 @@
     environment: anyNamed('environment'),
   )).thenReturn(ProcessResult(105, 0, '', ''));
   when(pm.runSync(
-    <String>['git', 'describe', '--match', 'v*.*.*', '--first-parent', '--long', '--tags'],
+    <String>['git', 'describe', '--match', '*.*.*', '--first-parent', '--long', '--tags'],
     workingDirectory: anyNamed('workingDirectory'),
     environment: anyNamed('environment'),
   )).thenReturn(ProcessResult(106, 0, 'v0.1.2-3-1234abcd', ''));
diff --git a/packages/flutter_tools/test/integration.shard/downgrade_upgrade_integration_test.dart b/packages/flutter_tools/test/integration.shard/downgrade_upgrade_integration_test.dart
index 353cfb8..438efc3 100644
--- a/packages/flutter_tools/test/integration.shard/downgrade_upgrade_integration_test.dart
+++ b/packages/flutter_tools/test/integration.shard/downgrade_upgrade_integration_test.dart
@@ -12,8 +12,8 @@
 
 import '../src/common.dart';
 
-const String _kInitialVersion = 'v1.9.1+hotfix.6';
-const String _kBranch = 'stable';
+const String _kInitialVersion = 'v1.9.1';
+const String _kBranch = 'dev';
 const FileSystem fileSystem = LocalFileSystem();
 const ProcessManager processManager = LocalProcessManager();
 final Stdio stdio = Stdio();
@@ -50,20 +50,25 @@
     final Directory testDirectory = parentDirectory.childDirectory('flutter');
     testDirectory.createSync(recursive: true);
 
+    int exitCode = 0;
+
     // Enable longpaths for windows integration test.
     await processManager.run(<String>[
       'git', 'config', '--system', 'core.longpaths', 'true',
     ]);
 
+    print('Step 1');
     // Step 1. Clone the dev branch of flutter into the test directory.
-    await processUtils.stream(<String>[
+    exitCode = await processUtils.stream(<String>[
       'git',
       'clone',
       'https://github.com/flutter/flutter.git',
     ], workingDirectory: parentDirectory.path, trace: true);
+    expect(exitCode, 0);
 
+    print('Step 2');
     // Step 2. Switch to the dev branch.
-    await processUtils.stream(<String>[
+    exitCode = await processUtils.stream(<String>[
       'git',
       'checkout',
       '--track',
@@ -71,23 +76,30 @@
       _kBranch,
       'origin/$_kBranch',
     ], workingDirectory: testDirectory.path, trace: true);
+    expect(exitCode, 0);
 
+    print('Step 3');
     // Step 3. Revert to a prior version.
-    await processUtils.stream(<String>[
+    exitCode = await processUtils.stream(<String>[
       'git',
       'reset',
       '--hard',
       _kInitialVersion,
     ], workingDirectory: testDirectory.path, trace: true);
+    expect(exitCode, 0);
 
-    // Step 4. Upgrade to the newest dev. This should update the persistent
+    print('Step 4');
+    // Step 4. Upgrade to the newest stable. This should update the persistent
     // tool state with the sha for v1.14.3
-    await processUtils.stream(<String>[
+    exitCode = await processUtils.stream(<String>[
       flutterBin,
       'upgrade',
+      '--verbose',
       '--working-directory=${testDirectory.path}'
     ], workingDirectory: testDirectory.path, trace: true);
+    expect(exitCode, 0);
 
+    print('Step 5');
     // Step 5. Verify that the version is different.
     final RunResult versionResult = await processUtils.run(<String>[
       'git',
@@ -100,14 +112,17 @@
     ], workingDirectory: testDirectory.path);
     expect(versionResult.stdout, isNot(contains(_kInitialVersion)));
 
+    print('Step 6');
     // Step 6. Downgrade back to initial version.
-    await processUtils.stream(<String>[
+    exitCode = await processUtils.stream(<String>[
        flutterBin,
       'downgrade',
       '--no-prompt',
       '--working-directory=${testDirectory.path}'
     ], workingDirectory: testDirectory.path, trace: true);
+    expect(exitCode, 0);
 
+    print('Step 7');
     // Step 7. Verify downgraded version matches original version.
     final RunResult oldVersionResult = await processUtils.run(<String>[
       'git',