Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit e02b647

Browse files
[flutter_plugin_tools] Switch 'publish' from --package to --packages (#4285)
Replaces the `publish`-command-specific `--package` flag with support for `--packages`, and unifies the flow with the existing looping for `--all-changed`. This better aligns the command's API with the rest of the commands, and reduces divergence in the two flows (e.g., `--package` would attempt to publish and fail if the package was already published, whereas now using `--packages` will use the flow that pre-checks against `pub.dev`). It also sets up a structure that will allow easily converting it to the new base package looping command that most other commands now use, which will be done in a follow-up. Since all calls now attempt to contact `pub.dev`, the tests have been adjusted to always mock the HTTP client so they will be hermetic. Part of flutter/flutter#83413
1 parent e07f161 commit e02b647

File tree

3 files changed

+168
-339
lines changed

3 files changed

+168
-339
lines changed

script/tool/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
- `build-examples` now supports UWP plugins via a `--winuwp` flag.
88
- **Breaking change**: `publish` no longer accepts `--no-tag-release` or
99
`--no-push-flags`. Releases now always tag and push.
10+
- **Breaking change**: `publish`'s `--package` flag has been replaced with the
11+
`--packages` flag used by most other packages.
1012

1113
## 0.5.0
1214

script/tool/lib/src/publish_plugin_command.dart

Lines changed: 82 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'dart:convert';
77
import 'dart:io' as io;
88

99
import 'package:file/file.dart';
10+
import 'package:flutter_plugin_tools/src/common/repository_package.dart';
1011
import 'package:git/git.dart';
1112
import 'package:http/http.dart' as http;
1213
import 'package:meta/meta.dart';
@@ -58,11 +59,6 @@ class PublishPluginCommand extends PluginCommand {
5859
_stdin = stdinput ?? io.stdin,
5960
super(packagesDir,
6061
platform: platform, processRunner: processRunner, gitDir: gitDir) {
61-
argParser.addOption(
62-
_packageOption,
63-
help: 'The package to publish.'
64-
'If the package directory name is different than its pubspec.yaml name, then this should specify the directory.',
65-
);
6662
argParser.addMultiOption(_pubFlagsOption,
6763
help:
6864
'A list of options that will be forwarded on to pub. Separate multiple flags with commas.');
@@ -75,8 +71,8 @@ class PublishPluginCommand extends PluginCommand {
7571
argParser.addFlag(
7672
_allChangedFlag,
7773
help:
78-
'Release all plugins that contains pubspec changes at the current commit compares to the base-sha.\n'
79-
'The $_packageOption option is ignored if this is on.',
74+
'Release all packages that contains pubspec changes at the current commit compares to the base-sha.\n'
75+
'The --packages option is ignored if this is on.',
8076
defaultsTo: false,
8177
);
8278
argParser.addFlag(
@@ -95,7 +91,6 @@ class PublishPluginCommand extends PluginCommand {
9591
negatable: true);
9692
}
9793

98-
static const String _packageOption = 'package';
9994
static const String _pubFlagsOption = 'pub-publish-flags';
10095
static const String _remoteOption = 'remote';
10196
static const String _allChangedFlag = 'all-changed';
@@ -113,7 +108,7 @@ class PublishPluginCommand extends PluginCommand {
113108

114109
@override
115110
final String description =
116-
'Attempts to publish the given plugin and tag its release on GitHub.\n'
111+
'Attempts to publish the given packages and tag the release(s) on GitHub.\n'
117112
'If running this on CI, an environment variable named $_pubCredentialName must be set to a String that represents the pub credential JSON.\n'
118113
'WARNING: Do not check in the content of pub credential JSON, it should only come from secure sources.';
119114

@@ -123,14 +118,6 @@ class PublishPluginCommand extends PluginCommand {
123118

124119
@override
125120
Future<void> run() async {
126-
final String packageName = getStringArg(_packageOption);
127-
final bool publishAllChanged = getBoolArg(_allChangedFlag);
128-
if (packageName.isEmpty && !publishAllChanged) {
129-
printError(
130-
'Must specify a package to publish. See `plugin_tools help publish-plugin`.');
131-
throw ToolExit(1);
132-
}
133-
134121
print('Checking local repo...');
135122
final GitDir repository = await gitDir;
136123
final String remoteName = getStringArg(_remoteOption);
@@ -146,36 +133,52 @@ class PublishPluginCommand extends PluginCommand {
146133
print('=============== DRY RUN ===============');
147134
}
148135

149-
bool successful;
150-
if (publishAllChanged) {
151-
successful = await _publishAllChangedPackages(
152-
baseGitDir: repository,
153-
remoteForTagPush: remote,
154-
);
155-
} else {
156-
successful = await _publishAndTagPackage(
157-
packageDir: _getPackageDir(packageName),
158-
remoteForTagPush: remote,
159-
);
160-
}
136+
final List<PackageEnumerationEntry> packages = await _getPackagesToProcess()
137+
.where((PackageEnumerationEntry entry) => !entry.excluded)
138+
.toList();
139+
bool successful = true;
140+
141+
successful = await _publishPackages(
142+
packages,
143+
baseGitDir: repository,
144+
remoteForTagPush: remote,
145+
);
161146

162-
_pubVersionFinder.httpClient.close();
163147
await _finish(successful);
164148
}
165149

166-
Future<bool> _publishAllChangedPackages({
150+
Stream<PackageEnumerationEntry> _getPackagesToProcess() async* {
151+
if (getBoolArg(_allChangedFlag)) {
152+
final GitVersionFinder gitVersionFinder = await retrieveVersionFinder();
153+
final List<String> changedPubspecs =
154+
await gitVersionFinder.getChangedPubSpecs();
155+
156+
for (final String pubspecPath in changedPubspecs) {
157+
// Convert git's Posix-style paths to a path that matches the current
158+
// filesystem.
159+
final String localStylePubspecPath =
160+
path.joinAll(p.posix.split(pubspecPath));
161+
final File pubspecFile = packagesDir.fileSystem
162+
.directory((await gitDir).path)
163+
.childFile(localStylePubspecPath);
164+
yield PackageEnumerationEntry(RepositoryPackage(pubspecFile.parent),
165+
excluded: false);
166+
}
167+
} else {
168+
yield* getTargetPackages(filterExcluded: false);
169+
}
170+
}
171+
172+
Future<bool> _publishPackages(
173+
List<PackageEnumerationEntry> packages, {
167174
required GitDir baseGitDir,
168175
required _RemoteInfo remoteForTagPush,
169176
}) async {
170-
final GitVersionFinder gitVersionFinder = await retrieveVersionFinder();
171-
final List<String> changedPubspecs =
172-
await gitVersionFinder.getChangedPubSpecs();
173-
if (changedPubspecs.isEmpty) {
177+
if (packages.isEmpty) {
174178
print('No version updates in this commit.');
175179
return true;
176180
}
177181

178-
print('Getting existing tags...');
179182
final io.ProcessResult existingTagsResult =
180183
await baseGitDir.runCommand(<String>['tag', '--sort=-committerdate']);
181184
final List<String> existingTags = (existingTagsResult.stdout as String)
@@ -185,16 +188,11 @@ class PublishPluginCommand extends PluginCommand {
185188
final List<String> packagesReleased = <String>[];
186189
final List<String> packagesFailed = <String>[];
187190

188-
for (final String pubspecPath in changedPubspecs) {
189-
// Convert git's Posix-style paths to a path that matches the current
190-
// filesystem.
191-
final String localStylePubspecPath =
192-
path.joinAll(p.posix.split(pubspecPath));
193-
final File pubspecFile = packagesDir.fileSystem
194-
.directory(baseGitDir.path)
195-
.childFile(localStylePubspecPath);
191+
for (final PackageEnumerationEntry entry in packages) {
192+
final RepositoryPackage package = entry.package;
193+
196194
final _CheckNeedsReleaseResult result = await _checkNeedsRelease(
197-
pubspecFile: pubspecFile,
195+
package: package,
198196
existingTags: existingTags,
199197
);
200198
switch (result) {
@@ -203,17 +201,15 @@ class PublishPluginCommand extends PluginCommand {
203201
case _CheckNeedsReleaseResult.noRelease:
204202
continue;
205203
case _CheckNeedsReleaseResult.failure:
206-
packagesFailed.add(pubspecFile.parent.basename);
204+
packagesFailed.add(package.displayName);
207205
continue;
208206
}
209207
print('\n');
210-
if (await _publishAndTagPackage(
211-
packageDir: pubspecFile.parent,
212-
remoteForTagPush: remoteForTagPush,
213-
)) {
214-
packagesReleased.add(pubspecFile.parent.basename);
208+
if (await _publishAndTagPackage(package,
209+
remoteForTagPush: remoteForTagPush)) {
210+
packagesReleased.add(package.displayName);
215211
} else {
216-
packagesFailed.add(pubspecFile.parent.basename);
212+
packagesFailed.add(package.displayName);
217213
}
218214
print('\n');
219215
}
@@ -230,31 +226,32 @@ class PublishPluginCommand extends PluginCommand {
230226
// Publish the package to pub with `pub publish`, then git tag the release
231227
// and push the tag to [remoteForTagPush].
232228
// Returns `true` if publishing and tagging are successful.
233-
Future<bool> _publishAndTagPackage({
234-
required Directory packageDir,
235-
required _RemoteInfo remoteForTagPush,
229+
Future<bool> _publishAndTagPackage(
230+
RepositoryPackage package, {
231+
_RemoteInfo? remoteForTagPush,
236232
}) async {
237-
if (!await _publishPlugin(packageDir: packageDir)) {
233+
if (!await _publishPackage(package)) {
238234
return false;
239235
}
240236
if (!await _tagRelease(
241-
packageDir: packageDir,
237+
package,
242238
remoteForPush: remoteForTagPush,
243239
)) {
244240
return false;
245241
}
246-
print('Released [${packageDir.basename}] successfully.');
242+
print('Published ${package.directory.basename} successfully.');
247243
return true;
248244
}
249245

250246
// Returns a [_CheckNeedsReleaseResult] that indicates the result.
251247
Future<_CheckNeedsReleaseResult> _checkNeedsRelease({
252-
required File pubspecFile,
248+
required RepositoryPackage package,
253249
required List<String> existingTags,
254250
}) async {
251+
final File pubspecFile = package.pubspecFile;
255252
if (!pubspecFile.existsSync()) {
256253
print('''
257-
The file at The pubspec file at ${pubspecFile.path} does not exist. Publishing will not happen for ${pubspecFile.parent.basename}.
254+
The pubspec file at ${pubspecFile.path} does not exist. Publishing will not happen for ${pubspecFile.parent.basename}.
258255
Safe to ignore if the package is deleted in this commit.
259256
''');
260257
return _CheckNeedsReleaseResult.noRelease;
@@ -279,7 +276,8 @@ Safe to ignore if the package is deleted in this commit.
279276
return _CheckNeedsReleaseResult.failure;
280277
}
281278

282-
// Check if the package named `packageName` with `version` has already published.
279+
// Check if the package named `packageName` with `version` has already
280+
// been published.
283281
final Version version = pubspec.version!;
284282
final PubVersionFinderResponse pubVersionFinderResponse =
285283
await _pubVersionFinder.getPackageVersion(packageName: pubspec.name);
@@ -303,31 +301,31 @@ Safe to ignore if the package is deleted in this commit.
303301
return _CheckNeedsReleaseResult.release;
304302
}
305303

306-
// Publish the plugin.
304+
// Publish the package.
307305
//
308306
// Returns `true` if successful, `false` otherwise.
309-
Future<bool> _publishPlugin({required Directory packageDir}) async {
310-
final bool gitStatusOK = await _checkGitStatus(packageDir);
307+
Future<bool> _publishPackage(RepositoryPackage package) async {
308+
final bool gitStatusOK = await _checkGitStatus(package);
311309
if (!gitStatusOK) {
312310
return false;
313311
}
314-
final bool publishOK = await _publish(packageDir);
312+
final bool publishOK = await _publish(package);
315313
if (!publishOK) {
316314
return false;
317315
}
318316
print('Package published!');
319317
return true;
320318
}
321319

322-
// Tag the release with <plugin-name>-v<version>, and, if [remoteForTagPush]
320+
// Tag the release with <package-name>-v<version>, and, if [remoteForTagPush]
323321
// is provided, push it to that remote.
324322
//
325323
// Return `true` if successful, `false` otherwise.
326-
Future<bool> _tagRelease({
327-
required Directory packageDir,
324+
Future<bool> _tagRelease(
325+
RepositoryPackage package, {
328326
_RemoteInfo? remoteForPush,
329327
}) async {
330-
final String tag = _getTag(packageDir);
328+
final String tag = _getTag(package);
331329
print('Tagging release $tag...');
332330
if (!getBoolArg(_dryRunFlag)) {
333331
final io.ProcessResult result = await (await gitDir).runCommand(
@@ -351,6 +349,7 @@ Safe to ignore if the package is deleted in this commit.
351349
}
352350

353351
Future<void> _finish(bool successful) async {
352+
_pubVersionFinder.httpClient.close();
354353
await _stdinSubscription?.cancel();
355354
_stdinSubscription = null;
356355
if (successful) {
@@ -361,20 +360,14 @@ Safe to ignore if the package is deleted in this commit.
361360
}
362361
}
363362

364-
// Returns the packageDirectory based on the package name.
365-
// Throws ToolExit if the `package` doesn't exist.
366-
Directory _getPackageDir(String packageName) {
367-
final Directory packageDir = packagesDir.childDirectory(packageName);
368-
if (!packageDir.existsSync()) {
369-
printError('${packageDir.absolute.path} does not exist.');
370-
throw ToolExit(1);
371-
}
372-
return packageDir;
373-
}
374-
375-
Future<bool> _checkGitStatus(Directory packageDir) async {
363+
Future<bool> _checkGitStatus(RepositoryPackage package) async {
376364
final io.ProcessResult statusResult = await (await gitDir).runCommand(
377-
<String>['status', '--porcelain', '--ignored', packageDir.absolute.path],
365+
<String>[
366+
'status',
367+
'--porcelain',
368+
'--ignored',
369+
package.directory.absolute.path
370+
],
378371
throwOnError: false,
379372
);
380373
if (statusResult.exitCode != 0) {
@@ -402,10 +395,10 @@ Safe to ignore if the package is deleted in this commit.
402395
return getRemoteUrlResult.stdout as String?;
403396
}
404397

405-
Future<bool> _publish(Directory packageDir) async {
398+
Future<bool> _publish(RepositoryPackage package) async {
406399
final List<String> publishFlags = getStringListArg(_pubFlagsOption);
407-
print(
408-
'Running `pub publish ${publishFlags.join(' ')}` in ${packageDir.absolute.path}...\n');
400+
print('Running `pub publish ${publishFlags.join(' ')}` in '
401+
'${package.directory.absolute.path}...\n');
409402
if (getBoolArg(_dryRunFlag)) {
410403
return true;
411404
}
@@ -419,22 +412,22 @@ Safe to ignore if the package is deleted in this commit.
419412

420413
final io.Process publish = await processRunner.start(
421414
flutterCommand, <String>['pub', 'publish'] + publishFlags,
422-
workingDirectory: packageDir);
415+
workingDirectory: package.directory);
423416
publish.stdout.transform(utf8.decoder).listen((String data) => print(data));
424417
publish.stderr.transform(utf8.decoder).listen((String data) => print(data));
425418
_stdinSubscription ??= _stdin
426419
.transform(utf8.decoder)
427420
.listen((String data) => publish.stdin.writeln(data));
428421
final int result = await publish.exitCode;
429422
if (result != 0) {
430-
printError('Publish ${packageDir.basename} failed.');
423+
printError('Publishing ${package.directory.basename} failed.');
431424
return false;
432425
}
433426
return true;
434427
}
435428

436-
String _getTag(Directory packageDir) {
437-
final File pubspecFile = packageDir.childFile('pubspec.yaml');
429+
String _getTag(RepositoryPackage package) {
430+
final File pubspecFile = package.pubspecFile;
438431
final YamlMap pubspecYaml =
439432
loadYaml(pubspecFile.readAsStringSync()) as YamlMap;
440433
final String name = pubspecYaml['name'] as String;

0 commit comments

Comments
 (0)