Skip to content

Commit 31193c8

Browse files
committed
Export more package API endpoints.
1 parent 3d75bce commit 31193c8

File tree

7 files changed

+115
-10
lines changed

7 files changed

+115
-10
lines changed

app/lib/package/api_export/api_exporter.dart

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'package:gcloud/service_scope.dart' as ss;
1010
import 'package:gcloud/storage.dart';
1111
import 'package:logging/logging.dart';
1212
import 'package:pub_dev/frontend/handlers/atom_feed.dart';
13+
import 'package:pub_dev/scorecard/backend.dart';
1314
import 'package:pub_dev/service/security_advisories/backend.dart';
1415
import 'package:pub_dev/shared/exceptions.dart';
1516
import 'package:pub_dev/shared/parallel_foreach.dart';
@@ -244,6 +245,22 @@ final class ApiExporter {
244245
versionListing,
245246
forceWrite: forceWrite,
246247
);
248+
await _api.package(package).likes.write(
249+
await packageBackend.getPackageLikesCount(package),
250+
forceWrite: forceWrite,
251+
);
252+
await _api.package(package).options.write(
253+
await packageBackend.getPackageOptions(package),
254+
forceWrite: forceWrite,
255+
);
256+
await _api.package(package).publisher.write(
257+
await packageBackend.getPublisherInfo(package),
258+
forceWrite: forceWrite,
259+
);
260+
await _api.package(package).score.write(
261+
await scoreCardBackend.getVersionScore(package),
262+
forceWrite: forceWrite,
263+
);
247264
await _api.package(package).feedAtomFile.write(
248265
await buildPackageAtomFeedContent(package),
249266
forceWrite: forceWrite,

app/lib/package/api_export/exported_api.dart

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'dart:async';
66
import 'dart:convert';
77
import 'dart:io';
88

9+
import 'package:_pub_shared/data/account_api.dart';
910
import 'package:_pub_shared/data/advisories_api.dart';
1011
import 'package:_pub_shared/data/package_api.dart';
1112
import 'package:clock/clock.dart';
@@ -273,6 +274,20 @@ final class ExportedPackage {
273274
ExportedJsonFile<ListAdvisoriesResponse> get advisories =>
274275
_suffix<ListAdvisoriesResponse>('/advisories');
275276

277+
/// Interface for writing `/api/packages/<package>/likes`.
278+
ExportedJsonFile<PackageLikesCount> get likes =>
279+
_suffix<PackageLikesCount>('/likes');
280+
281+
/// Interface for writing `/api/packages/<package>/options`.
282+
ExportedJsonFile<PkgOptions> get options => _suffix<PkgOptions>('/options');
283+
284+
/// Interface for writing `/api/packages/<package>/publisher`.
285+
ExportedJsonFile<PackagePublisherInfo> get publisher =>
286+
_suffix<PackagePublisherInfo>('/publisher');
287+
288+
/// Interface for writing `/api/packages/<package>/score`.
289+
ExportedJsonFile<VersionScore> get score => _suffix<VersionScore>('/score');
290+
276291
/// Interface for writing `/api/packages/<package>/feed.atom`
277292
ExportedAtomFeedFile get feedAtomFile => ExportedAtomFeedFile._(
278293
_owner,
@@ -406,6 +421,10 @@ final class ExportedPackage {
406421
await Future.wait([
407422
_owner._pool.withResource(() async => await versions.delete()),
408423
_owner._pool.withResource(() async => await advisories.delete()),
424+
_owner._pool.withResource(() async => await likes.delete()),
425+
_owner._pool.withResource(() async => await options.delete()),
426+
_owner._pool.withResource(() async => await publisher.delete()),
427+
_owner._pool.withResource(() async => await score.delete()),
409428
_owner._pool.withResource(() async => await feedAtomFile.delete()),
410429
..._owner._prefixes.map((prefix) async {
411430
await _owner._listBucket(

app/lib/package/backend.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import 'package:meta/meta.dart';
1818
import 'package:pool/pool.dart';
1919
import 'package:pub_dev/package/api_export/api_exporter.dart';
2020
import 'package:pub_dev/package/tarball_storage.dart';
21+
import 'package:pub_dev/scorecard/backend.dart';
2122
import 'package:pub_dev/service/async_queue/async_queue.dart';
2223
import 'package:pub_dev/service/rate_limit/rate_limit.dart';
2324
import 'package:pub_dev/shared/versions.dart';
@@ -493,6 +494,7 @@ class PackageBackend {
493494
});
494495
await purgePackageCache(package);
495496
await taskBackend.trackPackage(package);
497+
await apiExporter!.synchronizePackage(package);
496498
}
497499

498500
/// Updates [options] on [package]/[version], assuming the current user
@@ -531,6 +533,9 @@ class PackageBackend {
531533
}
532534
});
533535
await purgePackageCache(package);
536+
await purgeScorecardData(package, version,
537+
isLatest: pkg.latestVersion == version);
538+
await apiExporter!.synchronizePackage(package);
534539
}
535540

536541
/// Verifies an update to the credential-less publishing settings and
@@ -795,7 +800,7 @@ class PackageBackend {
795800
if (currentPublisherId != null) {
796801
await purgePublisherCache(publisherId: currentPublisherId);
797802
}
798-
803+
await apiExporter!.synchronizePackage(packageName);
799804
return rs;
800805
}
801806

app/lib/task/backend.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import 'package:indexed_blob/indexed_blob.dart' show BlobIndex, FileRange;
1818
import 'package:logging/logging.dart' show Logger;
1919
import 'package:pana/models.dart' show Summary;
2020
import 'package:pool/pool.dart' show Pool;
21+
import 'package:pub_dev/package/api_export/api_exporter.dart';
2122
import 'package:pub_dev/package/backend.dart';
2223
import 'package:pub_dev/package/models.dart';
2324
import 'package:pub_dev/package/upload_signer_service.dart';
@@ -721,6 +722,7 @@ class TaskBackend {
721722

722723
// Clearing the state cache after the update.
723724
await _purgeCache(package, version);
725+
await apiExporter!.synchronizePackage(package);
724726

725727
// If nothing else is running on the instance, delete it!
726728
// We do this in a microtask after returning, so that it doesn't slow down

app/test/admin/exported_api_sync_test.dart

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ void main() {
7171
testWithProfile('baseline checks', fn: () async {
7272
await syncExportedApi();
7373
final data = await listExportedApi();
74-
expect(data.keys, hasLength(greaterThan(20)));
75-
expect(data.keys, hasLength(lessThan(40)));
74+
expect(data.keys, hasLength(greaterThan(50)));
75+
expect(data.keys, hasLength(lessThan(70)));
7676

7777
final oxygenFiles = data.keys.where((k) => k.contains('oxygen')).toSet();
7878
expect(oxygenFiles, hasLength(greaterThan(5)));
@@ -82,12 +82,20 @@ void main() {
8282
'$runtimeVersion/api/archives/oxygen-2.0.0-dev.tar.gz',
8383
'$runtimeVersion/api/packages/oxygen',
8484
'$runtimeVersion/api/packages/oxygen/advisories',
85+
'$runtimeVersion/api/packages/oxygen/likes',
86+
'$runtimeVersion/api/packages/oxygen/options',
87+
'$runtimeVersion/api/packages/oxygen/publisher',
88+
'$runtimeVersion/api/packages/oxygen/score',
8589
'$runtimeVersion/api/packages/oxygen/feed.atom',
8690
'latest/api/archives/oxygen-1.0.0.tar.gz',
8791
'latest/api/archives/oxygen-1.2.0.tar.gz',
8892
'latest/api/archives/oxygen-2.0.0-dev.tar.gz',
8993
'latest/api/packages/oxygen',
9094
'latest/api/packages/oxygen/advisories',
95+
'latest/api/packages/oxygen/likes',
96+
'latest/api/packages/oxygen/options',
97+
'latest/api/packages/oxygen/publisher',
98+
'latest/api/packages/oxygen/score',
9199
'latest/api/packages/oxygen/feed.atom',
92100
});
93101

app/test/package/api_export/api_exporter_test.dart

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,36 @@ Future<void> _testExportedApiSynchronization(
132132
isNotNull,
133133
);
134134
expect(
135-
await bucket.readBytes('$runtimeVersion/api/packages/foo/feed.atom'),
136-
isNotNull,
135+
await bucket.readGzippedJson('$runtimeVersion/api/packages/foo/likes'),
136+
{
137+
'package': 'foo',
138+
'likes': 0,
139+
},
140+
);
141+
expect(
142+
await bucket.readGzippedJson('$runtimeVersion/api/packages/foo/options'),
143+
{
144+
'isDiscontinued': false,
145+
'replacedBy': null,
146+
'isUnlisted': false,
147+
},
148+
);
149+
expect(
150+
await bucket
151+
.readGzippedJson('$runtimeVersion/api/packages/foo/publisher'),
152+
{
153+
'publisherId': null,
154+
},
155+
);
156+
expect(
157+
await bucket.readGzippedJson('$runtimeVersion/api/packages/foo/score'),
158+
{
159+
'grantedPoints': isNotNull,
160+
'maxPoints': isNotNull,
161+
'likeCount': isNotNull,
162+
'tags': isNotEmpty,
163+
'lastUpdated': isNotNull,
164+
},
137165
);
138166
expect(
139167
await bucket.readGzippedJson('$runtimeVersion/api/packages/foo'),
@@ -143,6 +171,10 @@ Future<void> _testExportedApiSynchronization(
143171
'versions': hasLength(1),
144172
},
145173
);
174+
expect(
175+
await bucket.readString('$runtimeVersion/api/packages/foo/feed.atom'),
176+
contains('v1.0.0 of foo'),
177+
);
146178
expect(
147179
await bucket
148180
.readGzippedJson('$runtimeVersion/api/package-name-completion-data'),
@@ -156,10 +188,6 @@ Future<void> _testExportedApiSynchronization(
156188
await bucket.readString('$runtimeVersion/feed.atom'),
157189
contains('v1.0.0 of foo'),
158190
);
159-
expect(
160-
await bucket.readString('$runtimeVersion/api/packages/foo/feed.atom'),
161-
contains('v1.0.0 of foo'),
162-
);
163191
}
164192

165193
_log.info('## New package');
@@ -197,6 +225,22 @@ Future<void> _testExportedApiSynchronization(
197225
await bucket.readString('latest/api/packages/foo/feed.atom'),
198226
contains('v1.0.0 of foo'),
199227
);
228+
expect(
229+
await bucket.readGzippedJson('latest/api/packages/foo/likes'),
230+
isNotNull,
231+
);
232+
expect(
233+
await bucket.readGzippedJson('latest/api/packages/foo/options'),
234+
isNotNull,
235+
);
236+
expect(
237+
await bucket.readGzippedJson('latest/api/packages/foo/publisher'),
238+
isNotNull,
239+
);
240+
expect(
241+
await bucket.readGzippedJson('latest/api/packages/foo/score'),
242+
isNotNull,
243+
);
200244
// Note. that name completion data won't be updated until search caches
201245
// are purged, so we won't test that it is updated.
202246

@@ -444,6 +488,10 @@ Future<void> _testExportedApiSynchronization(
444488
await bucket.readGzippedJson('latest/api/packages/bar'),
445489
isNull,
446490
);
491+
expect(
492+
await bucket.readGzippedJson('latest/api/packages/bar/options'),
493+
isNull,
494+
);
447495
expect(
448496
await bucket.readGzippedJson('latest/api/packages/feed.atom'),
449497
isNull,
@@ -484,6 +532,10 @@ Future<void> _testExportedApiSynchronization(
484532
'versions': hasLength(2),
485533
},
486534
);
535+
expect(
536+
await bucket.readGzippedJson('latest/api/packages/bar/options'),
537+
isNotNull,
538+
);
487539
expect(
488540
await bucket.readBytes('latest/api/archives/bar-2.0.0.tar.gz'),
489541
isNotNull,

app/test/task/task_test.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,9 @@ void main() {
190190
await fakeTime.elapse(minutes: 10);
191191
});
192192

193-
testWithFakeTime('failing instances will be retried', (fakeTime) async {
193+
testWithFakeTime('failing instances will be retried', expectedLogMessages: [
194+
'SHOUT [pub-notice:cached_value] Updating cached `thirtyDaysTotalDownloadCounts` value failed.',
195+
], (fakeTime) async {
194196
await taskBackend.backfillTrackingState();
195197
await fakeTime.elapse(minutes: 1);
196198

0 commit comments

Comments
 (0)