Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow very_good create . #996

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
59 changes: 33 additions & 26 deletions lib/src/commands/create/commands/create_subcommand.dart
Original file line number Diff line number Diff line change
Expand Up @@ -117,15 +117,43 @@ abstract class CreateSubCommand extends Command<int> {

/// Gets the output [Directory].
Directory get outputDirectory {
final directory = argResults['output-directory'] as String? ?? '.';
return Directory(directory);
final directory = argResults['output-directory'] as String?;

if (directory != null) {
return Directory(directory);
}

final args = argResults.rest;

return Directory(args.first);
Comment on lines +120 to +128
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same logic as before, if the --output-directory argument isn't provided then treat the [project-name] argument as as a directory path.

}

/// Gets the project name.
String get projectName {
final args = argResults.rest;
_validateProjectName(args);
return args.first;

if (args.isEmpty) {
usageException('No option specified for the project name.');
}

if (args.length > 1) {
usageException('Multiple project names specified.');
}

final name = args.first == '.'
? path.basename(Directory.current.path)
: path.basename(args.first);

final isValidPackageName = _isValidPackageName(name);

if (!isValidPackageName) {
usageException(
'"$name" is not a valid package name.\n\n'
'See https://dart.dev/tools/pub/pubspec#name for more information.',
);
}

return name;
}

/// Gets the description for the project.
Expand All @@ -147,27 +175,6 @@ abstract class CreateSubCommand extends Command<int> {
return match != null && match.end == name.length;
}

void _validateProjectName(List<String> args) {
logger.detail('Validating project name; args: $args');

if (args.isEmpty) {
usageException('No option specified for the project name.');
}

if (args.length > 1) {
usageException('Multiple project names specified.');
}

final name = args.first;
final isValidProjectName = _isValidPackageName(name);
if (!isValidProjectName) {
usageException(
'"$name" is not a valid package name.\n\n'
'See https://dart.dev/tools/pub/pubspec#name for more information.',
);
}
}

Future<MasonGenerator> _getGeneratorForTemplate() async {
try {
final brick = Brick.version(
Expand Down Expand Up @@ -211,7 +218,7 @@ abstract class CreateSubCommand extends Command<int> {

await template.onGenerateComplete(
logger,
Directory(path.join(target.dir.path, projectName)),
outputDirectory,
);

return ExitCode.success.code;
Expand Down
170 changes: 152 additions & 18 deletions test/src/commands/create/create_subcommand_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:args/args.dart';
import 'package:args/command_runner.dart';
import 'package:mason/mason.dart';
import 'package:mocktail/mocktail.dart';
import 'package:path/path.dart' as path;
import 'package:test/test.dart';
import 'package:very_good_cli/src/commands/create/commands/create_subcommand.dart';
import 'package:very_good_cli/src/commands/create/templates/template.dart';
Expand Down Expand Up @@ -236,14 +237,139 @@ Run "runner help" to see global options.''';
});

group('parsing of options', () {
test('parses description, output dir and project name', () async {
group('for project name', () {
test('uses current directory basename as name if . provided',
() async {
final expectedProjectName = path.basename(Directory.current.path);

final result = await runner.run([
'create_subcommand',
'.',
]);

expect(result, equals(ExitCode.success.code));
verify(() => logger.progress('Bootstrapping')).called(1);

verify(
() => hooks.preGen(
vars: <String, dynamic>{
'project_name': expectedProjectName,
'description':
'A Very Good Project created by Very Good CLI.',
},
onVarsChanged: any(named: 'onVarsChanged'),
),
);
});

test('uses name if just a name is provided', () async {
final result = await runner.run([
'create_subcommand',
'name',
]);

expect(result, equals(ExitCode.success.code));
verify(() => logger.progress('Bootstrapping')).called(1);

verify(
() => hooks.preGen(
vars: <String, dynamic>{
'project_name': 'name',
'description':
'A Very Good Project created by Very Good CLI.',
},
onVarsChanged: any(named: 'onVarsChanged'),
),
);
});

test('uses last path segment if absolute path is provided', () async {
final result = await runner.run([
'create_subcommand',
'/path/to/name',
]);

expect(result, equals(ExitCode.success.code));
verify(() => logger.progress('Bootstrapping')).called(1);

verify(
() => hooks.preGen(
vars: <String, dynamic>{
'project_name': 'name',
'description':
'A Very Good Project created by Very Good CLI.',
},
onVarsChanged: any(named: 'onVarsChanged'),
),
);
});

test('uses last path segment if a relative path is provided',
() async {
final result = await runner.run([
'create_subcommand',
'./name',
]);

expect(result, equals(ExitCode.success.code));
verify(() => logger.progress('Bootstrapping')).called(1);

verify(
() => hooks.preGen(
vars: <String, dynamic>{
'project_name': 'name',
'description':
'A Very Good Project created by Very Good CLI.',
},
onVarsChanged: any(named: 'onVarsChanged'),
),
);
});
});

group('for output directory', () {
test(
'uses directory provided in --output-directory instead of the '
'one parsed from project',
() async {
final result = await runner.run([
'create_subcommand',
'path/to/test_project',
'--output-directory',
'path/to/test_dir',
'--description',
'test_desc',
]);

expect(result, equals(ExitCode.success.code));
verify(() => logger.progress('Bootstrapping')).called(1);

verify(
() => generator.generate(
any(
that: isA<DirectoryGeneratorTarget>().having(
(g) => g.dir.path,
'dir',
'path/to/test_dir',
),
),
vars: <String, dynamic>{
'project_name': 'test_project',
'description': 'test_desc',
},
logger: logger,
),
).called(1);
},
);
});

test('allows projects to be cwd (.)', () async {
final expectedProjectName = path.basename(Directory.current.path);

final result = await runner.run([
'create_subcommand',
'test_project',
'--description',
'test_desc',
'--output-directory',
'test_dir',
'.',
]);

expect(result, equals(ExitCode.success.code));
Expand All @@ -252,8 +378,8 @@ Run "runner help" to see global options.''';
verify(
() => hooks.preGen(
vars: <String, dynamic>{
'project_name': 'test_project',
'description': 'test_desc',
'project_name': expectedProjectName,
'description': 'A Very Good Project created by Very Good CLI.',
},
onVarsChanged: any(named: 'onVarsChanged'),
),
Expand All @@ -262,14 +388,16 @@ Run "runner help" to see global options.''';
() => generator.generate(
any(
that: isA<DirectoryGeneratorTarget>().having(
(g) => g.dir.path,
(g) {
return g.dir.path;
},
'dir',
'test_dir',
'.',
),
),
vars: <String, dynamic>{
'project_name': 'test_project',
'description': 'test_desc',
'project_name': expectedProjectName,
'description': 'A Very Good Project created by Very Good CLI.',
},
logger: logger,
),
Expand All @@ -283,9 +411,11 @@ Run "runner help" to see global options.''';
logger,
any(
that: isA<Directory>().having(
(d) => d.path,
(d) {
return d.path;
},
'path',
'test_dir/test_project',
'.',
),
),
),
Expand Down Expand Up @@ -318,9 +448,11 @@ Run "runner help" to see global options.''';
() => generator.generate(
any(
that: isA<DirectoryGeneratorTarget>().having(
(g) => g.dir.path,
(g) {
return g.dir.path;
},
'dir',
'.',
'test_project',
),
),
vars: <String, dynamic>{
Expand All @@ -336,9 +468,11 @@ Run "runner help" to see global options.''';
logger,
any(
that: isA<Directory>().having(
(d) => d.path,
(d) {
return d.path;
},
'path',
'./test_project',
'test_project',
),
),
),
Expand Down
Loading