in lib/src/report/dependencies.dart [26:245]
Future<ReportSection> trustworthyDependency(PackageContext context) async {
final pubspec = context.pubspec;
final packageDir = context.packageDir;
final toolEnvironment = context.toolEnvironment;
Future<Subsection> dependencies() async {
final issues = <Issue>[];
var bodyPrefix = '';
var points = 10;
var status = ReportStatus.passed;
if (context.pubspecAllowsCurrentSdk) {
try {
final outdated = Outdated.fromJson(await toolEnvironment.runPubOutdated(
packageDir,
args: [
'--json',
'--up-to-date',
'--no-dev-dependencies',
'--no-dependency-overrides',
],
usesFlutter: context.usesFlutter,
));
final outdatedVersions = <String, List<OutdatedVersionDescription>>{};
for (final p in outdated.packages) {
outdatedVersions[p.package] =
await computeOutdatedVersions(context, p);
}
String constraint(Dependency dependency) {
if (dependency is HostedDependency) {
return '`${dependency.version}`';
} else if (dependency is SdkDependency) {
return '`${dependency.sdk}`';
} else if (dependency is GitDependency) {
return '`${dependency.ref}`';
} else if (dependency is PathDependency) {
return '`${dependency.path}`';
} else {
return '-';
}
}
String makeTable(List<List<String>> rows) {
return [
['Package', 'Constraint', 'Compatible', 'Latest'],
[':-', ':-', ':-', ':-'],
...rows,
].map((r) => '|${r.join('|')}|').join('\n');
}
final links = <String>[];
String linkToPackage(String pkg) {
final link = '[`$pkg`]: https://pub.dev/packages/$pkg';
if (!links.contains(link)) {
links.add(link);
}
return '[`$pkg`]';
}
final depsTable = outdated.packages
.where((p) => pubspec.dependencies.containsKey(p.package))
.map((p) => [
linkToPackage(p.package),
constraint(pubspec.dependencies[p.package]!),
p.upgradable?.version ?? '-',
if (outdatedVersions.containsKey(p.package) &&
outdatedVersions[p.package]!.isNotEmpty)
'**${p.latest?.version ?? '-'}**'
else
p.latest?.version ?? '-',
])
.toList();
final transitiveTable = outdated.packages
.where((p) => !pubspec.dependencies.containsKey(p.package))
// See: https://github.com/dart-lang/pub/issues/2552
.where((p) => p.upgradable != null)
.map((p) => [
linkToPackage(p.package),
'-',
p.upgradable?.version ?? '-',
p.latest?.version ?? '-',
])
.toList();
bodyPrefix = [
// If we have deps show table
if (depsTable.isNotEmpty) ...[
makeTable(depsTable),
'',
] else ...[
'No dependencies.',
'',
],
// If we have transitive deps too
if (transitiveTable.isNotEmpty) ...[
'<details><summary>Transitive dependencies</summary>',
'',
makeTable(transitiveTable),
'</details>',
'',
],
'To reproduce run `dart pub outdated --no-dev-dependencies --up-to-date --no-dependency-overrides`.',
'',
if (links.isNotEmpty) ...[
...links,
'',
],
].join('\n');
for (final l in outdatedVersions.values) {
if (l.isNotEmpty) {
final worst = maxBy<OutdatedVersionDescription>(
l, (a, b) => a.status.index - b.status.index);
issues.add(worst.issue);
if (worst.status == OutdatedStatus.outdated) {
points = 0;
status = ReportStatus.failed;
} else if (worst.status == OutdatedStatus.outdatedByPreview ||
worst.status == OutdatedStatus.outdatedByRecent) {
// TODO(sigurdm): Could we find some way of indicating that
// points will be lost soon?
status = ReportStatus.passed;
}
}
}
} on ToolException catch (e) {
issues.add(Issue(
'Could not run `${context.usesFlutter ? 'flutter' : 'dart'} pub outdated`: ${e.message}'));
points = 0;
status = ReportStatus.failed;
}
} else {
issues.add(_unsupportedDartSdk(context,
command: '${context.usesFlutter ? 'flutter' : 'dart'} pub outdated'));
points = 0;
status = ReportStatus.failed;
}
return Subsection(
'All of the package dependencies are supported in the latest version',
issues,
points,
10,
status,
bodyPrefix: bodyPrefix,
);
}
Future<Subsection> sdkSupport() async {
final issues = <Issue>[];
final sdkConstraint = pubspec.dartSdkConstraint;
if (sdkConstraint == null) {
issues.add(Issue('Pubspec.yaml does not have an sdk version constraint.',
suggestion: 'Try adding an sdk constraint to your `pubspec.yaml`'));
} else if (!context.pubspecAllowsCurrentSdk) {
issues.add(_unsupportedDartSdk(context,
suggestion: 'Try widening the upper boundary of the constraint.'));
}
final runtimeInfo = toolEnvironment.runtimeInfo;
final usesFlutter = pubspec.usesFlutter;
if (usesFlutter) {
if (!runtimeInfo.hasFlutter) {
issues.add(Issue(
'Found no Flutter in your PATH. Could not determine the current Flutter version.'));
} else {
final flutterDartVersion =
Version.parse(runtimeInfo.flutterInternalDartSdkVersion!);
final allowsCurrentFlutterDart =
sdkConstraint?.allows(flutterDartVersion) ?? false;
if (!allowsCurrentFlutterDart) {
issues.add(
Issue(
'The current SDK constraint does not allow the Dart version used by the latest stable Flutter ($flutterDartVersion)',
span: tryGetSpanFromYamlMap(pubspec.environment, 'sdk'),
),
);
} else {
// TODO(sigurdm): this will not work well locally (installed version will
// not be latest). Perhaps we should query somewhere for the latest version.
final currentFlutterVersion = runtimeInfo.flutterVersion == null
? null
: Version.parse(runtimeInfo.flutterVersion!);
final flutterConstraint = pubspec.flutterSdkConstraint;
if (flutterConstraint != null &&
currentFlutterVersion != null &&
!flutterConstraint.allows(currentFlutterVersion)) {
issues.add(
Issue(
'The current flutter constraint does not allow the latest Flutter ($currentFlutterVersion)',
span: tryGetSpanFromYamlMap(pubspec.environment, 'flutter'),
),
);
}
}
}
}
final status = issues.isEmpty ? ReportStatus.passed : ReportStatus.failed;
final points = issues.isEmpty ? 10 : 0;
return Subsection(
'Package supports latest stable Dart and Flutter SDKs',
issues,
points,
10,
status,
);
}
final dependencySection = await dependencies();
final sdkSection = await sdkSupport();
final subsections = [dependencySection, sdkSection];
return makeSection(
id: ReportSectionId.dependency,
title: 'Support up-to-date dependencies',
maxPoints: 20,
subsections: subsections,
basePath: packageDir,
);
}