Skip to content

Commit fe8716f

Browse files
authored
Expose more precise repository verification status in 'AnalysisResult'. (#1433)
1 parent db996dd commit fe8716f

26 files changed

+117
-19
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
## 0.22.18-dev
22

33
- Make example's `README.md` priority over any dart file in the examples directory.
4+
- Expose more precise repository verification status in `AnalysisResult`.
45

56
## 0.22.17
67

lib/src/internal_model.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,11 +214,13 @@ class UrlStatus {
214214

215215
@JsonSerializable(includeIfNull: false, explicitToJson: true)
216216
class VerifiedRepository {
217+
final RepositoryStatus status;
217218
final Repository? repository;
218219
final String? contributingUrl;
219220
final String? verificationFailure;
220221

221222
VerifiedRepository({
223+
required this.status,
222224
this.repository,
223225
this.contributingUrl,
224226
this.verificationFailure,

lib/src/internal_model.g.dart

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/src/model.dart

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ class AnalysisResult {
331331
final String? issueTrackerUrl;
332332
final String? documentationUrl;
333333
final List<String>? fundingUrls;
334+
final RepositoryStatus? repositoryStatus;
334335
final Repository? repository;
335336
final String? contributingUrl;
336337
final List<License>? licenses;
@@ -343,6 +344,7 @@ class AnalysisResult {
343344
this.issueTrackerUrl,
344345
this.documentationUrl,
345346
this.fundingUrls,
347+
this.repositoryStatus,
346348
this.repository,
347349
this.contributingUrl,
348350
this.licenses,
@@ -356,6 +358,36 @@ class AnalysisResult {
356358
Map<String, dynamic> toJson() => _$AnalysisResultToJson(this);
357359
}
358360

361+
/// The status of the repository verification.
362+
enum RepositoryStatus {
363+
/// The repository URL was not specified, empty, or we were not able to
364+
/// infer it (e.g. from `homepage`).
365+
///
366+
/// No verification was done.
367+
unspecified,
368+
369+
/// The specified URL was not a valid or secure URL.
370+
///
371+
/// No verification was done.
372+
invalid,
373+
374+
/// There was no repository found on the specified URL.
375+
/// The issue may be transient, a repeated access may find it.
376+
///
377+
/// No verification was done.
378+
missing,
379+
380+
/// The repository did not pass verification tests.
381+
failed,
382+
383+
/// The repository passed verification tests.
384+
verified,
385+
386+
/// The repository verification encountered a failure, result is
387+
/// not conclusive.
388+
inconclusive;
389+
}
390+
359391
/// NOTE: the content of the class is experimental, clients should not rely on it yet.
360392
/// To get successful verification, the remote repository:
361393
/// - must be a valid remote repository with public access,

lib/src/model.g.dart

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/src/package_analyzer.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ Future<AnalysisResult> _createAnalysisResult(
258258
PackageContext context, Report report) async {
259259
final pubspecUrls = await context.pubspecUrlsWithIssues;
260260
final repoVerification = await context.repository;
261-
final repository = repoVerification?.repository;
261+
final repository = repoVerification.repository;
262262
final fundingUrls =
263263
pubspecUrls.funding.map((e) => e.verifiedUrl).nonNulls.toList();
264264
return AnalysisResult(
@@ -267,8 +267,9 @@ Future<AnalysisResult> _createAnalysisResult(
267267
issueTrackerUrl: pubspecUrls.issueTracker.verifiedUrl,
268268
documentationUrl: pubspecUrls.documentation.verifiedUrl,
269269
fundingUrls: fundingUrls.isEmpty ? null : fundingUrls,
270+
repositoryStatus: repoVerification.status,
270271
repository: repository,
271-
contributingUrl: repoVerification?.contributingUrl,
272+
contributingUrl: repoVerification.contributingUrl,
272273
licenses: await context.licenses,
273274
grantedPoints: report.grantedPoints,
274275
maxPoints: report.maxPoints,

lib/src/package_context.dart

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import 'internal_model.dart';
1616
import 'license.dart';
1717
import 'logging.dart';
1818
import 'messages.dart' as messages;
19+
import 'model.dart';
1920
import 'package_analyzer.dart' show InspectOptions;
2021
import 'pana_cache.dart';
2122
import 'pkg_resolution.dart';
@@ -61,12 +62,16 @@ class SharedAnalysisContext {
6162
return status;
6263
}
6364

64-
Future<VerifiedRepository?> verifyRepository(
65+
Future<VerifiedRepository> verifyRepository(
6566
String package,
6667
String? repositoryOrHomepage,
6768
) async {
68-
if (repositoryOrHomepage == null) {
69-
return null;
69+
repositoryOrHomepage = repositoryOrHomepage?.trim();
70+
if (repositoryOrHomepage == null || repositoryOrHomepage.isEmpty) {
71+
return VerifiedRepository(
72+
status: RepositoryStatus.unspecified,
73+
verificationFailure: 'Repository URL is missing.',
74+
);
7075
}
7176
final cacheType = 'repository';
7277
final cacheKey = '$package/$repositoryOrHomepage';
@@ -79,9 +84,7 @@ class SharedAnalysisContext {
7984
packageName: package,
8085
sourceUrl: repositoryOrHomepage,
8186
);
82-
if (repository != null) {
83-
await panaCache.writeData(cacheType, cacheKey, repository.toJson());
84-
}
87+
await panaCache.writeData(cacheType, cacheKey, repository.toJson());
8588
return repository;
8689
}
8790
}

lib/src/references/pubspec_urls.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ Future<PubspecUrlsWithIssues> checkPubspecUrls(PackageContext context) async {
5757
// Switch homepage and repository if only homepage is given,
5858
// and it can be verified as a valid repository.
5959
final verifiedRepository = await context.repository;
60-
final isVerifiedRepository = verifiedRepository?.repository != null;
60+
final status = verifiedRepository.status;
61+
final isVerifiedRepository = status == RepositoryStatus.verified;
6162
// We should switch these values if the repository has been verified.
6263
if (isVerifiedRepository &&
6364
pubspec.homepage != null &&
@@ -69,7 +70,7 @@ Future<PubspecUrlsWithIssues> checkPubspecUrls(PackageContext context) async {
6970

7071
// Set known issue tracker link in cases where it was not provided.
7172
if (pubspec.issueTracker == null && isVerifiedRepository) {
72-
final vr = verifiedRepository!.repository!;
73+
final vr = verifiedRepository.repository!;
7374
final repoSegments = vr.repository;
7475
if (RepositoryProvider.isGitHubCompatible(vr.provider) &&
7576
repoSegments != null) {

lib/src/report/template.dart

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,8 @@ Future<ReportSection> followsTemplate(PackageContext context) async {
170170
issues.addAll(pubspecUrls.issues);
171171

172172
final repository = await context.repository;
173-
if (repository?.verificationFailure != null) {
173+
final repositoryStatus = repository.status;
174+
if (repositoryStatus == RepositoryStatus.failed) {
174175
issues.add(Issue('Failed to verify repository URL.',
175176
suggestion:
176177
'Please provide a valid [`repository`](https://dart.dev/tools/pub/pubspec#repository) URL in `pubspec.yaml`, such that:\n\n'
@@ -179,7 +180,7 @@ Future<ReportSection> followsTemplate(PackageContext context) async {
179180
' * contains `name: ${pubspec.name}`,\n'
180181
' * contains a `version` property, and,\n'
181182
' * does not contain a `publish_to` property.\n\n'
182-
'${repository!.verificationFailure}'));
183+
'${repository.verificationFailure ?? 'status: `${repositoryStatus.name}`'}'));
183184
}
184185

185186
final executableFiles = await context.executablesInBinDirectory;
@@ -202,7 +203,7 @@ Future<ReportSection> followsTemplate(PackageContext context) async {
202203
issues.every((issue) =>
203204
(issue.suggestion ?? '').contains('was unreachable')) &&
204205
// repository verification succeeded
205-
repository?.repository != null;
206+
repository.repository != null;
206207

207208
final status = issues.isEmpty
208209
? ReportStatus.passed

lib/src/repository/check_repository.dart

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,33 @@ import 'git_local_repository.dart';
1818
const _maxPubspecBytes = 256 * 1024;
1919

2020
/// Returns the repository information for the current package.
21-
Future<VerifiedRepository?> checkRepository({
21+
Future<VerifiedRepository> checkRepository({
2222
required SharedAnalysisContext sharedContext,
2323
required String packageName,
2424
required String? sourceUrl,
2525
}) async {
26-
if (sourceUrl == null) {
27-
return null;
26+
sourceUrl = sourceUrl?.trim();
27+
if (sourceUrl == null || sourceUrl.isEmpty) {
28+
return VerifiedRepository(
29+
status: RepositoryStatus.missing,
30+
verificationFailure: 'Repository URL is missing.',
31+
);
2832
}
29-
final parsedSourceUrl = Repository.tryParseUrl(sourceUrl);
30-
if (parsedSourceUrl == null) {
31-
return null;
33+
late Repository parsedSourceUrl;
34+
try {
35+
parsedSourceUrl = Repository.parseUrl(sourceUrl);
36+
} on Exception catch (e) {
37+
return VerifiedRepository(
38+
status: RepositoryStatus.invalid,
39+
verificationFailure: e.toString(),
40+
);
3241
}
3342
var branch = parsedSourceUrl.branch;
3443
var completed = false;
3544
String? verificationFailure;
3645
var localPath = parsedSourceUrl.path;
3746
String? contributingUrl;
47+
RepositoryStatus? status;
3848

3949
Repository repositoryWithPath(String? path) {
4050
if (path == '' || path == '.') {
@@ -52,18 +62,23 @@ Future<VerifiedRepository?> checkRepository({
5262
VerifiedRepository result() {
5363
if (completed && verificationFailure == null) {
5464
return VerifiedRepository(
65+
status: RepositoryStatus.verified,
5566
repository: repositoryWithPath(localPath),
5667
contributingUrl: contributingUrl,
5768
);
5869
} else {
5970
return VerifiedRepository(
71+
status: status ?? RepositoryStatus.inconclusive,
6072
verificationFailure: verificationFailure,
6173
);
6274
}
6375
}
6476

6577
void failVerification(String message, [Object? error, StackTrace? st]) {
6678
verificationFailure = message;
79+
if (error == null) {
80+
status = RepositoryStatus.failed;
81+
}
6782
log.info(message, error, st);
6883
}
6984

@@ -81,6 +96,7 @@ Future<VerifiedRepository?> checkRepository({
8196
files.where((path) => p.basename(path) == 'pubspec.yaml').toList();
8297
if (pubspecFiles.isEmpty) {
8398
return VerifiedRepository(
99+
status: RepositoryStatus.failed,
84100
verificationFailure:
85101
'Could not find any `pubspec.yaml` in the repository.',
86102
);

test/goldens/end2end/_dummy_pkg-1.0.0-null-safety.1.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
"screenshots": [],
8181
"result": {
8282
"homepageUrl": "https://github.com/dart-lang/pub-dev",
83+
"repositoryStatus": "failed",
8384
"licenses": [
8485
{
8586
"path": "LICENSE",

test/goldens/end2end/async-2.11.0.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@
111111
"result": {
112112
"repositoryUrl": "https://github.com/dart-lang/async",
113113
"issueTrackerUrl": "https://github.com/dart-lang/async/issues",
114+
"repositoryStatus": "verified",
114115
"repository": {
115116
"provider": "github",
116117
"host": "github.com",

test/goldens/end2end/audio_service-0.18.15.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@
188188
"result": {
189189
"repositoryUrl": "https://github.com/ryanheise/audio_service/tree/minor/audio_service",
190190
"issueTrackerUrl": "https://github.com/ryanheise/audio_service/issues",
191+
"repositoryStatus": "verified",
191192
"repository": {
192193
"provider": "github",
193194
"host": "github.com",

test/goldens/end2end/bulma_min-0.7.4.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
"result": {
8383
"repositoryUrl": "https://github.com/agilord/bulma_min",
8484
"issueTrackerUrl": "https://github.com/agilord/bulma_min/issues",
85+
"repositoryStatus": "verified",
8586
"repository": {
8687
"provider": "github",
8788
"host": "github.com",

test/goldens/end2end/dnd-2.0.1.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
"homepageUrl": "https://code.makery.ch/library/dart-drag-and-drop/",
9797
"repositoryUrl": "https://github.com/marcojakob/dart-dnd",
9898
"issueTrackerUrl": "https://github.com/marcojakob/dart-dnd/issues",
99+
"repositoryStatus": "verified",
99100
"repository": {
100101
"provider": "github",
101102
"host": "github.com",

test/goldens/end2end/gg-1.0.12.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@
171171
"result": {
172172
"repositoryUrl": "https://github.com/inlavigo/gg.git",
173173
"issueTrackerUrl": "https://github.com/inlavigo/gg/issues",
174+
"repositoryStatus": "verified",
174175
"repository": {
175176
"provider": "github",
176177
"host": "github.com",

test/goldens/end2end/http-0.13.0.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@
116116
"result": {
117117
"repositoryUrl": "https://github.com/dart-lang/http",
118118
"issueTrackerUrl": "https://github.com/dart-lang/http/issues",
119+
"repositoryStatus": "verified",
119120
"repository": {
120121
"provider": "github",
121122
"host": "github.com",

test/goldens/end2end/lints-1.0.0.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
},
9292
"screenshots": [],
9393
"result": {
94+
"repositoryStatus": "unspecified",
9495
"licenses": [
9596
{
9697
"path": "LICENSE",

test/goldens/end2end/mime_type-0.3.2.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
"result": {
7676
"repositoryUrl": "https://github.com/mitsuoka/mime_type",
7777
"issueTrackerUrl": "https://github.com/mitsuoka/mime_type/issues",
78+
"repositoryStatus": "verified",
7879
"repository": {
7980
"provider": "github",
8081
"host": "github.com",

test/goldens/end2end/nsd_android-2.1.2.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@
111111
"result": {
112112
"repositoryUrl": "https://github.com/sebastianhaberey/nsd/tree/main/nsd_android",
113113
"issueTrackerUrl": "https://github.com/sebastianhaberey/nsd/issues",
114+
"repositoryStatus": "verified",
114115
"repository": {
115116
"provider": "github",
116117
"host": "github.com",

0 commit comments

Comments
 (0)