feat(shorebird_cli): add getVersion to ShorebirdFlutter (#1073)
This commit is contained in:
+7
-1
@@ -51,8 +51,14 @@ Usage: shorebird flutter versions use <version>''');
|
||||
}
|
||||
|
||||
if (!versions.contains(version)) {
|
||||
final openIssueLink = link(
|
||||
uri: Uri.parse(
|
||||
'https://github.com/shorebirdtech/shorebird/issues/new?assignees=&labels=feature&projects=&template=feature_request.md&title=feat%3A+',
|
||||
),
|
||||
message: 'open an issue',
|
||||
);
|
||||
logger.err('''
|
||||
Version $version not found.
|
||||
Version $version not found. Please $openIssueLink to request a new version.
|
||||
Use `shorebird flutter versions list` to list available versions.''');
|
||||
return ExitCode.software.code;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'dart:io';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:scoped/scoped.dart';
|
||||
import 'package:shorebird_cli/src/git.dart';
|
||||
import 'package:shorebird_cli/src/process.dart';
|
||||
import 'package:shorebird_cli/src/shorebird_env.dart';
|
||||
|
||||
/// A reference to a [ShorebirdFlutter] instance.
|
||||
@@ -19,6 +20,7 @@ class ShorebirdFlutter {
|
||||
/// {@macro shorebird_flutter}
|
||||
const ShorebirdFlutter();
|
||||
|
||||
static const executable = 'flutter';
|
||||
static const String flutterGitUrl =
|
||||
'https://github.com/shorebirdtech/flutter.git';
|
||||
|
||||
@@ -62,6 +64,30 @@ class ShorebirdFlutter {
|
||||
return status.isEmpty;
|
||||
}
|
||||
|
||||
/// Returns the current Shorebird Flutter version.
|
||||
/// Throws a [ProcessException] if the version check fails.
|
||||
/// Returns `null` if the version check succeeds but the version cannot be
|
||||
/// parsed.
|
||||
Future<String?> getVersion() async {
|
||||
const args = ['--version'];
|
||||
final result = await process.run(executable, args, runInShell: true);
|
||||
|
||||
if (result.exitCode != 0) {
|
||||
throw ProcessException(
|
||||
executable,
|
||||
args,
|
||||
'${result.stderr}',
|
||||
result.exitCode,
|
||||
);
|
||||
}
|
||||
|
||||
final output = result.stdout.toString();
|
||||
final flutterVersionRegex = RegExp(r'Flutter (\d+.\d+.\d+)');
|
||||
final match = flutterVersionRegex.firstMatch(output);
|
||||
|
||||
return match?.group(1);
|
||||
}
|
||||
|
||||
Future<List<String>> getVersions({String? revision}) async {
|
||||
final result = await git.forEachRef(
|
||||
format: '%(refname:short)',
|
||||
|
||||
@@ -10,7 +10,7 @@ final shorebirdVersionRef = create(ShorebirdVersion.new);
|
||||
/// The [ShorebirdVersion] instance available in the current zone.
|
||||
ShorebirdVersion get shorebirdVersion => read(shorebirdVersionRef);
|
||||
|
||||
/// {@template shorebird_version_manager}
|
||||
/// {@template shorebird_version}
|
||||
/// Provides information about installed and available versions of Shorebird.
|
||||
/// {@endtemplate}
|
||||
class ShorebirdVersion {
|
||||
|
||||
+7
-1
@@ -106,11 +106,17 @@ Usage: shorebird flutter versions use <version>'''),
|
||||
runWithOverrides(command.run),
|
||||
completion(equals(ExitCode.software.code)),
|
||||
);
|
||||
final openIssueLink = link(
|
||||
uri: Uri.parse(
|
||||
'https://github.com/shorebirdtech/shorebird/issues/new?assignees=&labels=feature&projects=&template=feature_request.md&title=feat%3A+',
|
||||
),
|
||||
message: 'open an issue',
|
||||
);
|
||||
verifyInOrder([
|
||||
() => logger.progress('Fetching Flutter versions'),
|
||||
() => progress.complete(),
|
||||
() => logger.err('''
|
||||
Version $version not found.
|
||||
Version $version not found. Please $openIssueLink to request a new version.
|
||||
Use `shorebird flutter versions list` to list available versions.'''),
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:mocktail/mocktail.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:scoped/scoped.dart';
|
||||
import 'package:shorebird_cli/src/git.dart';
|
||||
import 'package:shorebird_cli/src/process.dart';
|
||||
import 'package:shorebird_cli/src/shorebird_env.dart';
|
||||
import 'package:shorebird_cli/src/shorebird_flutter.dart';
|
||||
import 'package:test/test.dart';
|
||||
@@ -13,6 +14,11 @@ class _MockGit extends Mock implements Git {}
|
||||
|
||||
class _MockShorebirdEnv extends Mock implements ShorebirdEnv {}
|
||||
|
||||
class _MockShorebirdProcess extends Mock implements ShorebirdProcess {}
|
||||
|
||||
class _MockShorebirdProcessResult extends Mock
|
||||
implements ShorebirdProcessResult {}
|
||||
|
||||
void main() {
|
||||
group(ShorebirdFlutter, () {
|
||||
const flutterRevision = 'flutter-revision';
|
||||
@@ -20,13 +26,16 @@ void main() {
|
||||
late Directory flutterDirectory;
|
||||
late Git git;
|
||||
late ShorebirdEnv shorebirdEnv;
|
||||
late ShorebirdFlutter shorebirdFlutterManager;
|
||||
late ShorebirdProcess process;
|
||||
late ShorebirdProcessResult processResult;
|
||||
late ShorebirdFlutter shorebirdFlutter;
|
||||
|
||||
R runWithOverrides<R>(R Function() body) {
|
||||
return runScoped(
|
||||
body,
|
||||
values: {
|
||||
gitRef.overrideWith(() => git),
|
||||
processRef.overrideWith(() => process),
|
||||
shorebirdEnvRef.overrideWith(() => shorebirdEnv),
|
||||
},
|
||||
);
|
||||
@@ -37,7 +46,9 @@ void main() {
|
||||
flutterDirectory = Directory(p.join(shorebirdRoot.path, 'flutter'));
|
||||
git = _MockGit();
|
||||
shorebirdEnv = _MockShorebirdEnv();
|
||||
shorebirdFlutterManager = runWithOverrides(ShorebirdFlutter.new);
|
||||
process = _MockShorebirdProcess();
|
||||
processResult = _MockShorebirdProcessResult();
|
||||
shorebirdFlutter = runWithOverrides(ShorebirdFlutter.new);
|
||||
|
||||
when(
|
||||
() => git.clone(
|
||||
@@ -72,6 +83,52 @@ void main() {
|
||||
).thenAnswer((_) async => flutterRevision);
|
||||
when(() => shorebirdEnv.flutterDirectory).thenReturn(flutterDirectory);
|
||||
when(() => shorebirdEnv.flutterRevision).thenReturn(flutterRevision);
|
||||
when(
|
||||
() => process.run('flutter', ['--version'], runInShell: true),
|
||||
).thenAnswer((_) async => processResult);
|
||||
when(() => processResult.exitCode).thenReturn(0);
|
||||
});
|
||||
|
||||
group('getVersion', () {
|
||||
test('throws ProcessException when process exits with non-zero code',
|
||||
() async {
|
||||
const error = 'oops';
|
||||
when(() => processResult.exitCode).thenReturn(ExitCode.software.code);
|
||||
when(() => processResult.stderr).thenReturn(error);
|
||||
await expectLater(
|
||||
runWithOverrides(shorebirdFlutter.getVersion),
|
||||
throwsA(isA<ProcessException>()),
|
||||
);
|
||||
verify(
|
||||
() => process.run('flutter', ['--version'], runInShell: true),
|
||||
).called(1);
|
||||
});
|
||||
|
||||
test('returns null when cannot parse version', () async {
|
||||
when(() => processResult.stdout).thenReturn('');
|
||||
await expectLater(
|
||||
runWithOverrides(shorebirdFlutter.getVersion),
|
||||
completion(isNull),
|
||||
);
|
||||
verify(
|
||||
() => process.run('flutter', ['--version'], runInShell: true),
|
||||
).called(1);
|
||||
});
|
||||
|
||||
test('returns version when able to parse the string', () async {
|
||||
when(() => processResult.stdout).thenReturn('''
|
||||
Flutter 3.10.6 • channel stable • git@github.com:flutter/flutter.git
|
||||
Framework • revision f468f3366c (4 weeks ago) • 2023-07-12 15:19:05 -0700
|
||||
Engine • revision cdbeda788a
|
||||
Tools • Dart 3.0.6 • DevTools 2.23.1''');
|
||||
await expectLater(
|
||||
runWithOverrides(shorebirdFlutter.getVersion),
|
||||
completion(equals('3.10.6')),
|
||||
);
|
||||
verify(
|
||||
() => process.run('flutter', ['--version'], runInShell: true),
|
||||
).called(1);
|
||||
});
|
||||
});
|
||||
|
||||
group('getVersions', () {
|
||||
@@ -104,7 +161,7 @@ origin/flutter_release/3.10.6''';
|
||||
).thenAnswer((_) async => output);
|
||||
|
||||
await expectLater(
|
||||
runWithOverrides(shorebirdFlutterManager.getVersions),
|
||||
runWithOverrides(shorebirdFlutter.getVersions),
|
||||
completion(equals(versions)),
|
||||
);
|
||||
verify(
|
||||
@@ -135,7 +192,7 @@ origin/flutter_release/3.10.6''';
|
||||
);
|
||||
|
||||
expect(
|
||||
runWithOverrides(shorebirdFlutterManager.getVersions),
|
||||
runWithOverrides(shorebirdFlutter.getVersions),
|
||||
throwsA(
|
||||
isA<ProcessException>().having(
|
||||
(e) => e.message,
|
||||
@@ -155,7 +212,7 @@ origin/flutter_release/3.10.6''';
|
||||
).createSync(recursive: true);
|
||||
|
||||
await runWithOverrides(
|
||||
() => shorebirdFlutterManager.installRevision(revision: revision),
|
||||
() => shorebirdFlutter.installRevision(revision: revision),
|
||||
);
|
||||
|
||||
verifyNever(
|
||||
@@ -179,7 +236,7 @@ origin/flutter_release/3.10.6''';
|
||||
|
||||
await expectLater(
|
||||
runWithOverrides(
|
||||
() => shorebirdFlutterManager.installRevision(revision: revision),
|
||||
() => shorebirdFlutter.installRevision(revision: revision),
|
||||
),
|
||||
throwsA(exception),
|
||||
);
|
||||
@@ -204,7 +261,7 @@ origin/flutter_release/3.10.6''';
|
||||
|
||||
await expectLater(
|
||||
runWithOverrides(
|
||||
() => shorebirdFlutterManager.installRevision(revision: revision),
|
||||
() => shorebirdFlutter.installRevision(revision: revision),
|
||||
),
|
||||
throwsA(exception),
|
||||
);
|
||||
@@ -226,7 +283,7 @@ origin/flutter_release/3.10.6''';
|
||||
test('completes when clone and checkout succeed', () async {
|
||||
await expectLater(
|
||||
runWithOverrides(
|
||||
() => shorebirdFlutterManager.installRevision(revision: revision),
|
||||
() => shorebirdFlutter.installRevision(revision: revision),
|
||||
),
|
||||
completes,
|
||||
);
|
||||
@@ -236,7 +293,7 @@ origin/flutter_release/3.10.6''';
|
||||
group('pruneRemoteOrigin', () {
|
||||
test('completes when git command exits with code 0', () async {
|
||||
await expectLater(
|
||||
runWithOverrides(() => shorebirdFlutterManager.pruneRemoteOrigin()),
|
||||
runWithOverrides(() => shorebirdFlutter.pruneRemoteOrigin()),
|
||||
completes,
|
||||
);
|
||||
verify(
|
||||
@@ -252,7 +309,7 @@ origin/flutter_release/3.10.6''';
|
||||
const customRevision = 'custom-revision';
|
||||
await expectLater(
|
||||
runWithOverrides(
|
||||
() => shorebirdFlutterManager.pruneRemoteOrigin(
|
||||
() => shorebirdFlutter.pruneRemoteOrigin(
|
||||
revision: customRevision,
|
||||
),
|
||||
),
|
||||
@@ -284,7 +341,7 @@ origin/flutter_release/3.10.6''';
|
||||
);
|
||||
|
||||
expect(
|
||||
runWithOverrides(() => shorebirdFlutterManager.pruneRemoteOrigin()),
|
||||
runWithOverrides(() => shorebirdFlutter.pruneRemoteOrigin()),
|
||||
throwsA(
|
||||
isA<ProcessException>().having(
|
||||
(e) => e.message,
|
||||
@@ -299,7 +356,7 @@ origin/flutter_release/3.10.6''';
|
||||
group('isPorcelain', () {
|
||||
test('returns true when status is empty', () async {
|
||||
await expectLater(
|
||||
runWithOverrides(() => shorebirdFlutterManager.isPorcelain()),
|
||||
runWithOverrides(() => shorebirdFlutter.isPorcelain()),
|
||||
completion(isTrue),
|
||||
);
|
||||
verify(
|
||||
@@ -318,7 +375,7 @@ origin/flutter_release/3.10.6''';
|
||||
),
|
||||
).thenAnswer((_) async => 'M some/file');
|
||||
await expectLater(
|
||||
runWithOverrides(() => shorebirdFlutterManager.isPorcelain()),
|
||||
runWithOverrides(() => shorebirdFlutter.isPorcelain()),
|
||||
completion(isFalse),
|
||||
);
|
||||
verify(
|
||||
@@ -347,7 +404,7 @@ origin/flutter_release/3.10.6''';
|
||||
);
|
||||
|
||||
expect(
|
||||
runWithOverrides(() => shorebirdFlutterManager.isPorcelain()),
|
||||
runWithOverrides(() => shorebirdFlutter.isPorcelain()),
|
||||
throwsA(
|
||||
isA<ProcessException>().having(
|
||||
(e) => e.message,
|
||||
@@ -375,7 +432,7 @@ origin/flutter_release/3.10.6''';
|
||||
test('installs revision if it does not exist', () async {
|
||||
await expectLater(
|
||||
runWithOverrides(
|
||||
() => shorebirdFlutterManager.useVersion(version: version),
|
||||
() => shorebirdFlutter.useVersion(version: version),
|
||||
),
|
||||
completes,
|
||||
);
|
||||
@@ -403,7 +460,7 @@ origin/flutter_release/3.10.6''';
|
||||
.createSync(recursive: true);
|
||||
await expectLater(
|
||||
runWithOverrides(
|
||||
() => shorebirdFlutterManager.useVersion(version: version),
|
||||
() => shorebirdFlutter.useVersion(version: version),
|
||||
),
|
||||
completes,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user