Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion lib/src/commands/create/commands/app_ui_package.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ import 'package:very_good_cli/src/commands/create/templates/templates.dart';
class CreateAppUiPackage({
required super.logger,
required super.generatorFromBundle,
}) extends CreateSubCommand with Publishable, Workspace {
}) extends CreateSubCommand with Publishable, Workspace, FreeFormOrgName {
/// {@macro very_good_create_app_ui_package_command}
this;

@override
String get defaultOrgName => 'com.example.verygoodapp';

@override
String get name => 'app_ui_package';

Expand Down
54 changes: 47 additions & 7 deletions lib/src/commands/create/commands/create_subcommand.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ typedef TemplateVarResolvers = Map<String, Object? Function()>;
///
/// For sub commands that receive a workspace flag, sub classes must mix with
/// [Workspace].
///
/// For sub commands that receive a free-form org name, sub classes must mix
/// with [FreeFormOrgName].
abstract class CreateSubCommand({
/// The logger user to notify the user of the command's progress.
required final Logger logger,
Expand Down Expand Up @@ -92,12 +95,7 @@ abstract class CreateSubCommand({
}

if (this is OrgName) {
argParser.addOption(
'org-name',
help: 'The organization for this new project.',
defaultsTo: _defaultOrgName,
aliases: ['org'],
);
_addOrgNameOption(defaultsTo: _defaultOrgName);
}

if (this is Publishable) {
Expand All @@ -117,6 +115,19 @@ abstract class CreateSubCommand({
'from a parent Pub workspace.',
);
}

if (this is FreeFormOrgName) {
_addOrgNameOption(defaultsTo: (this as FreeFormOrgName).defaultOrgName);
}
}

void _addOrgNameOption({required String defaultsTo}) {
argParser.addOption(
'org-name',
help: 'The organization for this new project.',
defaultsTo: defaultsTo,
aliases: ['org'],
);
}

final MasonGeneratorFromBundle _generatorFromBundle =
Expand Down Expand Up @@ -270,7 +281,8 @@ abstract class CreateSubCommand({
/// Override to handle additional template vars, spreading
/// `super.templateVarResolvers` into the returned map.
///
/// For subcommands that mix with [OrgName], it includes 'org_name'.
/// For subcommands that mix with [OrgName] or [FreeFormOrgName], it
/// includes 'org_name'.
/// For subcommands that mix with [Publishable], it includes 'publishable'.
/// For subcommands that mix with [Workspace], it includes 'workspace'.
@mustCallSuper
Expand Down Expand Up @@ -410,3 +422,31 @@ mixin Workspace on CreateSubCommand {
fallbackValue: false,
);
}

/// Mixin for [CreateSubCommand] subclasses that receive a free-form org name,
/// such as a copyright holder or a GitHub organization.
///
/// Unlike [OrgName], the value is not validated as a reverse-domain
/// identifier. Both mixins register the `org-name` option, so combining them
/// throws an [ArgumentError] when the command is constructed.
///
/// The org name resolves from the `--org-name` option, then the
/// `create.org_name` key in `very_good.yaml`, then [defaultOrgName].
mixin FreeFormOrgName on CreateSubCommand {
/// The org name used when neither the `--org-name` option nor the
/// `create.org_name` configuration value is provided.
String get defaultOrgName;

@override
TemplateVarResolvers get templateVarResolvers => {
...super.templateVarResolvers,
'org_name': () => orgName,
};

/// Gets the organization name.
String get orgName => argResults.resolve<String>(
'org-name',
createConfig.orgName,
fallbackValue: defaultOrgName,
);
}
5 changes: 4 additions & 1 deletion lib/src/commands/create/commands/dart_cli.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import 'package:very_good_cli/src/commands/create/templates/templates.dart';
/// {@endtemplate}
class CreateDartCLI({required super.logger, required super.generatorFromBundle})
extends CreateSubCommand
with Publishable, Workspace {
with Publishable, Workspace, FreeFormOrgName {
/// {@macro very_good_create_dart_cli_command}
this {
argParser.addOption(
Expand All @@ -15,6 +15,9 @@ class CreateDartCLI({required super.logger, required super.generatorFromBundle})
);
}

@override
String get defaultOrgName => 'Very Good Ventures';

@override
String get name => 'dart_cli';

Expand Down
5 changes: 4 additions & 1 deletion lib/src/commands/create/commands/dart_package.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ import 'package:very_good_cli/src/commands/create/templates/templates.dart';
class CreateDartPackage({
required super.logger,
required super.generatorFromBundle,
}) extends CreateSubCommand with Publishable, Workspace {
}) extends CreateSubCommand with Publishable, Workspace, FreeFormOrgName {
/// {@macro very_good_create_dart_package_command}
this;

@override
String get defaultOrgName => 'Very Good Ventures';

@override
String get name => 'dart_package';

Expand Down
25 changes: 4 additions & 21 deletions lib/src/commands/create/commands/docs_site.dart
Original file line number Diff line number Diff line change
@@ -1,42 +1,25 @@
import 'package:very_good_cli/src/commands/commands.dart';
import 'package:very_good_cli/src/commands/create/templates/templates.dart';
import 'package:very_good_cli/src/very_good_config/very_good_config.dart';

/// {@template very_good_create_docs_site}
/// A [CreateSubCommand] for creating Dart command line interfaces.
/// {@endtemplate}
class CreateDocsSite({
required super.logger,
required super.generatorFromBundle,
}) extends CreateSubCommand with Publishable {
}) extends CreateSubCommand with Publishable, FreeFormOrgName {
/// {@macro very_good_create_docs_site}
this {
argParser.addOption(
'org-name',
help: 'The organization for this new project.',
defaultsTo: _defaultOrgName,
aliases: ['org'],
);
}
this;

static const _defaultOrgName = 'my-org';
@override
String get defaultOrgName => 'my-org';

@override
String get name => 'docs_site';

@override
String get description => 'Generate a Very Good documentation site.';

@override
TemplateVarResolvers get templateVarResolvers => {
...super.templateVarResolvers,
'org_name': () => argResults.resolve<String>(
'org-name',
createConfig.orgName,
fallbackValue: _defaultOrgName,
),
};

@override
Template get template => VeryGoodDocsSiteTemplate();
}
5 changes: 4 additions & 1 deletion lib/src/commands/create/commands/flutter_package.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ import 'package:very_good_cli/src/commands/create/templates/templates.dart';
class CreateFlutterPackage({
required super.logger,
required super.generatorFromBundle,
}) extends CreateSubCommand with Publishable, Workspace {
}) extends CreateSubCommand with Publishable, Workspace, FreeFormOrgName {
/// {@macro very_good_create_flutter_package_command}
this;

@override
String get defaultOrgName => 'Very Good Ventures';

@override
String get name => 'flutter_package';

Expand Down
4 changes: 4 additions & 0 deletions site/docs/commands/create.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ create:

With the file above, running `very_good create flutter_app my_app` behaves the same as running `very_good create flutter_app my_app --desc 'A Very Good project.' --org-name com.very.good --publishable --template core`. You can still override any of these values on the command line, for example `very_good create flutter_app my_app --org-name com.example` to use a different org name for a single run.

:::note
For `app_ui_package`, `dart_cli`, `dart_package`, and `flutter_package`, the org name is the copyright holder in the generated `LICENSE` and accepts any text. Setting `org_name` in `very_good.yaml` applies to these subcommands too.
:::

The `very_good.yaml` file is looked up starting from the directory where the command runs and walking up through its ancestors. The closest file wins; configuration from ancestor directories is not merged. This lets a single `very_good.yaml` at the repository root apply to commands run from any nested package.

## Available templates
Expand Down
3 changes: 3 additions & 0 deletions site/docs/templates/app_ui_package.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ generated project.
# Create a new App UI package named my_app_ui
very_good create app_ui_package my_app_ui --desc "My new App UI package"

# Create a new App UI package with a custom copyright holder
very_good create app_ui_package my_app_ui --desc "My new App UI package" --org-name "My Company"

# Create a new App UI package that is publishable
very_good create app_ui_package my_app_ui --desc "My new App UI package" --publishable

Expand Down
3 changes: 3 additions & 0 deletions site/docs/templates/dart_cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ very_good create dart_cli my_dart_cli --desc "My new Dart CLI package"
# Create a new Dart CLI application named my_dart_cli with a custom executable name
very_good create dart_cli my_dart_cli --desc "My new Dart CLI package" --executable-name my_executable_name

# Create a new Dart CLI application named my_dart_cli with a custom copyright holder
very_good create dart_cli my_dart_cli --desc "My new Dart CLI package" --org-name "My Company"

# Create a new Dart CLI application named my_dart_cli that is publishable
very_good create dart_cli my_dart_cli --desc "My new Dart CLI package" --publishable

Expand Down
3 changes: 3 additions & 0 deletions site/docs/templates/dart_pkg.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ Use `-o` or `--output-directory` to specify a custom output directory for the ge
# Create a new Dart package named my_dart_package
very_good create dart_package my_dart_package --desc "My new Dart package"

# Create a new Dart package named my_dart_package with a custom copyright holder
very_good create dart_package my_dart_package --desc "My new Dart package" --org-name "My Company"

# Create a new Dart package named my_dart_package that is publishable
very_good create dart_package my_dart_package --desc "My new Dart package" --publishable

Expand Down
3 changes: 3 additions & 0 deletions site/docs/templates/flutter_pkg.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ Use `-o` or `--output-directory` to specify a custom output directory for the ge
# Create a new Flutter package named my_flutter_package
very_good create flutter_package my_flutter_package --desc "My new Flutter package"

# Create a new Flutter package named my_flutter_package with a custom copyright holder
very_good create flutter_package my_flutter_package --desc "My new Flutter package" --org-name "My Company"

# Create a new Flutter package named my_flutter_package that is publishable
very_good create flutter_package my_flutter_package --desc "My new Flutter package" --publishable

Expand Down
18 changes: 18 additions & 0 deletions test/src/commands/create/commands/app_ui_package_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ Usage: very_good create app_ui_package <project-name> [arguments]
(defaults to "A Very Good Project created by Very Good CLI.")
--publishable Whether the generated project is intended to be published.
--[no-]workspace Whether the generated project should resolve its dependencies from a parent Pub workspace.
--org-name The organization for this new project.
(defaults to "com.example.verygoodapp")

Run "very_good help" to see global options.''',
];
Expand Down Expand Up @@ -103,6 +105,20 @@ void main() {
}),
);

test('passes the org name', () {
final command = CreateAppUiPackage(
logger: logger,
generatorFromBundle: null,
);
command.argResultOverrides = command.argParser.parse([
'my_app_ui',
'--org-name',
'Acme',
]);

expect(command.getTemplateVars(), containsPair('org_name', 'Acme'));
});

group('running the command', () {
final generatedFiles = List.filled(
10,
Expand Down Expand Up @@ -187,6 +203,7 @@ void main() {
'description': '',
'publishable': false,
'workspace': false,
'org_name': 'com.example.verygoodapp',
},
onVarsChanged: any(named: 'onVarsChanged'),
),
Expand All @@ -199,6 +216,7 @@ void main() {
'description': '',
'publishable': false,
'workspace': false,
'org_name': 'com.example.verygoodapp',
},
logger: logger,
),
Expand Down
15 changes: 15 additions & 0 deletions test/src/commands/create/commands/dart_cli_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ Usage: very_good create dart_cli <project-name> [arguments]
(defaults to "A Very Good Project created by Very Good CLI.")
--publishable Whether the generated project is intended to be published.
--[no-]workspace Whether the generated project should resolve its dependencies from a parent Pub workspace.
--org-name The organization for this new project.
(defaults to "Very Good Ventures")
--executable-name The CLI executable name (defaults to the project name)

Run "very_good help" to see global options.''',
Expand Down Expand Up @@ -102,6 +104,17 @@ void main() {
}),
);

test('passes the org name', () {
final command = CreateDartCLI(logger: logger, generatorFromBundle: null);
command.argResultOverrides = command.argParser.parse([
'my_cli',
'--org-name',
'Acme',
]);

expect(command.getTemplateVars(), containsPair('org_name', 'Acme'));
});

group('running the command', () {
final generatedFiles = List.filled(
10,
Expand Down Expand Up @@ -188,6 +201,7 @@ void main() {
'description': '',
'publishable': false,
'workspace': false,
'org_name': 'Very Good Ventures',
'executable_name': 'my_executable',
},
onVarsChanged: any(named: 'onVarsChanged'),
Expand All @@ -201,6 +215,7 @@ void main() {
'description': '',
'publishable': false,
'workspace': false,
'org_name': 'Very Good Ventures',
'executable_name': 'my_executable',
},
logger: logger,
Expand Down
18 changes: 18 additions & 0 deletions test/src/commands/create/commands/dart_package_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ Usage: very_good create dart_package <project-name> [arguments]
(defaults to "A Very Good Project created by Very Good CLI.")
--publishable Whether the generated project is intended to be published.
--[no-]workspace Whether the generated project should resolve its dependencies from a parent Pub workspace.
--org-name The organization for this new project.
(defaults to "Very Good Ventures")

Run "very_good help" to see global options.''',
];
Expand Down Expand Up @@ -100,6 +102,20 @@ void main() {
}),
);

test('passes the org name', () {
final command = CreateDartPackage(
logger: logger,
generatorFromBundle: null,
);
command.argResultOverrides = command.argParser.parse([
'my_package',
'--org-name',
'Acme',
]);

expect(command.getTemplateVars(), containsPair('org_name', 'Acme'));
});

group('running the command', () {
final generatedFiles = List.filled(
10,
Expand Down Expand Up @@ -184,6 +200,7 @@ void main() {
'description': '',
'publishable': false,
'workspace': false,
'org_name': 'Very Good Ventures',
},
onVarsChanged: any(named: 'onVarsChanged'),
),
Expand All @@ -196,6 +213,7 @@ void main() {
'description': '',
'publishable': false,
'workspace': false,
'org_name': 'Very Good Ventures',
},
logger: logger,
),
Expand Down
Loading
Loading