From 0e08c5080d216258610fa04def2e7e7ae3616ad0 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Thu, 17 Jun 2021 15:01:01 -0700 Subject: [PATCH 1/5] check already published against pub --- .../tool/lib/src/publish_plugin_command.dart | 39 ++- .../test/publish_plugin_command_test.dart | 255 ++++++++++++++---- 2 files changed, 214 insertions(+), 80 deletions(-) diff --git a/script/tool/lib/src/publish_plugin_command.dart b/script/tool/lib/src/publish_plugin_command.dart index 70ec75bc7b76..1e1c2a50ab1b 100644 --- a/script/tool/lib/src/publish_plugin_command.dart +++ b/script/tool/lib/src/publish_plugin_command.dart @@ -8,6 +8,7 @@ import 'dart:io' as io; import 'package:file/file.dart'; import 'package:git/git.dart'; +import 'package:http/http.dart' as http; import 'package:meta/meta.dart'; import 'package:path/path.dart' as p; import 'package:pub_semver/pub_semver.dart'; @@ -18,6 +19,7 @@ import 'common/core.dart'; import 'common/git_version_finder.dart'; import 'common/plugin_command.dart'; import 'common/process_runner.dart'; +import 'common/pub_version_finder.dart'; @immutable class _RemoteInfo { @@ -49,7 +51,9 @@ class PublishPluginCommand extends PluginCommand { Print print = print, io.Stdin? stdinput, GitDir? gitDir, - }) : _print = print, + http.Client? httpClient, + }) : _pubVersionFinder = + PubVersionFinder(httpClient: httpClient ?? http.Client()), _print = print, _stdin = stdinput ?? io.stdin, super(packagesDir, processRunner: processRunner, gitDir: gitDir) { argParser.addOption( @@ -131,6 +135,7 @@ class PublishPluginCommand extends PluginCommand { final Print _print; final io.Stdin _stdin; StreamSubscription? _stdinSubscription; + final PubVersionFinder _pubVersionFinder; @override Future run() async { @@ -182,6 +187,8 @@ class PublishPluginCommand extends PluginCommand { remoteForTagPush: remote, ); } + + _pubVersionFinder.httpClient.close(); await _finish(successful); } @@ -196,12 +203,6 @@ class PublishPluginCommand extends PluginCommand { _print('No version updates in this commit.'); return true; } - _print('Getting existing tags...'); - final io.ProcessResult existingTagsResult = - await baseGitDir.runCommand(['tag', '--sort=-committerdate']); - final List existingTags = (existingTagsResult.stdout as String) - .split('\n') - ..removeWhere((String element) => element.isEmpty); final List packagesReleased = []; final List packagesFailed = []; @@ -213,7 +214,6 @@ class PublishPluginCommand extends PluginCommand { final _CheckNeedsReleaseResult result = await _checkNeedsRelease( pubspecFile: pubspecFile, gitVersionFinder: gitVersionFinder, - existingTags: existingTags, ); switch (result) { case _CheckNeedsReleaseResult.release: @@ -272,7 +272,6 @@ class PublishPluginCommand extends PluginCommand { Future<_CheckNeedsReleaseResult> _checkNeedsRelease({ required File pubspecFile, required GitVersionFinder gitVersionFinder, - required List existingTags, }) async { if (!pubspecFile.existsSync()) { _print(''' @@ -293,21 +292,13 @@ Safe to ignore if the package is deleted in this commit. return _CheckNeedsReleaseResult.failure; } - // Get latest tagged version and compare with the current version. - // TODO(cyanglaz): Check latest version of the package on pub instead of git - // https://github.com/flutter/flutter/issues/81047 - - final String latestTag = existingTags.firstWhere( - (String tag) => tag.split('-v').first == pubspec.name, - orElse: () => ''); - if (latestTag.isNotEmpty) { - final String latestTaggedVersion = latestTag.split('-v').last; - final Version latestVersion = Version.parse(latestTaggedVersion); - if (pubspec.version! < latestVersion) { - _print( - 'The new version (${pubspec.version}) is lower than the current version ($latestVersion) for ${pubspec.name}.\nThis git commit is a revert, no release is tagged.'); - return _CheckNeedsReleaseResult.noRelease; - } + // Check if the package named `packageName` with `version` has already published. + final Version version = pubspec.version!; + final PubVersionFinderResponse pubVersionFinderResponse = + await _pubVersionFinder.getPackageVersion(package: pubspec.name); + if (pubVersionFinderResponse.versions.contains(version)) { + _print('The version $version of ${pubspec.name} has already been published, skip.'); + return _CheckNeedsReleaseResult.noRelease; } return _CheckNeedsReleaseResult.release; } diff --git a/script/tool/test/publish_plugin_command_test.dart b/script/tool/test/publish_plugin_command_test.dart index ef682bfe61f6..2cceb3c08e8c 100644 --- a/script/tool/test/publish_plugin_command_test.dart +++ b/script/tool/test/publish_plugin_command_test.dart @@ -13,6 +13,8 @@ import 'package:flutter_plugin_tools/src/common/core.dart'; import 'package:flutter_plugin_tools/src/common/process_runner.dart'; import 'package:flutter_plugin_tools/src/publish_plugin_command.dart'; import 'package:git/git.dart'; +import 'package:http/http.dart' as http; +import 'package:http/testing.dart'; import 'package:mockito/mockito.dart'; import 'package:test/test.dart'; @@ -427,6 +429,37 @@ void main() { }); test('can release newly created plugins', () async { + const Map httpResponsePlugin1 = { + 'name': 'plugin1', + 'versions': [], + }; + + const Map httpResponsePlugin2 = { + 'name': 'plugin2', + 'versions': [], + }; + + final MockClient mockClient = MockClient((http.Request request) async { + if (request.url.pathSegments.last == 'plugin1.json') { + return http.Response(json.encode(httpResponsePlugin1), 200); + } else if (request.url.pathSegments.last == 'plugin2.json') { + return http.Response(json.encode(httpResponsePlugin2), 200); + } + return http.Response('', 500); + }); + final PublishPluginCommand command = PublishPluginCommand(packagesDir, + processRunner: processRunner, + print: (Object? message) => printedMessages.add(message.toString()), + stdinput: mockStdin, + httpClient: mockClient, + gitDir: gitDir); + + commandRunner = CommandRunner( + 'publish_check_command', + 'Test for publish-check command.', + ); + commandRunner.addCommand(command); + // Non-federated final Directory pluginDir1 = createFakePlugin('plugin1', packagesDir, withSingleExample: true); @@ -449,7 +482,6 @@ void main() { containsAllInOrder([ 'Checking local repo...', 'Local repo is ready!', - 'Getting existing tags...', 'Running `pub publish ` in ${pluginDir1.path}...\n', 'Running `pub publish ` in ${pluginDir2.path}...\n', 'Packages released: plugin1, plugin2', @@ -466,6 +498,44 @@ void main() { test('can release newly created plugins, while there are existing plugins', () async { + const Map httpResponsePlugin0 = { + 'name': 'plugin0', + 'versions': ['0.0.1'], + }; + + const Map httpResponsePlugin1 = { + 'name': 'plugin1', + 'versions': [], + }; + + const Map httpResponsePlugin2 = { + 'name': 'plugin2', + 'versions': [], + }; + + final MockClient mockClient = MockClient((http.Request request) async { + if (request.url.pathSegments.last == 'plugin0.json') { + return http.Response(json.encode(httpResponsePlugin0), 200); + } else if (request.url.pathSegments.last == 'plugin1.json') { + return http.Response(json.encode(httpResponsePlugin1), 200); + } else if (request.url.pathSegments.last == 'plugin2.json') { + return http.Response(json.encode(httpResponsePlugin2), 200); + } + return http.Response('', 500); + }); + final PublishPluginCommand command = PublishPluginCommand(packagesDir, + processRunner: processRunner, + print: (Object? message) => printedMessages.add(message.toString()), + stdinput: mockStdin, + httpClient: mockClient, + gitDir: gitDir); + + commandRunner = CommandRunner( + 'publish_check_command', + 'Test for publish-check command.', + ); + commandRunner.addCommand(command); + // Prepare an exiting plugin and tag it final Directory pluginDir0 = createFakePlugin('plugin0', packagesDir, withSingleExample: true); @@ -500,7 +570,6 @@ void main() { containsAllInOrder([ 'Checking local repo...', 'Local repo is ready!', - 'Getting existing tags...', 'Running `pub publish ` in ${pluginDir1.path}...\n', 'Running `pub publish ` in ${pluginDir2.path}...\n', 'Packages released: plugin1, plugin2', @@ -516,6 +585,36 @@ void main() { }); test('can release newly created plugins, dry run', () async { + const Map httpResponsePlugin1 = { + 'name': 'plugin1', + 'versions': [], + }; + + const Map httpResponsePlugin2 = { + 'name': 'plugin2', + 'versions': [], + }; + + final MockClient mockClient = MockClient((http.Request request) async { + if (request.url.pathSegments.last == 'plugin1.json') { + return http.Response(json.encode(httpResponsePlugin1), 200); + } else if (request.url.pathSegments.last == 'plugin2.json') { + return http.Response(json.encode(httpResponsePlugin2), 200); + } + return http.Response('', 500); + }); + final PublishPluginCommand command = PublishPluginCommand(packagesDir, + processRunner: processRunner, + print: (Object? message) => printedMessages.add(message.toString()), + stdinput: mockStdin, + httpClient: mockClient, + gitDir: gitDir); + + commandRunner = CommandRunner( + 'publish_check_command', + 'Test for publish-check command.', + ); + commandRunner.addCommand(command); // Non-federated final Directory pluginDir1 = createFakePlugin('plugin1', packagesDir, withSingleExample: true); @@ -543,7 +642,6 @@ void main() { 'Checking local repo...', 'Local repo is ready!', '=============== DRY RUN ===============', - 'Getting existing tags...', 'Running `pub publish ` in ${pluginDir1.path}...\n', 'Tagging release plugin1-v0.0.1...', 'Pushing tag to upstream...', @@ -557,6 +655,37 @@ void main() { }); test('version change triggers releases.', () async { + const Map httpResponsePlugin1 = { + 'name': 'plugin1', + 'versions': [], + }; + + const Map httpResponsePlugin2 = { + 'name': 'plugin2', + 'versions': [], + }; + + final MockClient mockClient = MockClient((http.Request request) async { + if (request.url.pathSegments.last == 'plugin1.json') { + return http.Response(json.encode(httpResponsePlugin1), 200); + } else if (request.url.pathSegments.last == 'plugin2.json') { + return http.Response(json.encode(httpResponsePlugin2), 200); + } + return http.Response('', 500); + }); + final PublishPluginCommand command = PublishPluginCommand(packagesDir, + processRunner: processRunner, + print: (Object? message) => printedMessages.add(message.toString()), + stdinput: mockStdin, + httpClient: mockClient, + gitDir: gitDir); + + commandRunner = CommandRunner( + 'publish_check_command', + 'Test for publish-check command.', + ); + commandRunner.addCommand(command); + // Non-federated final Directory pluginDir1 = createFakePlugin('plugin1', packagesDir, withSingleExample: true); @@ -579,7 +708,6 @@ void main() { containsAllInOrder([ 'Checking local repo...', 'Local repo is ready!', - 'Getting existing tags...', 'Running `pub publish ` in ${pluginDir1.path}...\n', 'Running `pub publish ` in ${pluginDir2.path}...\n', 'Packages released: plugin1, plugin2', @@ -621,7 +749,6 @@ void main() { containsAllInOrder([ 'Checking local repo...', 'Local repo is ready!', - 'Getting existing tags...', 'Running `pub publish ` in ${pluginDir1.path}...\n', 'Running `pub publish ` in ${pluginDir2.path}...\n', 'Packages released: plugin1, plugin2', @@ -640,6 +767,37 @@ void main() { test( 'delete package will not trigger publish but exit the command successfully.', () async { + const Map httpResponsePlugin1 = { + 'name': 'plugin1', + 'versions': [], + }; + + const Map httpResponsePlugin2 = { + 'name': 'plugin2', + 'versions': [], + }; + + final MockClient mockClient = MockClient((http.Request request) async { + if (request.url.pathSegments.last == 'plugin1.json') { + return http.Response(json.encode(httpResponsePlugin1), 200); + } else if (request.url.pathSegments.last == 'plugin2.json') { + return http.Response(json.encode(httpResponsePlugin2), 200); + } + return http.Response('', 500); + }); + final PublishPluginCommand command = PublishPluginCommand(packagesDir, + processRunner: processRunner, + print: (Object? message) => printedMessages.add(message.toString()), + stdinput: mockStdin, + httpClient: mockClient, + gitDir: gitDir); + + commandRunner = CommandRunner( + 'publish_check_command', + 'Test for publish-check command.', + ); + commandRunner.addCommand(command); + // Non-federated final Directory pluginDir1 = createFakePlugin('plugin1', packagesDir, withSingleExample: true); @@ -662,7 +820,6 @@ void main() { containsAllInOrder([ 'Checking local repo...', 'Local repo is ready!', - 'Getting existing tags...', 'Running `pub publish ` in ${pluginDir1.path}...\n', 'Running `pub publish ` in ${pluginDir2.path}...\n', 'Packages released: plugin1, plugin2', @@ -703,7 +860,6 @@ void main() { containsAllInOrder([ 'Checking local repo...', 'Local repo is ready!', - 'Getting existing tags...', 'Running `pub publish ` in ${pluginDir1.path}...\n', 'The file at The pubspec file at ${pluginDir2.childFile('pubspec.yaml').path} does not exist. Publishing will not happen for plugin2.\nSafe to ignore if the package is deleted in this commit.\n', 'Packages released: plugin1', @@ -717,9 +873,39 @@ void main() { expect(processRunner.pushTagsArgs[2], 'plugin1-v0.0.2'); }); - test( - 'versions revert do not trigger releases. Also prints out warning message.', + test('Exiting versions do not trigger release, also prints out message.', () async { + const Map httpResponsePlugin1 = { + 'name': 'plugin1', + 'versions': ['0.0.1'], + }; + + const Map httpResponsePlugin2 = { + 'name': 'plugin2', + 'versions': ['0.0.1'], + }; + + final MockClient mockClient = MockClient((http.Request request) async { + if (request.url.pathSegments.last == 'plugin1.json') { + return http.Response(json.encode(httpResponsePlugin1), 200); + } else if (request.url.pathSegments.last == 'plugin2.json') { + return http.Response(json.encode(httpResponsePlugin2), 200); + } + return http.Response('', 500); + }); + final PublishPluginCommand command = PublishPluginCommand(packagesDir, + processRunner: processRunner, + print: (Object? message) => printedMessages.add(message.toString()), + stdinput: mockStdin, + httpClient: mockClient, + gitDir: gitDir); + + commandRunner = CommandRunner( + 'publish_check_command', + 'Test for publish-check command.', + ); + commandRunner.addCommand(command); + // Non-federated final Directory pluginDir1 = createFakePlugin('plugin1', packagesDir, withSingleExample: true); @@ -727,9 +913,9 @@ void main() { final Directory pluginDir2 = createFakePlugin('plugin2', packagesDir, withSingleExample: true, parentDirectoryName: 'plugin2'); createFakePubspec(pluginDir1, - name: 'plugin1', isFlutter: false, version: '0.0.2'); + name: 'plugin1', isFlutter: false, version: '0.0.1'); createFakePubspec(pluginDir2, - name: 'plugin2', isFlutter: false, version: '0.0.2'); + name: 'plugin2', isFlutter: false, version: '0.0.1'); await gitDir.runCommand(['add', '-A']); await gitDir.runCommand(['commit', '-m', 'Add plugins']); // Immediately return 0 when running `pub publish`. @@ -742,51 +928,8 @@ void main() { containsAllInOrder([ 'Checking local repo...', 'Local repo is ready!', - 'Getting existing tags...', - 'Running `pub publish ` in ${pluginDir1.path}...\n', - 'Running `pub publish ` in ${pluginDir2.path}...\n', - 'Packages released: plugin1, plugin2', - 'Done!' - ])); - expect(processRunner.pushTagsArgs, isNotEmpty); - expect(processRunner.pushTagsArgs[0], 'push'); - expect(processRunner.pushTagsArgs[1], 'upstream'); - expect(processRunner.pushTagsArgs[2], 'plugin1-v0.0.2'); - expect(processRunner.pushTagsArgs[3], 'push'); - expect(processRunner.pushTagsArgs[4], 'upstream'); - expect(processRunner.pushTagsArgs[5], 'plugin2-v0.0.2'); - - processRunner.pushTagsArgs.clear(); - printedMessages.clear(); - - final List plugin1Pubspec = - pluginDir1.childFile('pubspec.yaml').readAsLinesSync(); - plugin1Pubspec[plugin1Pubspec.indexWhere( - (String element) => element.contains('version:'))] = 'version: 0.0.1'; - pluginDir1 - .childFile('pubspec.yaml') - .writeAsStringSync(plugin1Pubspec.join('\n')); - final List plugin2Pubspec = - pluginDir2.childFile('pubspec.yaml').readAsLinesSync(); - plugin2Pubspec[plugin2Pubspec.indexWhere( - (String element) => element.contains('version:'))] = 'version: 0.0.1'; - pluginDir2 - .childFile('pubspec.yaml') - .writeAsStringSync(plugin2Pubspec.join('\n')); - await gitDir.runCommand(['add', '-A']); - await gitDir - .runCommand(['commit', '-m', 'Update versions to 0.0.1']); - - await commandRunner - .run(['publish-plugin', '--all-changed', '--base-sha=HEAD~']); - expect( - printedMessages, - containsAllInOrder([ - 'Checking local repo...', - 'Local repo is ready!', - 'Getting existing tags...', - 'The new version (0.0.1) is lower than the current version (0.0.2) for plugin1.\nThis git commit is a revert, no release is tagged.', - 'The new version (0.0.1) is lower than the current version (0.0.2) for plugin2.\nThis git commit is a revert, no release is tagged.', + 'The version 0.0.1 of plugin1 has already been published, skip.', + 'The version 0.0.1 of plugin2 has already been published, skip.', 'Done!' ])); From 911c2599c5da83b6e43857de0d667399c4fff756 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Thu, 17 Jun 2021 15:01:56 -0700 Subject: [PATCH 2/5] update changelog --- script/tool/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/script/tool/CHANGELOG.md b/script/tool/CHANGELOG.md index ae81ced63662..8df95930d693 100644 --- a/script/tool/CHANGELOG.md +++ b/script/tool/CHANGELOG.md @@ -6,6 +6,7 @@ - `xctest` now supports running macOS tests in addition to iOS - **Breaking change**: it now requires an `--ios` and/or `--macos` flag. - The tooling now runs in strong null-safe mode. +- `publish plugins` check against pub.dev to determine if a release should happen. ## 0.2.0 From 8a52c65a27aa18c11df21d1951e980c18b820068 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Thu, 17 Jun 2021 15:19:52 -0700 Subject: [PATCH 3/5] format --- script/tool/lib/src/publish_plugin_command.dart | 8 +++++--- script/tool/test/publish_plugin_command_test.dart | 12 +++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/script/tool/lib/src/publish_plugin_command.dart b/script/tool/lib/src/publish_plugin_command.dart index 1e1c2a50ab1b..36525f779b03 100644 --- a/script/tool/lib/src/publish_plugin_command.dart +++ b/script/tool/lib/src/publish_plugin_command.dart @@ -53,7 +53,8 @@ class PublishPluginCommand extends PluginCommand { GitDir? gitDir, http.Client? httpClient, }) : _pubVersionFinder = - PubVersionFinder(httpClient: httpClient ?? http.Client()), _print = print, + PubVersionFinder(httpClient: httpClient ?? http.Client()), + _print = print, _stdin = stdinput ?? io.stdin, super(packagesDir, processRunner: processRunner, gitDir: gitDir) { argParser.addOption( @@ -293,11 +294,12 @@ Safe to ignore if the package is deleted in this commit. } // Check if the package named `packageName` with `version` has already published. - final Version version = pubspec.version!; + final Version version = pubspec.version!; final PubVersionFinderResponse pubVersionFinderResponse = await _pubVersionFinder.getPackageVersion(package: pubspec.name); if (pubVersionFinderResponse.versions.contains(version)) { - _print('The version $version of ${pubspec.name} has already been published, skip.'); + _print( + 'The version $version of ${pubspec.name} has already been published, skip.'); return _CheckNeedsReleaseResult.noRelease; } return _CheckNeedsReleaseResult.release; diff --git a/script/tool/test/publish_plugin_command_test.dart b/script/tool/test/publish_plugin_command_test.dart index 26aea9ec7a82..f07b5efa64af 100644 --- a/script/tool/test/publish_plugin_command_test.dart +++ b/script/tool/test/publish_plugin_command_test.dart @@ -607,7 +607,8 @@ void main() { // Non-federated final Directory pluginDir1 = createFakePlugin('plugin1', packagesDir); // federated - final Directory pluginDir2 = createFakePlugin('plugin2', packagesDir.childDirectory('plugin2')); + final Directory pluginDir2 = + createFakePlugin('plugin2', packagesDir.childDirectory('plugin2')); await gitDir.runCommand(['add', '-A']); await gitDir.runCommand(['commit', '-m', 'Add plugins']); // Immediately return 1 when running `pub publish`. If dry-run does not work, test should throw. @@ -672,7 +673,8 @@ void main() { // Non-federated final Directory pluginDir1 = createFakePlugin('plugin1', packagesDir); // federated - final Directory pluginDir2 = createFakePlugin('plugin2', packagesDir.childDirectory('plugin2')); + final Directory pluginDir2 = + createFakePlugin('plugin2', packagesDir.childDirectory('plugin2')); await gitDir.runCommand(['add', '-A']); await gitDir.runCommand(['commit', '-m', 'Add plugins']); // Immediately return 0 when running `pub publish`. @@ -778,7 +780,8 @@ void main() { // Non-federated final Directory pluginDir1 = createFakePlugin('plugin1', packagesDir); // federated - final Directory pluginDir2 = createFakePlugin('plugin2', packagesDir.childDirectory('plugin2')); + final Directory pluginDir2 = + createFakePlugin('plugin2', packagesDir.childDirectory('plugin2')); await gitDir.runCommand(['add', '-A']); await gitDir.runCommand(['commit', '-m', 'Add plugins']); // Immediately return 0 when running `pub publish`. @@ -880,8 +883,7 @@ void main() { // Non-federated createFakePlugin('plugin1', packagesDir, version: '0.0.2'); // federated - createFakePlugin( - 'plugin2', packagesDir.childDirectory('plugin2'), + createFakePlugin('plugin2', packagesDir.childDirectory('plugin2'), version: '0.0.2'); await gitDir.runCommand(['add', '-A']); await gitDir.runCommand(['commit', '-m', 'Add plugins']); From 5f1412b74a17c0e21037294e17e246fef04cb253 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Thu, 17 Jun 2021 15:44:12 -0700 Subject: [PATCH 4/5] add logic for git tag --- .../tool/lib/src/publish_plugin_command.dart | 26 +++++- .../test/publish_plugin_command_test.dart | 87 +++++++++++++++++++ 2 files changed, 109 insertions(+), 4 deletions(-) diff --git a/script/tool/lib/src/publish_plugin_command.dart b/script/tool/lib/src/publish_plugin_command.dart index 36525f779b03..74bd4c2a2b52 100644 --- a/script/tool/lib/src/publish_plugin_command.dart +++ b/script/tool/lib/src/publish_plugin_command.dart @@ -205,6 +205,13 @@ class PublishPluginCommand extends PluginCommand { return true; } + _print('Getting existing tags...'); + final io.ProcessResult existingTagsResult = + await baseGitDir.runCommand(['tag', '--sort=-committerdate']); + final List existingTags = (existingTagsResult.stdout as String) + .split('\n') + ..removeWhere((String element) => element.isEmpty); + final List packagesReleased = []; final List packagesFailed = []; @@ -214,7 +221,7 @@ class PublishPluginCommand extends PluginCommand { .childFile(pubspecPath); final _CheckNeedsReleaseResult result = await _checkNeedsRelease( pubspecFile: pubspecFile, - gitVersionFinder: gitVersionFinder, + existingTags: existingTags, ); switch (result) { case _CheckNeedsReleaseResult.release: @@ -272,7 +279,7 @@ class PublishPluginCommand extends PluginCommand { // Returns a [_CheckNeedsReleaseResult] that indicates the result. Future<_CheckNeedsReleaseResult> _checkNeedsRelease({ required File pubspecFile, - required GitVersionFinder gitVersionFinder, + required List existingTags, }) async { if (!pubspecFile.existsSync()) { _print(''' @@ -298,9 +305,20 @@ Safe to ignore if the package is deleted in this commit. final PubVersionFinderResponse pubVersionFinderResponse = await _pubVersionFinder.getPackageVersion(package: pubspec.name); if (pubVersionFinderResponse.versions.contains(version)) { + final String tagsForPackageWithSameVersion = existingTags.firstWhere( + (String tag) => tag.split('-v').first == pubspec.name && tag.split('-v').last == version.toString(), + orElse: () => ''); + print(tagsForPackageWithSameVersion); _print( - 'The version $version of ${pubspec.name} has already been published, skip.'); - return _CheckNeedsReleaseResult.noRelease; + 'The version $version of ${pubspec.name} has already been published'); + if (tagsForPackageWithSameVersion.isEmpty) { + _print( + 'However, the git release tag for this version (${pubspec.name}-v$version) is not found. Please manually fix the tag then run the command again.'); + return _CheckNeedsReleaseResult.failure; + } else { + _print('skip.'); + return _CheckNeedsReleaseResult.noRelease; + } } return _CheckNeedsReleaseResult.release; } diff --git a/script/tool/test/publish_plugin_command_test.dart b/script/tool/test/publish_plugin_command_test.dart index f07b5efa64af..ab97999a9d39 100644 --- a/script/tool/test/publish_plugin_command_test.dart +++ b/script/tool/test/publish_plugin_command_test.dart @@ -537,6 +537,8 @@ void main() { createFakePlugin('plugin0', packagesDir); await gitDir.runCommand(['add', '-A']); await gitDir.runCommand(['commit', '-m', 'Add plugins']); + await gitDir.runCommand(['tag', 'plugin0-v0.0.1']); + // Immediately return 0 when running `pub publish`. processRunner.mockPublishCompleteCode = 0; mockStdin.readLineOutput = 'y'; @@ -880,6 +882,68 @@ void main() { ); commandRunner.addCommand(command); + // Non-federated + createFakePlugin('plugin1', packagesDir, version: '0.0.2'); + // federated + createFakePlugin('plugin2', packagesDir.childDirectory('plugin2'), + version: '0.0.2'); + await gitDir.runCommand(['add', '-A']); + await gitDir.runCommand(['commit', '-m', 'Add plugins']); + await gitDir.runCommand(['tag', 'plugin1-v0.0.2']); + await gitDir.runCommand(['tag', 'plugin2-v0.0.2']); + // Immediately return 0 when running `pub publish`. + processRunner.mockPublishCompleteCode = 0; + mockStdin.readLineOutput = 'y'; + await commandRunner + .run(['publish-plugin', '--all-changed', '--base-sha=HEAD~']); + expect( + printedMessages, + containsAllInOrder([ + 'Checking local repo...', + 'Local repo is ready!', + 'The version 0.0.2 of plugin1 has already been published', + 'skip.', + 'The version 0.0.2 of plugin2 has already been published', + 'skip.', + 'Done!' + ])); + + expect(processRunner.pushTagsArgs, isEmpty); + }); + + test('Exiting versions do not trigger release, but fail if the tags do not exist.', + () async { + const Map httpResponsePlugin1 = { + 'name': 'plugin1', + 'versions': ['0.0.2'], + }; + + const Map httpResponsePlugin2 = { + 'name': 'plugin2', + 'versions': ['0.0.2'], + }; + + final MockClient mockClient = MockClient((http.Request request) async { + if (request.url.pathSegments.last == 'plugin1.json') { + return http.Response(json.encode(httpResponsePlugin1), 200); + } else if (request.url.pathSegments.last == 'plugin2.json') { + return http.Response(json.encode(httpResponsePlugin2), 200); + } + return http.Response('', 500); + }); + final PublishPluginCommand command = PublishPluginCommand(packagesDir, + processRunner: processRunner, + print: (Object? message) => printedMessages.add(message.toString()), + stdinput: mockStdin, + httpClient: mockClient, + gitDir: gitDir); + + commandRunner = CommandRunner( + 'publish_check_command', + 'Test for publish-check command.', + ); + commandRunner.addCommand(command); + // Non-federated createFakePlugin('plugin1', packagesDir, version: '0.0.2'); // federated @@ -902,9 +966,32 @@ void main() { 'Done!' ])); +// bool hasError = false; +// final List output = await runCapturingPrint(runner, [ +// 'version-check', +// '--base-sha=master', +// '--against-pub' +// ], errorHandler: (Error e) { +// expect(e, isA()); +// hasError = true; +// }); +// expect(hasError, isTrue); + +// expect( +// output, +// containsAllInOrder([ +// _redColorString(''' +// versions for plugin in CHANGELOG.md and pubspec.yaml do not match. +// The version in pubspec.yaml is 1.0.1. +// The first version listed in CHANGELOG.md is 1.0.2. +// '''), +// ]), + // ); + expect(processRunner.pushTagsArgs, isEmpty); }); + test('No version change does not release any plugins', () async { // Non-federated final Directory pluginDir1 = createFakePlugin('plugin1', packagesDir); From 7300b407346db5ee35dbfbfd31f065eaa88d1dac Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Thu, 17 Jun 2021 15:46:20 -0700 Subject: [PATCH 5/5] fix test --- .../tool/lib/src/publish_plugin_command.dart | 7 ++-- .../test/publish_plugin_command_test.dart | 42 +++---------------- 2 files changed, 10 insertions(+), 39 deletions(-) diff --git a/script/tool/lib/src/publish_plugin_command.dart b/script/tool/lib/src/publish_plugin_command.dart index 74bd4c2a2b52..622a1a3cb133 100644 --- a/script/tool/lib/src/publish_plugin_command.dart +++ b/script/tool/lib/src/publish_plugin_command.dart @@ -306,14 +306,15 @@ Safe to ignore if the package is deleted in this commit. await _pubVersionFinder.getPackageVersion(package: pubspec.name); if (pubVersionFinderResponse.versions.contains(version)) { final String tagsForPackageWithSameVersion = existingTags.firstWhere( - (String tag) => tag.split('-v').first == pubspec.name && tag.split('-v').last == version.toString(), + (String tag) => + tag.split('-v').first == pubspec.name && + tag.split('-v').last == version.toString(), orElse: () => ''); - print(tagsForPackageWithSameVersion); _print( 'The version $version of ${pubspec.name} has already been published'); if (tagsForPackageWithSameVersion.isEmpty) { _print( - 'However, the git release tag for this version (${pubspec.name}-v$version) is not found. Please manually fix the tag then run the command again.'); + 'However, the git release tag for this version (${pubspec.name}-v$version) is not found. Please manually fix the tag then run the command again.'); return _CheckNeedsReleaseResult.failure; } else { _print('skip.'); diff --git a/script/tool/test/publish_plugin_command_test.dart b/script/tool/test/publish_plugin_command_test.dart index ab97999a9d39..c7832e0da191 100644 --- a/script/tool/test/publish_plugin_command_test.dart +++ b/script/tool/test/publish_plugin_command_test.dart @@ -911,7 +911,8 @@ void main() { expect(processRunner.pushTagsArgs, isEmpty); }); - test('Exiting versions do not trigger release, but fail if the tags do not exist.', + test( + 'Exiting versions do not trigger release, but fail if the tags do not exist.', () async { const Map httpResponsePlugin1 = { 'name': 'plugin1', @@ -954,44 +955,13 @@ void main() { // Immediately return 0 when running `pub publish`. processRunner.mockPublishCompleteCode = 0; mockStdin.readLineOutput = 'y'; - await commandRunner - .run(['publish-plugin', '--all-changed', '--base-sha=HEAD~']); - expect( - printedMessages, - containsAllInOrder([ - 'Checking local repo...', - 'Local repo is ready!', - 'The version 0.0.2 of plugin1 has already been published, skip.', - 'The version 0.0.2 of plugin2 has already been published, skip.', - 'Done!' - ])); - -// bool hasError = false; -// final List output = await runCapturingPrint(runner, [ -// 'version-check', -// '--base-sha=master', -// '--against-pub' -// ], errorHandler: (Error e) { -// expect(e, isA()); -// hasError = true; -// }); -// expect(hasError, isTrue); - -// expect( -// output, -// containsAllInOrder([ -// _redColorString(''' -// versions for plugin in CHANGELOG.md and pubspec.yaml do not match. -// The version in pubspec.yaml is 1.0.1. -// The first version listed in CHANGELOG.md is 1.0.2. -// '''), -// ]), - // ); - + await expectLater( + () => commandRunner.run( + ['publish-plugin', '--all-changed', '--base-sha=HEAD~']), + throwsA(const TypeMatcher())); expect(processRunner.pushTagsArgs, isEmpty); }); - test('No version change does not release any plugins', () async { // Non-federated final Directory pluginDir1 = createFakePlugin('plugin1', packagesDir);