@@ -7,6 +7,7 @@ import 'dart:convert';
7
7
import 'dart:io' as io;
8
8
9
9
import 'package:file/file.dart' ;
10
+ import 'package:flutter_plugin_tools/src/common/repository_package.dart' ;
10
11
import 'package:git/git.dart' ;
11
12
import 'package:http/http.dart' as http;
12
13
import 'package:meta/meta.dart' ;
@@ -58,11 +59,6 @@ class PublishPluginCommand extends PluginCommand {
58
59
_stdin = stdinput ?? io.stdin,
59
60
super (packagesDir,
60
61
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
- );
66
62
argParser.addMultiOption (_pubFlagsOption,
67
63
help:
68
64
'A list of options that will be forwarded on to pub. Separate multiple flags with commas.' );
@@ -75,8 +71,8 @@ class PublishPluginCommand extends PluginCommand {
75
71
argParser.addFlag (
76
72
_allChangedFlag,
77
73
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.' ,
80
76
defaultsTo: false ,
81
77
);
82
78
argParser.addFlag (
@@ -95,7 +91,6 @@ class PublishPluginCommand extends PluginCommand {
95
91
negatable: true );
96
92
}
97
93
98
- static const String _packageOption = 'package' ;
99
94
static const String _pubFlagsOption = 'pub-publish-flags' ;
100
95
static const String _remoteOption = 'remote' ;
101
96
static const String _allChangedFlag = 'all-changed' ;
@@ -113,7 +108,7 @@ class PublishPluginCommand extends PluginCommand {
113
108
114
109
@override
115
110
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 '
117
112
'If running this on CI, an environment variable named $_pubCredentialName must be set to a String that represents the pub credential JSON.\n '
118
113
'WARNING: Do not check in the content of pub credential JSON, it should only come from secure sources.' ;
119
114
@@ -123,14 +118,6 @@ class PublishPluginCommand extends PluginCommand {
123
118
124
119
@override
125
120
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
-
134
121
print ('Checking local repo...' );
135
122
final GitDir repository = await gitDir;
136
123
final String remoteName = getStringArg (_remoteOption);
@@ -146,36 +133,52 @@ class PublishPluginCommand extends PluginCommand {
146
133
print ('=============== DRY RUN ===============' );
147
134
}
148
135
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
+ );
161
146
162
- _pubVersionFinder.httpClient.close ();
163
147
await _finish (successful);
164
148
}
165
149
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, {
167
174
required GitDir baseGitDir,
168
175
required _RemoteInfo remoteForTagPush,
169
176
}) async {
170
- final GitVersionFinder gitVersionFinder = await retrieveVersionFinder ();
171
- final List <String > changedPubspecs =
172
- await gitVersionFinder.getChangedPubSpecs ();
173
- if (changedPubspecs.isEmpty) {
177
+ if (packages.isEmpty) {
174
178
print ('No version updates in this commit.' );
175
179
return true ;
176
180
}
177
181
178
- print ('Getting existing tags...' );
179
182
final io.ProcessResult existingTagsResult =
180
183
await baseGitDir.runCommand (< String > ['tag' , '--sort=-committerdate' ]);
181
184
final List <String > existingTags = (existingTagsResult.stdout as String )
@@ -185,16 +188,11 @@ class PublishPluginCommand extends PluginCommand {
185
188
final List <String > packagesReleased = < String > [];
186
189
final List <String > packagesFailed = < String > [];
187
190
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
+
196
194
final _CheckNeedsReleaseResult result = await _checkNeedsRelease (
197
- pubspecFile : pubspecFile ,
195
+ package : package ,
198
196
existingTags: existingTags,
199
197
);
200
198
switch (result) {
@@ -203,17 +201,15 @@ class PublishPluginCommand extends PluginCommand {
203
201
case _CheckNeedsReleaseResult .noRelease:
204
202
continue ;
205
203
case _CheckNeedsReleaseResult .failure:
206
- packagesFailed.add (pubspecFile.parent.basename );
204
+ packagesFailed.add (package.displayName );
207
205
continue ;
208
206
}
209
207
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);
215
211
} else {
216
- packagesFailed.add (pubspecFile.parent.basename );
212
+ packagesFailed.add (package.displayName );
217
213
}
218
214
print ('\n ' );
219
215
}
@@ -230,31 +226,32 @@ class PublishPluginCommand extends PluginCommand {
230
226
// Publish the package to pub with `pub publish`, then git tag the release
231
227
// and push the tag to [remoteForTagPush].
232
228
// 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,
236
232
}) async {
237
- if (! await _publishPlugin (packageDir : packageDir )) {
233
+ if (! await _publishPackage (package )) {
238
234
return false ;
239
235
}
240
236
if (! await _tagRelease (
241
- packageDir : packageDir ,
237
+ package ,
242
238
remoteForPush: remoteForTagPush,
243
239
)) {
244
240
return false ;
245
241
}
246
- print ('Released [${ packageDir . basename }] successfully.' );
242
+ print ('Published ${ package . directory . basename } successfully.' );
247
243
return true ;
248
244
}
249
245
250
246
// Returns a [_CheckNeedsReleaseResult] that indicates the result.
251
247
Future <_CheckNeedsReleaseResult > _checkNeedsRelease ({
252
- required File pubspecFile ,
248
+ required RepositoryPackage package ,
253
249
required List <String > existingTags,
254
250
}) async {
251
+ final File pubspecFile = package.pubspecFile;
255
252
if (! pubspecFile.existsSync ()) {
256
253
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 }.
258
255
Safe to ignore if the package is deleted in this commit.
259
256
''' );
260
257
return _CheckNeedsReleaseResult .noRelease;
@@ -279,7 +276,8 @@ Safe to ignore if the package is deleted in this commit.
279
276
return _CheckNeedsReleaseResult .failure;
280
277
}
281
278
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.
283
281
final Version version = pubspec.version! ;
284
282
final PubVersionFinderResponse pubVersionFinderResponse =
285
283
await _pubVersionFinder.getPackageVersion (packageName: pubspec.name);
@@ -303,31 +301,31 @@ Safe to ignore if the package is deleted in this commit.
303
301
return _CheckNeedsReleaseResult .release;
304
302
}
305
303
306
- // Publish the plugin .
304
+ // Publish the package .
307
305
//
308
306
// 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 );
311
309
if (! gitStatusOK) {
312
310
return false ;
313
311
}
314
- final bool publishOK = await _publish (packageDir );
312
+ final bool publishOK = await _publish (package );
315
313
if (! publishOK) {
316
314
return false ;
317
315
}
318
316
print ('Package published!' );
319
317
return true ;
320
318
}
321
319
322
- // Tag the release with <plugin -name>-v<version>, and, if [remoteForTagPush]
320
+ // Tag the release with <package -name>-v<version>, and, if [remoteForTagPush]
323
321
// is provided, push it to that remote.
324
322
//
325
323
// Return `true` if successful, `false` otherwise.
326
- Future <bool > _tagRelease ({
327
- required Directory packageDir,
324
+ Future <bool > _tagRelease (
325
+ RepositoryPackage package, {
328
326
_RemoteInfo ? remoteForPush,
329
327
}) async {
330
- final String tag = _getTag (packageDir );
328
+ final String tag = _getTag (package );
331
329
print ('Tagging release $tag ...' );
332
330
if (! getBoolArg (_dryRunFlag)) {
333
331
final io.ProcessResult result = await (await gitDir).runCommand (
@@ -351,6 +349,7 @@ Safe to ignore if the package is deleted in this commit.
351
349
}
352
350
353
351
Future <void > _finish (bool successful) async {
352
+ _pubVersionFinder.httpClient.close ();
354
353
await _stdinSubscription? .cancel ();
355
354
_stdinSubscription = null ;
356
355
if (successful) {
@@ -361,20 +360,14 @@ Safe to ignore if the package is deleted in this commit.
361
360
}
362
361
}
363
362
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 {
376
364
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
+ ],
378
371
throwOnError: false ,
379
372
);
380
373
if (statusResult.exitCode != 0 ) {
@@ -402,10 +395,10 @@ Safe to ignore if the package is deleted in this commit.
402
395
return getRemoteUrlResult.stdout as String ? ;
403
396
}
404
397
405
- Future <bool > _publish (Directory packageDir ) async {
398
+ Future <bool > _publish (RepositoryPackage package ) async {
406
399
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 ' );
409
402
if (getBoolArg (_dryRunFlag)) {
410
403
return true ;
411
404
}
@@ -419,22 +412,22 @@ Safe to ignore if the package is deleted in this commit.
419
412
420
413
final io.Process publish = await processRunner.start (
421
414
flutterCommand, < String > ['pub' , 'publish' ] + publishFlags,
422
- workingDirectory: packageDir );
415
+ workingDirectory: package.directory );
423
416
publish.stdout.transform (utf8.decoder).listen ((String data) => print (data));
424
417
publish.stderr.transform (utf8.decoder).listen ((String data) => print (data));
425
418
_stdinSubscription ?? = _stdin
426
419
.transform (utf8.decoder)
427
420
.listen ((String data) => publish.stdin.writeln (data));
428
421
final int result = await publish.exitCode;
429
422
if (result != 0 ) {
430
- printError ('Publish ${packageDir .basename } failed.' );
423
+ printError ('Publishing ${package . directory .basename } failed.' );
431
424
return false ;
432
425
}
433
426
return true ;
434
427
}
435
428
436
- String _getTag (Directory packageDir ) {
437
- final File pubspecFile = packageDir. childFile ( 'pubspec.yaml' ) ;
429
+ String _getTag (RepositoryPackage package ) {
430
+ final File pubspecFile = package.pubspecFile ;
438
431
final YamlMap pubspecYaml =
439
432
loadYaml (pubspecFile.readAsStringSync ()) as YamlMap ;
440
433
final String name = pubspecYaml['name' ] as String ;
0 commit comments