Skip to content

Commit

Permalink
feat(packages): ensure git dependencies are reachable (#379)
Browse files Browse the repository at this point in the history
  • Loading branch information
felangel authored May 6, 2022
1 parent 666b513 commit 886bb85
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 0 deletions.
2 changes: 2 additions & 0 deletions lib/src/cli/cli.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import 'package:glob/glob.dart';
import 'package:lcov_parser/lcov_parser.dart';
import 'package:mason/mason.dart';
import 'package:path/path.dart' as p;
import 'package:pubspec_parse/pubspec_parse.dart';
import 'package:universal_io/io.dart';
import 'package:very_good_cli/src/commands/test/templates/test_runner_bundle.dart';
import 'package:very_good_test_runner/very_good_test_runner.dart';

part 'dart_cli.dart';
part 'flutter_cli.dart';
part 'git_cli.dart';

/// Abstraction for running commands via command-line.
class _Cmd {
Expand Down
36 changes: 36 additions & 0 deletions lib/src/cli/flutter_cli.dart
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ class Flutter {
final installDone = progress?.call(
'Running "flutter packages get" in $cwd',
);

try {
await _verifyGitDependencies(cwd);
} catch (_) {
installDone?.call();
rethrow;
}

try {
await _Cmd.run(
'flutter',
Expand Down Expand Up @@ -200,6 +208,34 @@ class Flutter {
}
}

/// Ensures all git dependencies are reachable for the pubspec
/// located in the [cwd].
///
/// If any git dependencies are unreachable,
/// an [UnreachableGitDependency] is thrown.
Future<void> _verifyGitDependencies(String cwd) async {
final pubspec = Pubspec.parse(
await File(p.join(cwd, 'pubspec.yaml')).readAsString(),
);

final dependencies = pubspec.dependencies;
final devDependencies = pubspec.devDependencies;
final dependencyOverrides = pubspec.dependencyOverrides;
final gitDependencies = [
...dependencies.entries,
...devDependencies.entries,
...dependencyOverrides.entries
]
.where((entry) => entry.value is GitDependency)
.map((entry) => entry.value)
.cast<GitDependency>()
.toList();

await Future.wait(
gitDependencies.map((dependency) => Git.reachable(dependency.url)),
);
}

/// Run a command on directories with a `pubspec.yaml`.
Future<List<T>> _runCommand<T>({
required Future<T> Function(String cwd) cmd,
Expand Down
32 changes: 32 additions & 0 deletions lib/src/cli/git_cli.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
part of 'cli.dart';

/// {@template unreachable_git_dependency}
/// Thrown when `flutter packages get` or `flutter pub get`
/// encounters an unreachable git dependency.
/// {@endtemplate}
class UnreachableGitDependency implements Exception {
/// {@macro unreachable_git_dependency}
const UnreachableGitDependency({required this.remote});

/// The associated git remote [Uri].
final Uri remote;

@override
String toString() {
return '''
$remote is unreachable.
Make sure the remote exists and you have the correct access rights.''';
}
}

/// Git CLI
class Git {
/// Determine whether the [remote] is reachable.
static Future<void> reachable(Uri remote) async {
try {
await _Cmd.run('git', ['ls-remote', '$remote', '--exit-code']);
} catch (_) {
throw UnreachableGitDependency(remote: remote);
}
}
}
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ dependencies:
meta: ^1.3.0
path: ^1.8.0
pub_updater: ^0.2.1
pubspec_parse: ^1.2.0
universal_io: ^2.0.4
usage: ^4.0.2
very_good_analysis: ^2.4.0
Expand Down
32 changes: 32 additions & 0 deletions test/src/cli/flutter_cli_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,16 @@ dev_dependencies:

const invalidPubspec = 'name: example';

const unreachableGitUrlPubspec = '''
name: example
environment:
sdk: ">=2.13.0 <3.0.0"
dev_dependencies:
very_good_analysis:
git:
url: https://github.com/verygoodopensource/_very_good_analysis''';

class MockLogger extends Mock implements Logger {}

void main() {
Expand All @@ -194,6 +204,17 @@ void main() {
);
});

test('throws when there is an unreachable git url', () {
final directory = Directory.systemTemp.createTempSync();
File(p.join(directory.path, 'pubspec.yaml'))
.writeAsStringSync(unreachableGitUrlPubspec);

expectLater(
Flutter.packagesGet(cwd: directory.path),
throwsA(isA<UnreachableGitDependency>()),
);
});

test('completes when there is a pubspec.yaml', () {
expectLater(Flutter.packagesGet(), completes);
});
Expand Down Expand Up @@ -238,6 +259,17 @@ void main() {
);
});

test('throws when there is an unreachable git url', () {
final directory = Directory.systemTemp.createTempSync();
File(p.join(directory.path, 'pubspec.yaml'))
.writeAsStringSync(unreachableGitUrlPubspec);

expectLater(
Flutter.packagesGet(cwd: directory.path),
throwsA(isA<UnreachableGitDependency>()),
);
});

test('completes when there is a pubspec.yaml', () {
final directory = Directory.systemTemp.createTempSync();
File(p.join(directory.path, 'pubspec.yaml')).writeAsStringSync(pubspec);
Expand Down
43 changes: 43 additions & 0 deletions test/src/cli/git_cli_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import 'package:test/test.dart';
import 'package:very_good_cli/src/cli/cli.dart';

void main() {
group('Git', () {
group('reachable', () {
test('completes for a reachable remote', () async {
await expectLater(
Git.reachable(
Uri.parse('https://github.com/verygoodopensource/very_good_cli'),
),
completes,
);
});

test('throws UnreachableGitDependency for an unreachable remote',
() async {
await expectLater(
Git.reachable(
Uri.parse('https://github.com/verygoodopensource/_very_good_cli'),
),
throwsA(isA<UnreachableGitDependency>()),
);
});
});

group('UnreachableGitDependency', () {
test('has correct toString override', () {
final remote =
Uri.parse('https://github.com/verygoodopensource/_very_good_cli');
final exception = UnreachableGitDependency(remote: remote);
expect(
exception.toString(),
equals(
'''
$remote is unreachable.
Make sure the remote exists and you have the correct access rights.''',
),
);
});
});
});
}

0 comments on commit 886bb85

Please sign in to comment.