diff --git a/script/tool/lib/src/update_excerpts_command.dart b/script/tool/lib/src/update_excerpts_command.dart index 8583e4993c7..d50082377f8 100644 --- a/script/tool/lib/src/update_excerpts_command.dart +++ b/script/tool/lib/src/update_excerpts_command.dart @@ -15,7 +15,7 @@ import 'common/package_looping_command.dart'; import 'common/process_runner.dart'; import 'common/repository_package.dart'; -/// A command to update README code excerpts from code files. +/// A command to update .md code excerpts from code files. class UpdateExcerptsCommand extends PackageLoopingCommand { /// Creates a excerpt updater command instance. UpdateExcerptsCommand( @@ -51,7 +51,7 @@ class UpdateExcerptsCommand extends PackageLoopingCommand { final String name = 'update-excerpts'; @override - final String description = 'Updates code excerpts in README.md files, based ' + final String description = 'Updates code excerpts in .md files, based ' 'on code from code files, via code-excerpt'; @override @@ -105,13 +105,16 @@ class UpdateExcerptsCommand extends PackageLoopingCommand { } if (getBoolArg(_failOnChangeFlag)) { - final String? stateError = await _validateRepositoryState(); + final String? stateError = await _validateRepositoryState(package); if (stateError != null) { - printError('README.md is out of sync with its source excerpts.\n\n' - 'If you edited code in README.md directly, you should instead edit ' - 'the example source files. If you edited source files, run the ' - 'repository tooling\'s "$name" command on this package, and update ' - 'your PR with the resulting changes.'); + printError('One or more .md files are out of sync with their source ' + 'excerpts.\n\n' + 'If you edited code in a .md file directly, you should instead ' + 'edit the example source files. If you edited source files, run ' + 'the repository tooling\'s "$name" command on this package, and ' + 'update your PR with the resulting changes.\n\n' + 'For more information, see ' + 'https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#readme-code'); return PackageResult.fail([stateError]); } } @@ -138,14 +141,24 @@ class UpdateExcerptsCommand extends PackageLoopingCommand { return exitCode == 0; } - /// Runs the injection step to update [targetPackage]'s README with the latest - /// excerpts from [example], returning true on success. + /// Runs the injection step to update [targetPackage]'s top-level .md files + /// with the latest excerpts from [example], returning true on success. Future _injectSnippets( RepositoryPackage example, { required RepositoryPackage targetPackage, }) async { - final String relativeReadmePath = - getRelativePosixPath(targetPackage.readmeFile, from: example.directory); + final List relativeMdPaths = targetPackage.directory + .listSync() + .whereType() + .where((File f) => + f.basename.toLowerCase().endsWith('.md') && + // Exclude CHANGELOG since it should never have excerpts. + f.basename != 'CHANGELOG.md') + .map((File f) => getRelativePosixPath(f, from: example.directory)) + .toList(); + if (relativeMdPaths.isEmpty) { + return true; + } final int exitCode = await processRunner.runAndStream( 'dart', [ @@ -154,7 +167,7 @@ class UpdateExcerptsCommand extends PackageLoopingCommand { '--write-in-place', '--yaml', '--no-escape-ng-interpolation', - relativeReadmePath, + ...relativeMdPaths, ], workingDir: example.directory); return exitCode == 0; @@ -212,11 +225,11 @@ class UpdateExcerptsCommand extends PackageLoopingCommand { /// Checks the git state, returning an error string if any .md files have /// changed. - Future _validateRepositoryState() async { + Future _validateRepositoryState(RepositoryPackage package) async { final io.ProcessResult checkFiles = await processRunner.run( 'git', ['ls-files', '--modified'], - workingDir: packagesDir, + workingDir: package.directory, logOnError: true, ); if (checkFiles.exitCode != 0) { diff --git a/script/tool/test/update_excerpts_command_test.dart b/script/tool/test/update_excerpts_command_test.dart index 7bb0297de13..09862b3b321 100644 --- a/script/tool/test/update_excerpts_command_test.dart +++ b/script/tool/test/update_excerpts_command_test.dart @@ -111,7 +111,7 @@ void main() { test('updates example readme when config is present', () async { final RepositoryPackage package = createFakePlugin('a_package', packagesDir, - extraFiles: [kReadmeExcerptConfigPath]); + extraFiles: [kReadmeExcerptConfigPath, 'example/README.md']); final Directory example = getExampleDir(package); final List output = @@ -153,6 +153,52 @@ void main() { ])); }); + test('includes all top-level .md files', () async { + const String otherMdFileName = 'another_file.md'; + final RepositoryPackage package = createFakePlugin('a_package', packagesDir, + extraFiles: [kReadmeExcerptConfigPath, otherMdFileName]); + final Directory example = getExampleDir(package); + + final List output = + await runCapturingPrint(runner, ['update-excerpts']); + + expect( + processRunner.recordedCalls, + containsAll([ + ProcessCall( + 'dart', + const [ + 'run', + 'build_runner', + 'build', + '--config', + 'excerpt', + '--output', + 'excerpts', + '--delete-conflicting-outputs', + ], + example.path), + ProcessCall( + 'dart', + const [ + 'run', + 'code_excerpt_updater', + '--write-in-place', + '--yaml', + '--no-escape-ng-interpolation', + '../README.md', + '../$otherMdFileName', + ], + example.path), + ])); + + expect( + output, + containsAllInOrder([ + contains('Ran for 1 package(s)'), + ])); + }); + test('skips when no config is present', () async { createFakePlugin('a_package', packagesDir); @@ -277,7 +323,7 @@ void main() { test('fails if example injection fails', () async { createFakePlugin('a_package', packagesDir, - extraFiles: [kReadmeExcerptConfigPath]); + extraFiles: [kReadmeExcerptConfigPath, 'example/README.md']); processRunner.mockProcessesForExecutable['dart'] = [ FakeProcessInfo(MockProcess(), ['pub', 'get']), @@ -307,7 +353,7 @@ void main() { createFakePlugin('a_plugin', packagesDir, extraFiles: [kReadmeExcerptConfigPath]); - const String changedFilePath = 'packages/a_plugin/README.md'; + const String changedFilePath = 'README.md'; processRunner.mockProcessesForExecutable['git'] = [ FakeProcessInfo(MockProcess(stdout: changedFilePath)), ]; @@ -323,9 +369,10 @@ void main() { expect( output, containsAllInOrder([ - contains('README.md is out of sync with its source excerpts'), + contains( + 'One or more .md files are out of sync with their source excerpts'), contains('Snippets are out of sync in the following files: ' - 'packages/a_plugin/README.md'), + '$changedFilePath'), ])); });