Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose wasm readiness analysis in the report (without any score) #1396

Merged
merged 4 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.22.11

- Expose `wasm` readiness analysis in the report (without any score).

## 0.22.10

- Remove `workspace` and `resolution` properties from pubspec before analyzing.
Expand Down
23 changes: 23 additions & 0 deletions lib/src/internal_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import 'package:json_annotation/json_annotation.dart';

import 'model.dart';
import 'tag/_common.dart';
import 'tag/pana_tags.dart';
import 'tool/run_constrained.dart';

part 'internal_model.g.dart';

Expand Down Expand Up @@ -47,6 +50,26 @@ class VersionDescriptor {
Map<String, dynamic> toJson() => _$VersionDescriptorToJson(this);
}

class AnalyzeToolResult {
final List<CodeProblem>? items;
final List<String> tags;
final List<Explanation> explanations;
final ToolException? toolError;

AnalyzeToolResult({
required this.items,
required this.tags,
required this.explanations,
}) : toolError = null;

AnalyzeToolResult.toolError(this.toolError)
: items = null,
tags = [PanaTags.hasError],
explanations = [];

bool get hasError => toolError != null;
}

@JsonSerializable()
class CodeProblem implements Comparable<CodeProblem> {
/// The errors which don't block platform classification.
Expand Down
53 changes: 2 additions & 51 deletions lib/src/package_analyzer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,15 @@ import 'package:logging/logging.dart';
import 'package:path/path.dart' as path;

import 'download_utils.dart';
import 'internal_model.dart';
import 'logging.dart';
import 'maintenance.dart';
import 'messages.dart';
import 'model.dart';
import 'package_context.dart';
import 'pubspec.dart';
import 'report/create_report.dart';
import 'sdk_env.dart';
import 'tag/pana_tags.dart';
import 'tag/tagger.dart';
import 'tool/git_tool.dart';
import 'tool/run_constrained.dart';
import 'utils.dart';

class InspectOptions {
Expand Down Expand Up @@ -120,17 +116,6 @@ class PackageAnalyzer {
packageDir: pkgDir,
);

final dartFiles = <String>[];
final fileList = listFiles(pkgDir, deleteBadExtracted: true);
await for (final file in fileList) {
final isInBin = path.isWithin('bin', file);
final isInLib = path.isWithin('lib', file);
final isDart = file.endsWith('.dart');
if (isDart && (isInLib || isInBin)) {
dartFiles.add(file);
}
}

Pubspec? pubspec;
try {
pubspec = context.pubspec;
Expand All @@ -157,42 +142,8 @@ class PackageAnalyzer {
'[report the issue](https://github.com/dart-lang/pana/issues).');
}

if (await context.resolveDependencies()) {
List<CodeProblem>? analyzerItems;
if (dartFiles.isNotEmpty) {
try {
analyzerItems = await context.staticAnalysis();
} on ToolException catch (e) {
context.errors
.add(runningDartAnalyzerFailed(context.usesFlutter, e.message));
}
} else {
analyzerItems = <CodeProblem>[];
}
if (analyzerItems != null && !analyzerItems.any((item) => item.isError)) {
final tagger = Tagger(pkgDir);
final tags_ = <String>[];
final explanations = <Explanation>[];
// TODO: refactor these methods to return the tags+explanations
tagger.sdkTags(tags_, explanations);
tagger.platformTags(tags_, explanations);
tagger.runtimeTags(tags_, explanations);
tagger.flutterPluginTags(tags_, explanations);
tagger.nullSafetyTags(tags_, explanations);
tagger.wasmReadyTag(tags_, explanations);
// tags are exposed, explanations are ignored
// TODO: use a single result object to derive tags + report
tags.addAll(tags_);

if (context.currentSdkVersion.major >= 3) {
tags.add(PanaTags.isDart3Compatible);
}
} else {
tags.add(PanaTags.hasError);
}
} else {
tags.add(PanaTags.hasError);
}
final tr = await context.staticAnalysis;
tags.addAll(tr.tags);

final licenses = await context.licenses;
tags.addAll((await context.licenceTags).tags);
Expand Down
67 changes: 56 additions & 11 deletions lib/src/package_context.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ import 'repository/check_repository.dart';
import 'screenshots.dart';
import 'sdk_env.dart';
import 'tag/license_tags.dart';
import 'tag/pana_tags.dart';
import 'tag/tagger.dart';
import 'tool/run_constrained.dart';
import 'utils.dart' show listFocusDirs;
import 'utils.dart' show listFiles, listFocusDirs;

/// Shared (intermediate) results between different packages or versions.
/// External systems that may be independent of the archive content may be
Expand Down Expand Up @@ -94,7 +96,6 @@ class PackageContext {
final _stopwatch = Stopwatch();

Pubspec? _pubspec;
List<CodeProblem>? _codeProblems;

PackageContext({
required this.sharedContext,
Expand Down Expand Up @@ -228,17 +229,61 @@ class PackageContext {
}
}();

Future<List<CodeProblem>> staticAnalysis() async {
if (_codeProblems != null) return _codeProblems!;
try {
late final Future<List<String>> _dartFiles = () async {
final results = <String>[];
final fileList = listFiles(packageDir, deleteBadExtracted: true);
await for (final file in fileList) {
final isInBin = p.isWithin('bin', file);
final isInLib = p.isWithin('lib', file);
final isDart = file.endsWith('.dart');
if (isDart && (isInLib || isInBin)) {
results.add(file);
}
}
return results;
}();

late final Future<AnalyzeToolResult> staticAnalysis = () async {
List<CodeProblem>? items;
final tags = <String>[];
final explanations = <Explanation>[];
final dartFiles = await _dartFiles;

if (!await resolveDependencies()) {
tags.add(PanaTags.hasError);
} else if (dartFiles.isEmpty) {
items = [];
} else {
log.info('Analyzing package...');
_codeProblems = await _staticAnalysis(packageDir: packageDir);
return _codeProblems!;
} on ToolException catch (e) {
errors.add(messages.runningDartAnalyzerFailed(usesFlutter, e.message));
rethrow;
try {
items = await _staticAnalysis(packageDir: packageDir);
} on ToolException catch (e) {
errors.add(messages.runningDartAnalyzerFailed(usesFlutter, e.message));
return AnalyzeToolResult.toolError(e);
}
}
}

if (items != null && !items.any((item) => item.isError)) {
final tagger = Tagger(packageDir);
// TODO: refactor these methods to return the tags+explanations
tagger.sdkTags(tags, explanations);
tagger.platformTags(tags, explanations);
tagger.runtimeTags(tags, explanations);
tagger.flutterPluginTags(tags, explanations);
tagger.nullSafetyTags(tags, explanations);
tagger.wasmReadyTag(tags, explanations);
if (currentSdkVersion.major >= 3) {
tags.add(PanaTags.isDart3Compatible);
}
} else {
tags.add(PanaTags.hasError);
}
return AnalyzeToolResult(
items: items,
tags: tags,
explanations: explanations,
);
}();

Future<List<CodeProblem>> _staticAnalysis({
required String packageDir,
Expand Down
6 changes: 2 additions & 4 deletions lib/src/report/create_report.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import '../model.dart';
import '../package_context.dart';
import '../pubspec.dart';

import 'dependencies.dart';
import 'documentation.dart';
Expand All @@ -19,9 +18,8 @@ import 'template.dart';
export '_common.dart' show renderSimpleSectionSummary;

Future<Report> createReport(PackageContext context) async {
Pubspec pubspec;
try {
pubspec = context.pubspec;
context.pubspec;
} on Exception catch (e) {
return Report(
sections: [
Expand All @@ -38,7 +36,7 @@ Future<Report> createReport(PackageContext context) async {
}

final templateReport = await followsTemplate(context);
final platformReport = await multiPlatform(context.packageDir, pubspec);
final platformReport = await multiPlatform(context);
final staticAnalysisReport = await staticAnalysis(context);
final dependenciesReport = await trustworthyDependency(context);

Expand Down
50 changes: 43 additions & 7 deletions lib/src/report/multi_platform.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,20 @@ import 'dart:io';
import 'package:path/path.dart' as p;

import '../model.dart';
import '../pubspec.dart';
import '../package_context.dart';
import '../tag/pana_tags.dart';
import '../tag/tagger.dart';
import '_common.dart';

Future<ReportSection> multiPlatform(String packageDir, Pubspec pubspec) async {
Future<ReportSection> multiPlatform(PackageContext context) async {
Subsection subsection;
final flutterPackage = pubspec.usesFlutter;
final flutterPackage = context.pubspec.usesFlutter;

if (File(p.join(packageDir, '.dart_tool', 'package_config.json'))
if (File(p.join(context.packageDir, '.dart_tool', 'package_config.json'))
.existsSync()) {
final tags = <String>[];
final explanations = <Explanation>[];
final tagger = Tagger(packageDir);
final tagger = Tagger(context.packageDir);
final sdkTags = <String>[];
final sdkExplanations = <Explanation>[];
tagger.sdkTags(sdkTags, sdkExplanations);
Expand Down Expand Up @@ -117,11 +117,47 @@ Future<ReportSection> multiPlatform(String packageDir, Pubspec pubspec) async {
);
}

final wasmSubsection = await _createWasmSubsection(context);

return makeSection(
id: ReportSectionId.platform,
title: 'Platform support',
maxPoints: 20,
basePath: packageDir,
subsections: [subsection],
basePath: context.packageDir,
subsections: [subsection, wasmSubsection],
maxIssues: 20);
}

Future<Subsection> _createWasmSubsection(PackageContext context) async {
final tr = await context.staticAnalysis;
final description = 'WASM readiness';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps:

Suggested change
final description = 'WASM readiness';
final description = 'WASM compatibility';

final explanation =
tr.explanations.where((e) => e.tag == PanaTags.isWasmReady).firstOrNull;
if (explanation != null) {
return Subsection(
description,
[explanationToIssue(explanation)],
0,
0,
ReportStatus.failed,
);
}

if (tr.tags.contains(PanaTags.isWasmReady)) {
return Subsection(
description,
[RawParagraph('Package is compatible with runtime `wasm`.')],
isoos marked this conversation as resolved.
Show resolved Hide resolved
0,
0,
ReportStatus.passed,
);
} else {
return Subsection(
description,
[RawParagraph('Unable to detect compatibility with runtime `wasm`.')],
isoos marked this conversation as resolved.
Show resolved Hide resolved
0,
0,
ReportStatus.failed,
);
}
}
8 changes: 4 additions & 4 deletions lib/src/report/static_analysis.dart
Original file line number Diff line number Diff line change
Expand Up @@ -106,18 +106,18 @@ Future<_AnalysisResult> _analyzePackage(PackageContext context) async {
context.usesFlutter ? 'flutter pub get' : 'dart pub get',
);
}
final list = await context.staticAnalysis();
final rs = await context.staticAnalysis;

return _AnalysisResult(
list
rs.items!
.where((element) => element.isError)
.map(issueFromCodeProblem)
.toList(),
list
rs.items!
.where((element) => element.isWarning)
.map(issueFromCodeProblem)
.toList(),
list
rs.items!
.where((element) => element.isInfo)
.map(issueFromCodeProblem)
.toList(),
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: pana
description: PAckage aNAlyzer - produce a report summarizing the health and quality of a Dart package.
version: 0.22.10
version: 0.22.11
repository: https://github.com/dart-lang/pana
topics:
- tool
Expand Down
2 changes: 1 addition & 1 deletion test/goldens/end2end/_dummy_pkg-1.0.0-null-safety.1.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"grantedPoints": 0,
"maxPoints": 20,
"status": "failed",
"summary": "### [x] 0/20 points: Platform support detection failed\n\n<details>\n<summary>\nCould not determine supported platforms as package resolution failed.\n</summary>\n\nRun `dart pub get` for more information.\n</details>"
"summary": "### [x] 0/20 points: Platform support detection failed\n\n<details>\n<summary>\nCould not determine supported platforms as package resolution failed.\n</summary>\n\nRun `dart pub get` for more information.\n</details>\n\n### [x] 0/0 points: WASM readiness\n\nUnable to detect compatibility with runtime `wasm`."
},
{
"id": "analysis",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ Could not determine supported platforms as package resolution failed.
Run `dart pub get` for more information.
</details>

### [x] 0/0 points: WASM readiness

Unable to detect compatibility with runtime `wasm`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a reason here. Is it because the resolution failed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either the resolution failed or there are error-level issues in the code, which prevent static analysis. As these are exposed at the other parts of the report, I don't think we need to repeat them here.


## 0/50 Pass static analysis

### [x] 0/50 points: code has no errors, warnings, lints, or formatting issues
Expand Down
2 changes: 1 addition & 1 deletion test/goldens/end2end/async-2.11.0.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
"grantedPoints": 20,
"maxPoints": 20,
"status": "passed",
"summary": "### [*] 20/20 points: Supports 6 of 6 possible platforms (**iOS**, **Android**, **Web**, **Windows**, **macOS**, **Linux**)\n\n* ✓ Android\n* ✓ iOS\n* ✓ Windows\n* ✓ Linux\n* ✓ macOS\n* ✓ Web"
"summary": "### [*] 20/20 points: Supports 6 of 6 possible platforms (**iOS**, **Android**, **Web**, **Windows**, **macOS**, **Linux**)\n\n* ✓ Android\n* ✓ iOS\n* ✓ Windows\n* ✓ Linux\n* ✓ macOS\n* ✓ Web\n\n### [*] 0/0 points: WASM readiness\n\nPackage is compatible with runtime `wasm`."
},
{
"id": "analysis",
Expand Down
4 changes: 4 additions & 0 deletions test/goldens/end2end/async-2.11.0.json_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ See [package layout](https://dart.dev/tools/pub/package-layout#examples) guideli
* ✓ macOS
* ✓ Web

### [*] 0/0 points: WASM readiness

Package is compatible with runtime `wasm`.

## 50/50 Pass static analysis

### [*] 50/50 points: code has no errors, warnings, lints, or formatting issues
Expand Down
Loading
Loading