Fix publish cmd (#38490)

diff --git a/packages/flutter_tools/lib/src/commands/packages.dart b/packages/flutter_tools/lib/src/commands/packages.dart
index 8b60b93..6078a17 100644
--- a/packages/flutter_tools/lib/src/commands/packages.dart
+++ b/packages/flutter_tools/lib/src/commands/packages.dart
@@ -17,8 +17,8 @@
     addSubcommand(PackagesGetCommand('get', false));
     addSubcommand(PackagesGetCommand('upgrade', true));
     addSubcommand(PackagesTestCommand());
+    addSubcommand(PackagesPublishCommand());
     addSubcommand(PackagesForwardCommand('downgrade', 'Downgrade packages in a Flutter project', requiresPubspec: true));
-    addSubcommand(PackagesForwardCommand('publish', 'Publish the current package to pub.dev', requiresPubspec: true));
     addSubcommand(PackagesForwardCommand('deps', 'Print package dependencies', requiresPubspec: true));
     addSubcommand(PackagesForwardCommand('run', 'Run an executable from a package', requiresPubspec: true));
     addSubcommand(PackagesForwardCommand('cache', 'Work with the Pub system cache'));
@@ -170,6 +170,47 @@
   }
 }
 
+class PackagesPublishCommand extends FlutterCommand {
+  PackagesPublishCommand() {
+    requiresPubspecYaml();
+    argParser.addFlag('dry-run',
+      abbr: 'n',
+      negatable: false,
+      help: 'Validate but do not publish the package.',
+    );
+    argParser.addFlag('force',
+      abbr: 'f',
+      negatable: false,
+      help: 'Publish without confirmation if there are no errors.',
+    );
+  }
+
+  @override
+  String get name => 'publish';
+
+  @override
+  String get description {
+    return 'Publish the current package to pub.dev';
+  }
+
+  @override
+  String get invocation {
+    return '${runner.executableName} pub publish [--dry-run]';
+  }
+
+  @override
+  Future<FlutterCommandResult> runCommand() async {
+    final List<String> args = <String>[
+      ...argResults.rest,
+      if (argResults['dry-run']) '--dry-run',
+      if (argResults['force']) '--force',
+    ];
+    Cache.releaseLockEarly();
+    await pubInteractively(<String>['publish', ...args]);
+    return null;
+  }
+}
+
 class PackagesForwardCommand extends FlutterCommand {
   PackagesForwardCommand(this._commandName, this._description, {bool requiresPubspec = false}) {
     if (requiresPubspec) {
diff --git a/packages/flutter_tools/test/general.shard/commands/packages_test.dart b/packages/flutter_tools/test/general.shard/commands/packages_test.dart
index 02a20d7..e92e9a7 100644
--- a/packages/flutter_tools/test/general.shard/commands/packages_test.dart
+++ b/packages/flutter_tools/test/general.shard/commands/packages_test.dart
@@ -348,7 +348,7 @@
     testUsingContext('pub publish', () async {
       final PromptingProcess process = PromptingProcess();
       mockProcessManager.processFactory = (List<String> commands) => process;
-      final Future<void> runPackages = createTestCommandRunner(PackagesCommand()).run(<String>['packages', 'pub', 'publish']);
+      final Future<void> runPackages = createTestCommandRunner(PackagesCommand()).run(<String>['pub', 'publish']);
       final Future<void> runPrompt = process.showPrompt('Proceed (y/n)? ', <String>['hello', 'world']);
       final Future<void> simulateUserInput = Future<void>(() {
         mockStdio.simulateStdin('y');
@@ -370,12 +370,23 @@
     });
 
     testUsingContext('publish', () async {
-      await createTestCommandRunner(PackagesCommand()).run(<String>['packages', 'publish']);
+      await createTestCommandRunner(PackagesCommand()).run(<String>['pub', 'publish']);
       final List<String> commands = mockProcessManager.commands;
-      expect(commands, hasLength(3));
+      expect(commands, hasLength(2));
       expect(commands[0], matches(r'dart-sdk[\\/]bin[\\/]pub'));
-      expect(commands[1], '--trace');
-      expect(commands[2], 'publish');
+      expect(commands[1], 'publish');
+    }, overrides: <Type, Generator>{
+      ProcessManager: () => mockProcessManager,
+      Stdio: () => mockStdio,
+      BotDetector: () => const AlwaysTrueBotDetector(),
+    });
+
+    testUsingContext('packages publish', () async {
+      await createTestCommandRunner(PackagesCommand()).run(<String>['packages', 'pub', 'publish']);
+      final List<String> commands = mockProcessManager.commands;
+      expect(commands, hasLength(2));
+      expect(commands[0], matches(r'dart-sdk[\\/]bin[\\/]pub'));
+      expect(commands[1], 'publish');
     }, overrides: <Type, Generator>{
       ProcessManager: () => mockProcessManager,
       Stdio: () => mockStdio,