Skip to content

Commit e3cbafb

Browse files
committed
Report unmapped fields in integrity checks + delete Package.isWithheld and withheldReason.
1 parent 6352f10 commit e3cbafb

File tree

3 files changed

+43
-1
lines changed

3 files changed

+43
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ AppEngine version, listed here to ease deployment and troubleshooting.
44
## Next Release (replace with git tag when deployed)
55
* Bump runtimeVersion to `2024.12.12`.
66
* Upgraded runtime Dart SDK to `3.6.0`.
7+
* Note: Started reporting unmapped fields and deleting `Package.isWithheld` and `Package.withheldReason`.
78

89
## `20241212t111200-all`
910
* Bump runtimeVersion to `2024.12.11`.

app/lib/shared/integrity.dart

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ class IntegrityChecker {
4040
final DatastoreDB _db;
4141
final int _concurrency;
4242

43+
static const _knownUnmappedFields = {
44+
'Package.isWithheld',
45+
'Package.withheldReason',
46+
};
47+
final _unmappedFields = <String>{};
4348
final _userToOauth = <String, String?>{};
4449
final _oauthToUser = <String, String>{};
4550
final _deletedUsers = <String>{};
@@ -93,7 +98,13 @@ class IntegrityChecker {
9398
yield* _checkAuditLogs();
9499
yield* _checkModerationCases();
95100
yield* _reportPubspecVersionIssues();
96-
// TODO: report unmapped properties
101+
102+
if (_unmappedFields.isNotEmpty) {
103+
for (final field in _unmappedFields) {
104+
if (_knownUnmappedFields.contains(field)) continue;
105+
yield 'Unmapped field found: $field.';
106+
}
107+
}
97108
} finally {
98109
_httpClient.close();
99110
}
@@ -448,6 +459,7 @@ class IntegrityChecker {
448459
}
449460

450461
await for (final pvi in pviQuery.run()) {
462+
_updateUnmappedFields(pvi);
451463
final key = pvi.qualifiedVersionKey;
452464
pviKeys.add(key);
453465
yield* checkPackageVersionKey('PackageVersionInfo', key);
@@ -475,6 +487,7 @@ class IntegrityChecker {
475487
..filter('package =', p.name);
476488
final foundAssetIds = <String?>{};
477489
await for (final pva in pvaQuery.run()) {
490+
_updateUnmappedFields(pva);
478491
final key = pva.qualifiedVersionKey;
479492
if (pva.id !=
480493
Uri(pathSegments: [pva.package!, pva.version!, pva.kind!]).path) {
@@ -907,13 +920,23 @@ class IntegrityChecker {
907920
}
908921
}
909922

923+
void _updateUnmappedFields(Model m) {
924+
if (m is ExpandoModel && m.additionalProperties.isNotEmpty) {
925+
for (final key in m.additionalProperties.keys) {
926+
final field = [m.runtimeType.toString(), key].join('.');
927+
_unmappedFields.add(field);
928+
}
929+
}
930+
}
931+
910932
Stream<String> _queryWithPool<R extends Model>(
911933
Stream<String> Function(R model) fn) async* {
912934
final query = _db.query<R>();
913935
final pool = Pool(_concurrency);
914936
final futures = <Future<List<String>>>[];
915937
try {
916938
await for (final m in query.run()) {
939+
_updateUnmappedFields(m);
917940
final f = pool.withResource(() => fn(m).toList());
918941
futures.add(f);
919942
}

app/lib/tool/backfill/backfill_new_fields.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import 'package:clock/clock.dart';
66
import 'package:logging/logging.dart';
7+
import 'package:meta/meta.dart';
78
import 'package:pub_dev/account/models.dart';
89
import 'package:pub_dev/package/api_export/api_exporter.dart';
910
import 'package:pub_dev/package/backend.dart';
@@ -20,9 +21,11 @@ final _logger = Logger('backfill_new_fields');
2021
/// release could remove the backfill from here.
2122
Future<void> backfillNewFields() async {
2223
await migrateIsBlocked();
24+
await _removeKnownUnmappedFields();
2325
}
2426

2527
/// Migrates entities from the `isBlocked` fields to the new `isModerated` instead.
28+
@visibleForTesting
2629
Future<void> migrateIsBlocked() async {
2730
_logger.info('Migrating isBlocked...');
2831
final pkgQuery = dbService.query<Package>()..filter('isBlocked =', true);
@@ -88,3 +91,18 @@ Future<void> migrateIsBlocked() async {
8891

8992
_logger.info('isBlocked migration completed.');
9093
}
94+
95+
Future<void> _removeKnownUnmappedFields() async {
96+
await for (final p in dbService.query<Package>().run()) {
97+
if (p.additionalProperties.isEmpty) continue;
98+
if (p.additionalProperties.containsKey('isWithheld') ||
99+
p.additionalProperties.containsKey('withheldReason')) {
100+
await withRetryTransaction(dbService, (tx) async {
101+
final pkg = await tx.lookupValue<Package>(p.key);
102+
pkg.additionalProperties.remove('isWithheld');
103+
pkg.additionalProperties.remove('withheldReason');
104+
tx.insert(pkg);
105+
});
106+
}
107+
}
108+
}

0 commit comments

Comments
 (0)