Skip to content

Commit

Permalink
Fix bug in shared-command plugin template when plugin name ends wit…
Browse files Browse the repository at this point in the history
…h `_sidekick_plugin` (#242)

* add failing tests which reproduce bug

* Fix plugin templates

* add `topics` block to plugin templates pubspec

* format
  • Loading branch information
Giuspepe authored Jul 6, 2023
1 parent c235c77 commit 4d681a6
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 88 deletions.
141 changes: 78 additions & 63 deletions sidekick/test/plugins_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,71 +84,86 @@ void main() {
);
});

for (final template in CreatePluginCommand.templates.keys) {
test(
'plugin e2e $template: create valid code, install in cli, run command',
() async {
await withSidekickCli((cli) async {
// create plugin
await cli.run([
'sidekick',
'plugins',
'create',
'-t',
template,
'-n',
template.snakeCase,
]);
group('create plugin, install in cli, run plugin command', () {
for (final pluginName in ['foo', 'sidekick_foo_bar_sidekick_plugin']) {
for (final template in CreatePluginCommand.templates.keys) {
test(
"template '$template', plugin name '$pluginName'",
() async {
await withSidekickCli((cli) async {
// create plugin
await cli.run([
'sidekick',
'plugins',
'create',
'-t',
template,
'-n',
pluginName,
]);

final pluginDir = cli.root.directory(template.snakeCase);
overrideSidekickCoreWithLocalPath(pluginDir);
overrideSidekickPluginInstallerWithLocalPath(pluginDir);
final pluginDir = cli.root.directory(pluginName);
overrideSidekickCoreWithLocalPath(pluginDir);
overrideSidekickPluginInstallerWithLocalPath(pluginDir);

// plugin code should be valid
if (analyzeGeneratedCode) {
run('dart pub get', workingDirectory: pluginDir.path);
run('dart analyze --fatal-infos', workingDirectory: pluginDir.path);
run('dart format --set-exit-if-changed ${pluginDir.path}');
}
expect(
pluginDir.file('analysis_options.yaml').readAsStringSync(),
contains('package:lint/analysis_options.yaml'),
);
expect(
pluginDir.file('.gitignore').readAsStringSync(),
contains('\npubspec.lock'),
);
expect(
pluginDir.file('README.md').readAsStringSync(),
allOf([
contains('dashi sidekick plugins install'),
contains('${template.snakeCase} sidekick plugin'),
]),
);
// plugin code should be valid
if (analyzeGeneratedCode) {
run('dart pub get', workingDirectory: pluginDir.path);
run(
'dart analyze --fatal-infos',
workingDirectory: pluginDir.path,
);
run('dart format --set-exit-if-changed ${pluginDir.path}');
}
expect(
pluginDir.file('analysis_options.yaml').readAsStringSync(),
contains('package:lint/analysis_options.yaml'),
);
expect(
pluginDir.file('.gitignore').readAsStringSync(),
contains('\npubspec.lock'),
);
expect(
pluginDir.file('README.md').readAsStringSync(),
allOf([
contains('dashi sidekick plugins install'),
contains('$pluginName sidekick plugin'),
]),
);

// plugin can be installed
await cli.run(
[
'sidekick',
'plugins',
'install',
'-s',
'path',
template.snakeCase,
],
);
// plugin can be installed
await cli.run(
[
'sidekick',
'plugins',
'install',
'-s',
'path',
pluginName,
],
);

// TODO if we add an option to execute the sidekick entrypoint without compiling it, we could speed up the tests a little bit here:
// after a plugin is installed, the hash values of the sidekick CLI
// change and thus the entrypoint has to be recompiled.
// however in this case, we don't gain anything time-wise from compiling
// because we use the entrypoint only once here.
// so if we ran the entrypoint without compiling it heree, these tests
// would be a little bit faster.
await cli.run([template.paramCase]);
});
},
timeout: const Timeout(Duration(minutes: 5)),
);
}
// TODO if we add an option to execute the sidekick entrypoint without compiling it, we could speed up the tests a little bit here:
// after a plugin is installed, the hash values of the sidekick CLI
// change and thus the entrypoint has to be recompiled.
// however in this case, we don't gain anything time-wise from compiling
// because we use the entrypoint only once here.
// so if we ran the entrypoint without compiling it heree, these tests
// would be a little bit faster.

// running the new command should succeed
final command = pluginName
.removePrefix('sidekick_')
.removePrefix('plugin_')
.removeSuffix('_plugin')
.removeSuffix('_sidekick')
.paramCase;
await cli.run([command]);
});
},
timeout: const Timeout(Duration(minutes: 5)),
);
}
}
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ extension on PluginTemplateProperties {
name: $pluginName
description: Generated sidekick plugin (template install-only)
version: 0.0.1
topics:
- sidekick
- cli
- sidekick-plugin
environment:
sdk: '>=3.0.0 <4.0.0'
Expand All @@ -49,30 +53,30 @@ import 'package:sidekick_plugin_installer/sidekick_plugin_installer.dart';
Future<void> main() async {
final SidekickPackage package = PluginContext.sidekickPackage;
final commandFile = package.root.file('lib/src/${pluginName.snakeCase}.dart');
commandFile.writeAsStringSync("""
final commandFile = package.root.file('lib/src/commands/${pluginName.snakeCase}.dart');
commandFile..createSync(recursive: true)..writeAsStringSync("""
$exampleCommand
""");
registerPlugin(
sidekickCli: package,
import: "import 'package:\${package.name}/src/${pluginName.snakeCase}.dart';",
command: '${pluginName.pascalCase}Command()',
import: "import 'package:\${package.name}/src/commands/${pluginName.snakeCase}.dart';",
command: '${commandName.pascalCase}Command()',
);
}
''';

String get exampleCommand => '''
import 'package:sidekick_core/sidekick_core.dart';
class ${pluginName.pascalCase}Command extends Command {
class ${commandName.pascalCase}Command extends Command {
@override
final String description = 'Sample command';
@override
final String name = '${pluginName.paramCase}';
final String name = '$commandName';
${pluginName.pascalCase}Command() {
${commandName.pascalCase}Command() {
// add parameters here with argParser.addOption
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,20 @@ class PluginTemplateProperties {
final String pluginName;

/// The name of the command that will be generated
String get commandName {
return pluginName.replaceAll('_sidekick_plugin', '').paramCase;
}
late final String commandName = pluginName
.removePrefix('sidekick_')
.removePrefix('plugin_')
.removeSuffix('_plugin')
.removeSuffix('_sidekick')
.paramCase;

/// Where the files should be written to. This is considered as root directory
final Directory pluginDirectory;

/// The type of template to generate. Also see [CreatePluginCommand.templates]
final String templateType;

const PluginTemplateProperties({
PluginTemplateProperties({
required this.pluginName,
required this.pluginDirectory,
required this.templateType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class SharedCodeTemplate extends PluginTemplateGenerator {
final templateDirectory = pluginDirectory.directory('template')
..createSync();
final pluginCommandTemplateFile = templateDirectory
.file('${props.pluginName.snakeCase}_command.template.dart')
.file('commands/${props.commandName.snakeCase}_command.template.dart')
..createSync(recursive: true);
pluginCommandTemplateFile.writeAsStringSync(props.exampleCommand);

Expand All @@ -43,6 +43,10 @@ extension on PluginTemplateProperties {
name: $pluginName
description: Generated sidekick plugin (template shared-code)
version: 0.0.1
topics:
- sidekick
- cli
- sidekick-plugin
environment:
sdk: '>=3.0.0 <4.0.0'
Expand All @@ -67,18 +71,19 @@ Future<void> main() async {
pubGet(package);
final cliCommandFile =
package.root.file('lib/src/${pluginName.snakeCase}_command.dart');
package.root.file('lib/src/commands/${commandName.snakeCase}_command.dart');
cliCommandFile.createSync(recursive: true);
PluginContext
.installerPlugin
.root
.file('template/${pluginName.snakeCase}_command.template.dart')
.file('template/commands/${commandName.snakeCase}_command.template.dart')
.copySync(cliCommandFile.path);
registerPlugin(
sidekickCli: package,
import: "import 'package:\${package.name}/src/${pluginName.snakeCase}_command.dart';",
command: '${pluginName.pascalCase}Command()',
import: "import 'package:\${package.name}/src/commands/${commandName.snakeCase}_command.dart';",
command: '${commandName.pascalCase}Command()',
);
}
''';
Expand All @@ -89,14 +94,14 @@ ${[
"import 'package:$pluginName/${pluginName.snakeCase}.dart';",
].sorted().join('\n')}
class ${pluginName.pascalCase}Command extends Command {
class ${commandName.pascalCase}Command extends Command {
@override
final String description = 'Sample command';
@override
final String name = '${pluginName.paramCase}';
final String name = '$commandName';
${pluginName.pascalCase}Command() {
${commandName.pascalCase}Command() {
// add parameters here with argParser.addOption
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ class SharedCommandTemplate extends PluginTemplateGenerator {
.writeAsStringSync(props.library);

final srcDir = libDirectory.directory('src')..createSync();
srcDir
.file('${props.commandName.snakeCase}_command.dart')
.writeAsStringSync(props.exampleCommand);
final commandFile =
srcDir.file('commands/${props.commandName.snakeCase}_command.dart');
commandFile
..createSync(recursive: true)
..writeAsStringSync(props.exampleCommand);

super.generate(props);
}
Expand All @@ -41,6 +43,10 @@ extension on PluginTemplateProperties {
name: $pluginName
description: Generated sidekick plugin (template shared-command)
version: 0.0.1
topics:
- sidekick
- cli
- sidekick-plugin
environment:
sdk: '>=3.0.0 <4.0.0'
Expand All @@ -66,8 +72,8 @@ Future<void> main() async {
registerPlugin(
sidekickCli: package,
import: "import 'package:$pluginName/${pluginName.snakeCase}.dart';",
command: '${pluginName.pascalCase}Command()',
import: "import 'package:$pluginName/$pluginName.dart';",
command: '${commandName.pascalCase}Command()',
);
}
''';
Expand All @@ -76,7 +82,7 @@ Future<void> main() async {
/// Sidekick plugin ${pluginName.titleCase}
library ${pluginName.snakeCase};
export 'package:${pluginName.snakeCase}/src/${commandName.snakeCase}_command.dart';
export 'package:${pluginName.snakeCase}/src/commands/${commandName.snakeCase}_command.dart';
''';

String get exampleCommand => '''
Expand Down

0 comments on commit 4d681a6

Please sign in to comment.