Skip to content

Commit

Permalink
Migrate some admin tool to actions. (#8137)
Browse files Browse the repository at this point in the history
  • Loading branch information
isoos authored Oct 15, 2024
1 parent ba5b411 commit a9568e4
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 93 deletions.
4 changes: 4 additions & 0 deletions app/lib/admin/actions/actions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ import 'moderation_case_list.dart';
import 'moderation_case_resolve.dart';
import 'moderation_case_update.dart';
import 'moderation_transparency_metrics.dart';
import 'package_discontinue.dart';
import 'package_info.dart';
import 'package_latest_update.dart';
import 'package_reservation_create.dart';
import 'package_reservation_delete.dart';
import 'package_reservation_list.dart';
Expand Down Expand Up @@ -102,7 +104,9 @@ final class AdminAction {
moderationCaseResolve,
moderationCaseUpdate,
moderationTransparencyMetrics,
packageDiscontinue,
packageInfo,
packageLatestUpdate,
packageReservationCreate,
packageReservationDelete,
packageReservationList,
Expand Down
67 changes: 67 additions & 0 deletions app/lib/admin/actions/package_discontinue.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:clock/clock.dart';
import 'package:pub_dev/package/backend.dart';
import 'package:pub_dev/package/models.dart';
import 'package:pub_dev/shared/datastore.dart';

import 'actions.dart';

final packageDiscontinue = AdminAction(
name: 'package-discontinue',
summary: 'Sets the package discontinued.',
description: '''
Sets the `Package.isDiscontinued` and `Package.replacedBy` properties.
''',
options: {
'package': 'The package to be discontinued.',
'value': 'The value to set (defaults to true).',
'replaced-by':
'The Package.replacedBy field (if not set will be set to `null`).',
},
invoke: (options) async {
final package = options['package'];
InvalidInputException.check(
package != null && package.isNotEmpty,
'`package` must be given',
);
final value = options['value'] ?? 'true';
InvalidInputException.checkAnyOf(value, 'value', ['true', 'false']);
final valueToSet = value == 'true';

final p = await packageBackend.lookupPackage(package!);
if (p == null) {
throw NotFoundException.resource(package);
}

final replacedBy = options['replaced-by'];
if (replacedBy != null) {
final rp = await packageBackend.lookupPackage(replacedBy);
if (rp == null) {
throw NotFoundException('Replacing package "$replacedBy" not found.');
}
}

final info = await withRetryTransaction(dbService, (tx) async {
final pkg = await tx.lookupOrNull<Package>(p.key);
if (pkg == null) {
throw NotFoundException.resource(package);
}
pkg.isDiscontinued = valueToSet;
pkg.replacedBy = valueToSet ? replacedBy : null;
pkg.updated = clock.now().toUtc();
tx.insert(pkg);
return pkg;
});

return {
'package': {
'name': info.name,
'isDiscontinued': info.isDiscontinued,
'replacedBy': info.replacedBy,
},
};
},
);
39 changes: 39 additions & 0 deletions app/lib/admin/actions/package_latest_update.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:pub_dev/package/backend.dart';

import 'actions.dart';

final packageLatestUpdate = AdminAction(
name: 'package-latest-update',
summary: 'Updates the latest version of a package or all packages.',
description: '''
Ensures Package.latestVersion / latestPreviewVersion / latestPrereleaseVersion is up-to-date.
When no package is specified, all packages will be updated.
''',
options: {
'package': 'The package to be updated (optional).',
'concurrency':
'The concurrently running update operations (defaults to 10).',
},
invoke: (options) async {
final package = options['package'];
final concurrency = int.parse(options['concurrency'] ?? '10');

if (package != null) {
final updated = await packageBackend.updatePackageVersions(package);
return {
'updated': updated,
};
} else {
final stat = await packageBackend.updateAllPackageVersions(
concurrency: concurrency);
return {
'updatedCount': stat,
};
}
},
);
4 changes: 0 additions & 4 deletions app/lib/admin/backend.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,11 @@ import 'tools/delete_all_staging.dart';
import 'tools/list_package_blocked.dart';
import 'tools/list_tools.dart';
import 'tools/notify_service.dart';
import 'tools/package_discontinued.dart';
import 'tools/package_publisher.dart';
import 'tools/publisher_member.dart';
import 'tools/recent_uploaders.dart';
import 'tools/set_package_blocked.dart';
import 'tools/set_user_blocked.dart';
import 'tools/update_package_versions.dart';
import 'tools/user_merger.dart';

final _logger = Logger('pub.admin.backend');
Expand All @@ -69,9 +67,7 @@ final Map<String, Tool> availableTools = {
'delete-all-staging': executeDeleteAllStaging,
'list-package-blocked': executeListPackageBlocked,
'notify-service': executeNotifyService,
'package-discontinued': executeSetPackageDiscontinued,
'package-publisher': executeSetPackagePublisher,
'update-package-versions': executeUpdatePackageVersions,
'recent-uploaders': executeRecentUploaders,
'publisher-member': executePublisherMember,
'publisher-invite-member': executePublisherInviteMember,
Expand Down
55 changes: 0 additions & 55 deletions app/lib/admin/tools/package_discontinued.dart

This file was deleted.

34 changes: 0 additions & 34 deletions app/lib/admin/tools/update_package_versions.dart

This file was deleted.

42 changes: 42 additions & 0 deletions app/test/admin/package_actions_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,47 @@ void main() {
}
});
});

testWithProfile('discontinue', fn: () async {
final client = createPubApiClient(authToken: siteAdminToken);
final rs = await client.adminInvokeAction(
'package-discontinue',
AdminInvokeActionArguments(arguments: {
'package': 'oxygen',
'replaced-by': 'neon',
}),
);
expect(rs.output, {
'package': {
'name': 'oxygen',
'isDiscontinued': true,
'replacedBy': 'neon',
},
});
});

testWithProfile('update latest on a single package', fn: () async {
final client = createPubApiClient(authToken: siteAdminToken);
final rs = await client.adminInvokeAction(
'package-latest-update',
AdminInvokeActionArguments(arguments: {
'package': 'oxygen',
}),
);
expect(rs.output, {
'updated': false,
});
});

testWithProfile('update latest on all packages', fn: () async {
final client = createPubApiClient(authToken: siteAdminToken);
final rs = await client.adminInvokeAction(
'package-latest-update',
AdminInvokeActionArguments(arguments: {}),
);
expect(rs.output, {
'updatedCount': 0,
});
});
});
}

0 comments on commit a9568e4

Please sign in to comment.