Skip to content

Commit

Permalink
wip: use paths instead of names with backwards compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
a-wallen committed Jul 9, 2024
1 parent cc786aa commit b706a2d
Show file tree
Hide file tree
Showing 2 changed files with 171 additions and 100 deletions.
78 changes: 34 additions & 44 deletions lib/src/commands/create/commands/create_subcommand.dart
Original file line number Diff line number Diff line change
Expand Up @@ -117,27 +117,44 @@ 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);
}

/// The project name that the user provided.
///
/// Since the project name could be user provided as either:
/// 1. A valid package name
/// 2. '.', the current working directory (the project assumes the cwd's name)
/// this needs to exist to provide a fallback value for [outputDirectory] and
/// [projectName].
String get _projectName {
final args = argResults.rest;
_validateProjectName(args);
return args.first;

return Directory(args.first);
}

/// Gets the project name.
String get projectName => _projectName == '.'
? path.basename(Directory.current.path)
: _projectName;
String get projectName {
final args = argResults.rest;

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.
String get projectDescription => argResults['description'] as String? ?? '';
Expand All @@ -158,28 +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 @@ -223,12 +218,7 @@ abstract class CreateSubCommand extends Command<int> {

await template.onGenerateComplete(
logger,
Directory(
[
target.dir.path,
if (_projectName != '.') projectName,
].join(Platform.pathSeparator),
),
outputDirectory,
);

return ExitCode.success.code;
Expand Down
193 changes: 137 additions & 56 deletions test/src/commands/create/create_subcommand_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -237,60 +237,131 @@ Run "runner help" to see global options.''';
});

group('parsing of options', () {
test('parses description, output dir and project name', () async {
final result = await runner.run([
'create_subcommand',
'test_project',
'--description',
'test_desc',
'--output-directory',
'test_dir',
]);
group('for project name', () {
test('uses current directory basename as name if . provided',
() async {
final expectedProjectName = path.basename(Directory.current.path);

expect(result, equals(ExitCode.success.code));
verify(() => logger.progress('Bootstrapping')).called(1);
final result = await runner.run([
'create_subcommand',
'.',
]);

verify(
() => hooks.preGen(
vars: <String, dynamic>{
'project_name': 'test_project',
'description': 'test_desc',
},
onVarsChanged: any(named: 'onVarsChanged'),
),
);
verify(
() => generator.generate(
any(
that: isA<DirectoryGeneratorTarget>().having(
(g) => g.dir.path,
'dir',
'test_dir',
),
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'),
),
vars: <String, dynamic>{
'project_name': 'test_project',
'description': 'test_desc',
},
logger: logger,
),
).called(1);
expect(
progressLogs,
equals(['Generated ${generatedFiles.length} file(s)']),
);
verify(
() => template.onGenerateComplete(
logger,
any(
that: isA<Directory>().having(
(d) => d.path,
'path',
path.join('test_dir', 'test_project'),
),
);
});

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'),
),
),
).called(1);
);
});

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 {
Expand All @@ -317,7 +388,9 @@ Run "runner help" to see global options.''';
() => generator.generate(
any(
that: isA<DirectoryGeneratorTarget>().having(
(g) => g.dir.path,
(g) {
return g.dir.path;
},
'dir',
'.',
),
Expand All @@ -338,7 +411,11 @@ Run "runner help" to see global options.''';
logger,
any(
that: isA<Directory>().having(
(d) => d.path,
(d) {
print(Directory.current);
print(d.absolute.path);
return d.path;
},
'path',
'.',
),
Expand Down Expand Up @@ -373,9 +450,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 @@ -391,9 +470,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

0 comments on commit b706a2d

Please sign in to comment.