├── .pubignore ├── site ├── static │ ├── .nojekyll │ ├── CNAME │ └── img │ │ ├── favicon.ico │ │ ├── watch.jpeg │ │ ├── docs_dark.png │ │ ├── docs_light.png │ │ ├── core_devices.png │ │ ├── dart_cli_hero.png │ │ ├── meta │ │ └── open-graph.png │ │ ├── docs_overview_dark.png │ │ ├── docs_overview_light.png │ │ ├── icon_commands.svg │ │ └── cli_icon.svg ├── .prettierrc ├── .prettierignore ├── babel.config.js ├── docs │ ├── resources │ │ ├── learn_more.md │ │ ├── _category_.json │ │ ├── tutorials.md │ │ └── syntax_changes_in_0_10_0.md │ ├── commands │ │ ├── _category_.json │ │ └── get_pkgs.md │ └── templates │ │ ├── _category_.json │ │ ├── dart_pkg.md │ │ ├── flutter_pkg.md │ │ ├── dart_cli.md │ │ ├── wear.md │ │ ├── federated_plugin.md │ │ ├── docs_site.md │ │ └── flame_game.md ├── tsconfig.json ├── .gitignore ├── eslint.config.js ├── sidebars.js ├── README.md ├── package.json ├── src │ └── pages │ │ └── index.module.css └── docusaurus.config.js ├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── build.yaml │ ├── feature_request.yaml │ ├── ci.yaml │ ├── style.yaml │ ├── chore.yaml │ ├── test.yaml │ ├── refactor.yaml │ ├── revert.yaml │ ├── performance.yaml │ ├── documentation.yaml │ └── bug_report.yaml ├── CODEOWNERS ├── labels.yml ├── workflows │ ├── sync_labels.yaml │ ├── ci.yaml │ ├── release_please.yaml │ ├── pub_publish.yaml │ ├── site.yaml │ ├── bump_templates.yaml │ ├── site_deploy.yaml │ ├── test_optimizer.yaml │ ├── very_good_cli.yaml │ ├── spdx_license_bot.yaml │ ├── e2e.yaml │ └── spdx_license.yaml ├── dependabot.yaml ├── PULL_REQUEST_TEMPLATE.md └── cspell.json ├── .release-please-manifest.json ├── lib ├── src │ ├── commands │ │ ├── packages │ │ │ ├── commands │ │ │ │ ├── commands.dart │ │ │ │ ├── check │ │ │ │ │ ├── commands │ │ │ │ │ │ └── commands.dart │ │ │ │ │ └── check.dart │ │ │ │ └── get.dart │ │ │ └── packages.dart │ │ ├── dart │ │ │ ├── commands │ │ │ │ └── commands.dart │ │ │ └── dart.dart │ │ ├── create │ │ │ ├── templates │ │ │ │ ├── very_good_core │ │ │ │ │ ├── very_good_core.dart │ │ │ │ │ └── very_good_core_template.dart │ │ │ │ ├── very_good_dart_cli │ │ │ │ │ ├── very_good_dart_cli.dart │ │ │ │ │ └── very_good_dart_cli_template.dart │ │ │ │ ├── very_good_wear_app │ │ │ │ │ ├── very_good_wear_app.dart │ │ │ │ │ └── very_good_wear_app_template.dart │ │ │ │ ├── very_good_docs_site │ │ │ │ │ ├── very_good_docs_site.dart │ │ │ │ │ └── very_good_docs_site_template.dart │ │ │ │ ├── very_good_flame_game │ │ │ │ │ ├── very_good_flame_game.dart │ │ │ │ │ └── very_good_flame_game_template.dart │ │ │ │ ├── very_good_dart_package │ │ │ │ │ ├── very_good_dart_package.dart │ │ │ │ │ └── very_good_dart_package_template.dart │ │ │ │ ├── very_good_flutter_plugin │ │ │ │ │ ├── very_good_flutter_plugin.dart │ │ │ │ │ └── very_good_flutter_plugin_template.dart │ │ │ │ ├── very_good_flutter_package │ │ │ │ │ ├── very_good_flutter_package.dart │ │ │ │ │ └── very_good_flutter_package_template.dart │ │ │ │ ├── templates.dart │ │ │ │ ├── template.dart │ │ │ │ └── post_generate_actions.dart │ │ │ ├── commands │ │ │ │ ├── commands.dart │ │ │ │ ├── dart_package.dart │ │ │ │ ├── flutter_package.dart │ │ │ │ ├── docs_site.dart │ │ │ │ ├── dart_cli.dart │ │ │ │ ├── flutter_app.dart │ │ │ │ ├── flame_game.dart │ │ │ │ └── flutter_plugin.dart │ │ │ └── create.dart │ │ ├── commands.dart │ │ └── update.dart │ ├── cli │ │ ├── templates │ │ │ └── templates.dart │ │ ├── git_cli.dart │ │ └── dart_cli.dart │ ├── mcp │ │ ├── mcp.dart │ │ └── mcp_command.dart │ ├── version.dart │ └── logger_extension.dart └── very_good_cli.dart ├── mason.yaml ├── test ├── fixtures │ ├── fixtures.dart │ ├── golden_test.png │ └── lcov_fixtures.dart ├── helpers │ ├── helpers.dart │ ├── command_helper.dart │ └── test_multi_template_commands.dart ├── ensure_build_test.dart └── src │ ├── commands │ ├── dart │ │ └── dart_test.dart │ ├── packages │ │ ├── packages_test.dart │ │ └── commands │ │ │ └── check │ │ │ └── check_test.dart │ └── create │ │ └── create_test.dart │ └── cli │ ├── process_overrides_test.dart │ └── git_cli_test.dart ├── dart_test.yaml ├── tool ├── spdx_license │ ├── hooks │ │ ├── analysis_options.yaml │ │ ├── dart_test.yaml │ │ └── pubspec.yaml │ ├── analysis_options.yaml │ ├── brick.yaml │ ├── pubspec.yaml │ ├── test │ │ └── spdx_license_test.dart │ ├── __brick__ │ │ └── spdx_license.gen.dart │ ├── README.md │ └── CONTRIBUTING.md ├── generate_test_optimizer_bundle.sh └── generate_bundles.sh ├── doc └── assets │ ├── vgv_logo.png │ ├── very_good_create.gif │ └── very_good_create.png ├── e2e ├── test │ └── commands │ │ ├── test │ │ ├── compilation_error │ │ │ ├── fixture │ │ │ │ ├── analysis_options.yaml │ │ │ │ ├── lib │ │ │ │ │ └── compilation_error.dart │ │ │ │ ├── pubspec.yaml │ │ │ │ └── test │ │ │ │ │ └── src │ │ │ │ │ └── my_package_test.dart │ │ │ └── compilation_error_test.dart │ │ ├── spaced_golden_file_name │ │ │ ├── fixture │ │ │ │ ├── test │ │ │ │ │ ├── sized box.png │ │ │ │ │ └── spaced_golden_file_name_test.dart │ │ │ │ └── pubspec.yaml │ │ │ └── spaced_golden_file_name_test.dart │ │ ├── async_main │ │ │ ├── fixture │ │ │ │ ├── pubspec.yaml │ │ │ │ └── test │ │ │ │ │ └── async_main_test.dart │ │ │ └── async_main_test.dart │ │ └── no_project │ │ │ ├── fixture │ │ │ └── pubspec.yaml │ │ │ └── no_project_test.dart │ │ ├── create │ │ ├── docs_site │ │ │ └── docs_site_test.dart │ │ ├── flutter_app │ │ │ └── core_test.dart │ │ ├── flame_game │ │ │ └── flame_game_test.dart │ │ ├── flutter_package │ │ │ └── flutter_pkg_test.dart │ │ ├── dart_cli │ │ │ └── dart_cli_test.dart │ │ ├── dart_package │ │ │ └── dart_pkg_test.dart │ │ └── flutter_plugin │ │ │ └── flutter_plugin_test.dart │ │ └── packages │ │ └── check │ │ └── licenses │ │ ├── unknown_licenses_test.dart │ │ ├── licenses_allowed_test.dart │ │ └── licenses_forbidden_test.dart ├── analysis_options.yaml ├── helpers │ ├── helpers.dart │ ├── copy_directory.dart │ ├── expect_successful_process_result.dart │ └── command_helper.dart ├── .gitignore └── pubspec.yaml ├── analysis_options.yaml ├── bricks └── test_optimizer │ ├── hooks │ ├── analysis_options.yaml │ ├── pre_gen.dart │ ├── pubspec.yaml │ ├── lib │ │ ├── dart_identifier_generator.dart │ │ └── pre_gen.dart │ └── test │ │ └── dart_identifier_generator_test.dart │ ├── brick.yaml │ ├── README.md │ ├── __brick__ │ └── test │ │ └── .test_optimizer.dart │ └── CONTRIBUTING.md ├── example └── README.md ├── .gitignore ├── bin └── very_good.dart ├── .release-please-config.json ├── LICENSE ├── coverage_badge.svg ├── pubspec.yaml └── CODE_OF_CONDUCT.md /.pubignore: -------------------------------------------------------------------------------- 1 | tool/ -------------------------------------------------------------------------------- /site/static/.nojekyll: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /site/static/CNAME: -------------------------------------------------------------------------------- 1 | cli.vgv.dev -------------------------------------------------------------------------------- /site/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false -------------------------------------------------------------------------------- /.release-please-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | ".": "0.28.0" 3 | } 4 | -------------------------------------------------------------------------------- /lib/src/commands/packages/commands/commands.dart: -------------------------------------------------------------------------------- 1 | export 'get.dart'; 2 | -------------------------------------------------------------------------------- /lib/src/cli/templates/templates.dart: -------------------------------------------------------------------------------- 1 | export 'test_optimizer_bundle.dart'; 2 | -------------------------------------------------------------------------------- /mason.yaml: -------------------------------------------------------------------------------- 1 | bricks: 2 | spdx_license: 3 | path: tool/spdx_license 4 | -------------------------------------------------------------------------------- /lib/src/commands/dart/commands/commands.dart: -------------------------------------------------------------------------------- 1 | export 'dart_test_command.dart'; 2 | -------------------------------------------------------------------------------- /lib/src/mcp/mcp.dart: -------------------------------------------------------------------------------- 1 | export 'mcp_command.dart'; 2 | export 'mcp_server.dart'; 3 | -------------------------------------------------------------------------------- /lib/src/commands/packages/commands/check/commands/commands.dart: -------------------------------------------------------------------------------- 1 | export 'licenses.dart'; 2 | -------------------------------------------------------------------------------- /site/.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | /build 3 | /public/build 4 | .env 5 | .docusaurus 6 | -------------------------------------------------------------------------------- /test/fixtures/fixtures.dart: -------------------------------------------------------------------------------- 1 | export 'lcov_fixtures.dart'; 2 | export 'test_runner_fixtures.dart'; 3 | -------------------------------------------------------------------------------- /dart_test.yaml: -------------------------------------------------------------------------------- 1 | tags: 2 | pull-request-only: 3 | skip: "Should only be run during pull request" 4 | -------------------------------------------------------------------------------- /test/helpers/helpers.dart: -------------------------------------------------------------------------------- 1 | export 'command_helper.dart'; 2 | export 'test_multi_template_commands.dart'; 3 | -------------------------------------------------------------------------------- /tool/spdx_license/hooks/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.yaml 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Every request must be reviewed and accepted by: 2 | 3 | * @VeryGoodOpenSource/codeowners 4 | -------------------------------------------------------------------------------- /doc/assets/vgv_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/very_good_cli/HEAD/doc/assets/vgv_logo.png -------------------------------------------------------------------------------- /e2e/test/commands/test/compilation_error/fixture/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | analyzer: 2 | exclude: 3 | - test 4 | -------------------------------------------------------------------------------- /e2e/test/commands/test/compilation_error/fixture/lib/compilation_error.dart: -------------------------------------------------------------------------------- 1 | class Thing { 2 | const Thing(); 3 | } 4 | -------------------------------------------------------------------------------- /lib/src/version.dart: -------------------------------------------------------------------------------- 1 | // Generated code. Do not modify. 2 | const packageVersion = '0.28.0'; // x-release-please-version 3 | -------------------------------------------------------------------------------- /site/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /site/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/very_good_cli/HEAD/site/static/img/favicon.ico -------------------------------------------------------------------------------- /site/static/img/watch.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/very_good_cli/HEAD/site/static/img/watch.jpeg -------------------------------------------------------------------------------- /site/static/img/docs_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/very_good_cli/HEAD/site/static/img/docs_dark.png -------------------------------------------------------------------------------- /site/static/img/docs_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/very_good_cli/HEAD/site/static/img/docs_light.png -------------------------------------------------------------------------------- /test/fixtures/golden_test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/very_good_cli/HEAD/test/fixtures/golden_test.png -------------------------------------------------------------------------------- /tool/spdx_license/hooks/dart_test.yaml: -------------------------------------------------------------------------------- 1 | tags: 2 | pull-request-only: 3 | skip: "Should only be run during pull request" 4 | -------------------------------------------------------------------------------- /doc/assets/very_good_create.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/very_good_cli/HEAD/doc/assets/very_good_create.gif -------------------------------------------------------------------------------- /doc/assets/very_good_create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/very_good_cli/HEAD/doc/assets/very_good_create.png -------------------------------------------------------------------------------- /site/static/img/core_devices.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/very_good_cli/HEAD/site/static/img/core_devices.png -------------------------------------------------------------------------------- /site/static/img/dart_cli_hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/very_good_cli/HEAD/site/static/img/dart_cli_hero.png -------------------------------------------------------------------------------- /site/static/img/meta/open-graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/very_good_cli/HEAD/site/static/img/meta/open-graph.png -------------------------------------------------------------------------------- /e2e/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.yaml 2 | analyzer: 3 | exclude: 4 | - test/commands/test/** 5 | -------------------------------------------------------------------------------- /e2e/helpers/helpers.dart: -------------------------------------------------------------------------------- 1 | export 'command_helper.dart'; 2 | export 'copy_directory.dart'; 3 | export 'expect_successful_process_result.dart'; 4 | -------------------------------------------------------------------------------- /site/docs/resources/learn_more.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | --- 4 | 5 | # Learn More 📖 6 | 7 | Additional content about Very Good CLI. 8 | -------------------------------------------------------------------------------- /site/static/img/docs_overview_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/very_good_cli/HEAD/site/static/img/docs_overview_dark.png -------------------------------------------------------------------------------- /site/static/img/docs_overview_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/very_good_cli/HEAD/site/static/img/docs_overview_light.png -------------------------------------------------------------------------------- /lib/src/commands/create/templates/very_good_core/very_good_core.dart: -------------------------------------------------------------------------------- 1 | export 'very_good_core_bundle.dart'; 2 | export 'very_good_core_template.dart'; 3 | -------------------------------------------------------------------------------- /tool/spdx_license/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.yaml 2 | analyzer: 3 | exclude: 4 | - __brick__/ 5 | -------------------------------------------------------------------------------- /.github/labels.yml: -------------------------------------------------------------------------------- 1 | - name: "platform: windows" 2 | color: "78EFFF" 3 | description: Building on or for Windows specifically 4 | aliases: [windows] 5 | -------------------------------------------------------------------------------- /lib/src/commands/create/templates/very_good_dart_cli/very_good_dart_cli.dart: -------------------------------------------------------------------------------- 1 | export 'very_good_dart_cli_bundle.dart'; 2 | export 'very_good_dart_cli_template.dart'; 3 | -------------------------------------------------------------------------------- /lib/src/commands/create/templates/very_good_wear_app/very_good_wear_app.dart: -------------------------------------------------------------------------------- 1 | export 'very_good_wear_app_bundle.dart'; 2 | export 'very_good_wear_app_template.dart'; 3 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.yaml 2 | analyzer: 3 | exclude: 4 | - "**/version.dart" 5 | - "bricks/**/__brick__" 6 | -------------------------------------------------------------------------------- /lib/src/commands/create/templates/very_good_docs_site/very_good_docs_site.dart: -------------------------------------------------------------------------------- 1 | export 'very_good_docs_site_bundle.dart'; 2 | export 'very_good_docs_site_template.dart'; 3 | -------------------------------------------------------------------------------- /bricks/test_optimizer/hooks/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.yaml 2 | linter: 3 | rules: 4 | public_member_api_docs: false 5 | -------------------------------------------------------------------------------- /lib/src/commands/create/templates/very_good_flame_game/very_good_flame_game.dart: -------------------------------------------------------------------------------- 1 | export 'very_good_flame_game_bundle.dart'; 2 | export 'very_good_flame_game_template.dart'; 3 | -------------------------------------------------------------------------------- /e2e/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by pub 4 | .dart_tool/ 5 | .packages 6 | build/ 7 | pubspec.lock -------------------------------------------------------------------------------- /lib/src/commands/create/templates/very_good_dart_package/very_good_dart_package.dart: -------------------------------------------------------------------------------- 1 | export 'very_good_dart_package_bundle.dart'; 2 | export 'very_good_dart_package_template.dart'; 3 | -------------------------------------------------------------------------------- /lib/src/commands/create/templates/very_good_flutter_plugin/very_good_flutter_plugin.dart: -------------------------------------------------------------------------------- 1 | export 'very_good_flutter_plugin_bundle.dart'; 2 | export 'very_good_flutter_plugin_template.dart'; 3 | -------------------------------------------------------------------------------- /lib/src/commands/create/templates/very_good_flutter_package/very_good_flutter_package.dart: -------------------------------------------------------------------------------- 1 | export 'very_good_flutter_package_bundle.dart'; 2 | export 'very_good_flutter_package_template.dart'; 3 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # Example 2 | 3 | ```sh 4 | # Activate Very Good CLI 5 | dart pub global activate very_good_cli 6 | 7 | # See list of available commands 8 | very_good --help 9 | ``` 10 | -------------------------------------------------------------------------------- /e2e/test/commands/test/spaced_golden_file_name/fixture/test/sized box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/very_good_cli/HEAD/e2e/test/commands/test/spaced_golden_file_name/fixture/test/sized box.png -------------------------------------------------------------------------------- /bricks/test_optimizer/hooks/pre_gen.dart: -------------------------------------------------------------------------------- 1 | import 'package:mason/mason.dart'; 2 | 3 | import 'lib/pre_gen.dart' as pre_gen; 4 | 5 | Future run(HookContext context) async { 6 | await pre_gen.run(context); 7 | } 8 | -------------------------------------------------------------------------------- /lib/src/commands/commands.dart: -------------------------------------------------------------------------------- 1 | export 'create/commands/commands.dart'; 2 | export 'create/create.dart'; 3 | export 'dart/dart.dart'; 4 | export 'packages/packages.dart'; 5 | export 'test/test.dart'; 6 | export 'update.dart'; 7 | -------------------------------------------------------------------------------- /e2e/test/commands/test/compilation_error/fixture/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: compilation_error 2 | version: 0.1.0+1 3 | publish_to: none 4 | 5 | environment: 6 | sdk: ^3.10.0 7 | 8 | dev_dependencies: 9 | test: ^1.24.3 10 | -------------------------------------------------------------------------------- /site/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // This file is not used in compilation. It is here just for a nice editor experience. 3 | "extends": "@tsconfig/docusaurus/tsconfig.json", 4 | "compilerOptions": { 5 | "baseUrl": "." 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/ensure_build_test.dart: -------------------------------------------------------------------------------- 1 | @Tags(['pull-request-only']) 2 | library; 3 | 4 | import 'package:build_verify/build_verify.dart'; 5 | import 'package:test/test.dart'; 6 | 7 | void main() { 8 | test('ensure_build', expectBuildClean); 9 | } 10 | -------------------------------------------------------------------------------- /e2e/test/commands/test/async_main/fixture/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: async_main 2 | description: Fixture for testing async main. 3 | version: 0.1.0+1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: ^3.10.0 8 | 9 | dev_dependencies: 10 | test: ^1.24.3 11 | -------------------------------------------------------------------------------- /lib/very_good_cli.dart: -------------------------------------------------------------------------------- 1 | /// A Very Good Command-Line Interface for Dart 🦄 2 | /// 3 | /// ```sh 4 | /// # activate very_good_cli 5 | /// dart pub global activate very_good_cli 6 | /// 7 | /// # see usage 8 | /// very_good --help 9 | /// ``` 10 | library; 11 | -------------------------------------------------------------------------------- /e2e/test/commands/test/async_main/fixture/test/async_main_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:test/test.dart'; 2 | 3 | void main() async { 4 | group('AsyncMain', () { 5 | test('will succeed', () { 6 | expect(true, equals(!false)); 7 | }); 8 | }); 9 | } 10 | -------------------------------------------------------------------------------- /site/docs/commands/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Commands", 3 | "position": 4, 4 | "link": { 5 | "title": "Commands", 6 | "type": "generated-index", 7 | "description": "Learn about the additional commands supported by Very Good CLI." 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /site/docs/resources/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Resources", 3 | "position": 4, 4 | "link": { 5 | "title": "Resources", 6 | "type": "generated-index", 7 | "description": "Learn more about Very Good CLI with tutorials and helpful resources." 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /e2e/test/commands/test/no_project/fixture/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: no_project 2 | description: Fixture for testing no project. 3 | version: 0.1.0+1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: ">=3.0.0 <4.0.0" 8 | 9 | dev_dependencies: 10 | test: ^1.24.3 11 | test_api: 0.6.0 12 | -------------------------------------------------------------------------------- /lib/src/commands/create/commands/commands.dart: -------------------------------------------------------------------------------- 1 | export 'create_subcommand.dart'; 2 | export 'dart_cli.dart'; 3 | export 'dart_package.dart'; 4 | export 'docs_site.dart'; 5 | export 'flame_game.dart'; 6 | export 'flutter_app.dart'; 7 | export 'flutter_package.dart'; 8 | export 'flutter_plugin.dart'; 9 | -------------------------------------------------------------------------------- /tool/spdx_license/brick.yaml: -------------------------------------------------------------------------------- 1 | name: spdx_license 2 | description: Generates a Dart SPDX License enumeration. 3 | version: 0.1.0+1 4 | publish_to: none 5 | 6 | environment: 7 | mason: ^0.1.0 8 | 9 | vars: 10 | licenses: 11 | type: list 12 | description: List of all SPDX licenses 13 | -------------------------------------------------------------------------------- /site/docs/templates/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Templates", 3 | "position": 2, 4 | "link": { 5 | "title": "Templates 🦄", 6 | "type": "generated-index", 7 | "description": "Learn about all of the templates that can be generated with the very_good create command." 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /site/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /e2e/test/commands/test/spaced_golden_file_name/fixture/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: spaced_golden_file_name 2 | description: Fixture for testing golden files with spaced file names. 3 | publish_to: none 4 | 5 | environment: 6 | sdk: ^3.10.0 7 | 8 | dependencies: 9 | flutter: 10 | sdk: flutter 11 | 12 | dev_dependencies: 13 | flutter_test: 14 | sdk: flutter 15 | -------------------------------------------------------------------------------- /e2e/test/commands/test/compilation_error/fixture/test/src/my_package_test.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: prefer_const_constructors 2 | 3 | import 'package:compilation_error/compilation_error.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | void main() { 7 | group(Thing, () { 8 | test('can be instantiated', () { 9 | expect(Thing(thing: true), isNull); 10 | }); 11 | }); 12 | } 13 | -------------------------------------------------------------------------------- /tool/generate_test_optimizer_bundle.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | BUNDLE_OUTPUT_DIR="lib/src/cli/templates" 3 | mason bundle --source path ./bricks/test_optimizer/ -t dart --output-dir $BUNDLE_OUTPUT_DIR 4 | 5 | input="lib/src/cli/templates/test_optimizer_bundle.dart" 6 | echo -e "// To generate this file, run: tool/generate_test_optimizer_bundle.sh\n$(cat $input)" > $input 7 | 8 | dart format $BUNDLE_OUTPUT_DIR -------------------------------------------------------------------------------- /bricks/test_optimizer/brick.yaml: -------------------------------------------------------------------------------- 1 | name: test_optimizer 2 | description: A brick that generates a single entrypoint for Dart tests. 3 | version: 0.1.0+1 4 | publish_to: none 5 | 6 | environment: 7 | mason: ^0.1.0 8 | 9 | vars: 10 | package-root: 11 | type: string 12 | default: "." 13 | description: The path to the package root. 14 | prompt: Please enter the path to the package root. 15 | -------------------------------------------------------------------------------- /bricks/test_optimizer/hooks/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: hooks 2 | publish_to: none 3 | 4 | environment: 5 | sdk: ^3.10.0 6 | 7 | dependencies: 8 | mason: ^0.1.0 9 | path: ^1.8.1 10 | 11 | # Beware: on hooks, even dev dependencies have to be compatible to all dart versions covered by 12 | # the sdk constraints above 13 | dev_dependencies: 14 | mocktail: ^1.0.0 15 | test: ^1.25.0 16 | very_good_analysis: ^10.0.0 17 | -------------------------------------------------------------------------------- /e2e/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: very_good_cli_e2e 2 | description: End to End tests for package:very_good_cli 3 | version: 0.1.0+1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: ^3.10.0 8 | 9 | dev_dependencies: 10 | mason: ^0.1.0 11 | mocktail: ^1.0.0 12 | path: ^1.8.0 13 | pub_updater: ^0.5.0 14 | test: ^1.25.0 15 | universal_io: ^2.0.4 16 | very_good_analysis: ^10.0.0 17 | very_good_cli: 18 | path: ../ 19 | -------------------------------------------------------------------------------- /tool/spdx_license/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: spdx_license_brick_test 2 | description: Testing package for the SPDX License brick output. 3 | version: 0.1.0+1 4 | repository: https://github.com/VeryGoodOpenSource/very_good_cli 5 | issue_tracker: https://github.com/VeryGoodOpenSource/very_good_cli/issues 6 | publish_to: none 7 | 8 | environment: 9 | sdk: ^3.10.0 10 | 11 | dev_dependencies: 12 | test: ^1.25.2 13 | very_good_analysis: ^10.0.0 14 | -------------------------------------------------------------------------------- /site/eslint.config.js: -------------------------------------------------------------------------------- 1 | const js = require('@eslint/js'); 2 | const globals = require('globals'); 3 | const jest = require('eslint-plugin-jest'); 4 | 5 | module.exports = [ 6 | { 7 | files: ['*.js'], 8 | ignores: ['eslint.config.js'], 9 | rules: { 10 | ...globals.rules, 11 | ...js.configs.recommended.rules, 12 | }, 13 | languageOptions: { 14 | globals: { ...globals.node, ...jest.environments.globals.globals }, 15 | }, 16 | }, 17 | ]; 18 | -------------------------------------------------------------------------------- /e2e/test/commands/test/spaced_golden_file_name/fixture/test/spaced_golden_file_name_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | 4 | void main() { 5 | testWidgets('renders SizedBox', (tester) async { 6 | final widget = SizedBox.shrink(); 7 | await tester.pumpWidget(widget); 8 | 9 | await expectLater( 10 | find.byWidget(widget), 11 | matchesGoldenFile('sized box.png'), 12 | ); 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /site/docs/commands/get_pkgs.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | --- 4 | 5 | # Get Packages 📦 6 | 7 | Get packages in a Dart or Flutter project with `very_good packages get`. 8 | 9 | ## Usage 10 | 11 | ```sh 12 | very_good packages get [arguments] 13 | -h, --help Print this usage information. 14 | -r, --recursive Install dependencies recursively for all nested packages. 15 | --ignore Exclude packages from installing dependencies. 16 | 17 | Run "very_good help" to see global options. 18 | ``` 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub 2 | .dart_tool/ 3 | .packages 4 | pubspec.lock 5 | 6 | # Conventional directory for build outputs 7 | build/ 8 | 9 | # Directory created by dartdoc 10 | doc/api/ 11 | 12 | # Temporary Files 13 | .tmp/ 14 | 15 | # Files generated during tests 16 | .test_coverage.dart 17 | coverage/ 18 | .test_optimizer.dart 19 | !bricks/test_optimizer/__brick__/test/.test_optimizer.dart 20 | 21 | # Android studio and IntelliJ 22 | .idea 23 | 24 | # Misc files 25 | .DS_Store 26 | 27 | # Files generated by Mason 28 | mason-lock.json 29 | .mason -------------------------------------------------------------------------------- /e2e/helpers/copy_directory.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:path/path.dart' as path; 4 | 5 | Future copyDirectory(Directory from, Directory to) async { 6 | await to.create(recursive: true); 7 | await for (final entity in from.list(recursive: true)) { 8 | final toPath = path.join( 9 | to.path, 10 | path.relative(entity.path, from: from.path), 11 | ); 12 | if (entity is Directory) { 13 | await Directory(toPath).create(); 14 | } else if (entity is File) { 15 | await entity.copy(toPath); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tool/spdx_license/hooks/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: spdx_license_hooks 2 | description: Hook for generating SPDX license. 3 | version: 0.1.0+1 4 | repository: https://github.com/VeryGoodOpenSource/very_good_cli 5 | issue_tracker: https://github.com/VeryGoodOpenSource/very_good_cli/issues 6 | publish_to: none 7 | 8 | environment: 9 | sdk: ^3.10.0 10 | 11 | dependencies: 12 | archive: ^4.0.7 13 | http: ^1.2.1 14 | mason: ^0.1.0 15 | meta: ^1.12.0 16 | path: ^1.9.0 17 | 18 | dev_dependencies: 19 | mocktail: ^1.0.3 20 | test: ">=1.25.2 <1.27.0" 21 | very_good_analysis: ^10.0.0 22 | -------------------------------------------------------------------------------- /lib/src/commands/create/templates/templates.dart: -------------------------------------------------------------------------------- 1 | export 'post_generate_actions.dart'; 2 | export 'template.dart'; 3 | export 'very_good_core/very_good_core.dart'; 4 | export 'very_good_dart_cli/very_good_dart_cli.dart'; 5 | export 'very_good_dart_package/very_good_dart_package.dart'; 6 | export 'very_good_docs_site/very_good_docs_site.dart'; 7 | export 'very_good_flame_game/very_good_flame_game.dart'; 8 | export 'very_good_flutter_package/very_good_flutter_package.dart'; 9 | export 'very_good_flutter_plugin/very_good_flutter_plugin.dart'; 10 | export 'very_good_wear_app/very_good_wear_app.dart'; 11 | -------------------------------------------------------------------------------- /site/docs/templates/dart_pkg.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 5 3 | --- 4 | 5 | # Dart Package 🎯 6 | 7 | This template is for a Dart package. 8 | 9 | ## Usage 10 | 11 | ```sh 12 | # Create a new Dart package named my_dart_package 13 | very_good create dart_package my_dart_package --desc "My new Dart package" 14 | 15 | # Create a new Dart package named my_dart_package that is publishable 16 | very_good create dart_package my_dart_package --desc "My new Dart package" --publishable 17 | 18 | # Create a new Dart package named with the name of the current directory 19 | very_good create dart_package . --desc "My new Dart package" 20 | ``` 21 | -------------------------------------------------------------------------------- /tool/generate_bundles.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Runs `mason bundle` to generate bundles for all bricks within the respective templates directories. 3 | 4 | bricks=( 5 | very_good_core 6 | very_good_dart_package 7 | very_good_dart_cli 8 | very_good_flutter_package 9 | very_good_flutter_plugin 10 | very_good_flame_game 11 | very_good_docs_site 12 | very_good_wear_app 13 | ) 14 | 15 | for brick in "${bricks[@]}" 16 | do 17 | echo "bundling $brick..." 18 | mason bundle --source hosted $brick --type dart --output-dir "lib/src/commands/create/templates/$brick/" 19 | done 20 | 21 | dart format lib/src/commands/create/templates -------------------------------------------------------------------------------- /.github/workflows/sync_labels.yaml: -------------------------------------------------------------------------------- 1 | name: ♻️ Sync Labels 2 | 3 | on: 4 | push: 5 | paths: 6 | - .github/labels.yml 7 | branches: 8 | - main 9 | workflow_dispatch: 10 | 11 | jobs: 12 | labels: 13 | name: ♻️ Sync labels 14 | runs-on: ubuntu-20.04 15 | steps: 16 | - name: ⤵️ Check out code from GitHub 17 | uses: actions/checkout@v6 18 | 19 | - name: 🚀 Run Label Sync 20 | uses: srealmoreno/label-sync-action@v2 21 | with: 22 | config-file: | 23 | .github/labels.yml 24 | https://raw.githubusercontent.com/VeryGoodOpenSource/.github/main/.github/labels.yml 25 | -------------------------------------------------------------------------------- /site/sidebars.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Creating a sidebar enables you to: 3 | - create an ordered group of docs 4 | - render a sidebar for each doc of that group 5 | - provide next/previous navigation 6 | 7 | The sidebars can be generated from the filesystem, or explicitly defined here. 8 | 9 | Create as many sidebars as you want. 10 | */ 11 | 12 | // @ts-check 13 | 14 | /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ 15 | const sidebars = { 16 | // By default, Docusaurus generates a sidebar from the docs folder structure 17 | tutorialSidebar: [{ type: 'autogenerated', dirName: '.' }], 18 | }; 19 | 20 | module.exports = sidebars; 21 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | build: 10 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/semantic_pull_request.yml@v1 11 | 12 | spell-check: 13 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/spell_check.yml@v1 14 | with: 15 | includes: "**/*.md" 16 | modified_files_only: false 17 | 18 | pana: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: noop 22 | run: echo 'noop' 23 | 24 | e2e: 25 | runs-on: ubuntu-latest 26 | steps: 27 | - name: noop 28 | run: echo 'noop' 29 | -------------------------------------------------------------------------------- /lib/src/commands/dart/dart.dart: -------------------------------------------------------------------------------- 1 | import 'package:args/command_runner.dart'; 2 | import 'package:mason/mason.dart'; 3 | import 'package:very_good_cli/src/commands/dart/commands/commands.dart'; 4 | 5 | /// {@template dart_command} 6 | /// `very_good dart` command for running dart related commands. 7 | /// {@endtemplate} 8 | class DartCommand extends Command { 9 | /// {@macro packages_command} 10 | DartCommand({required Logger logger}) { 11 | addSubcommand(DartTestCommand(logger: logger)); 12 | } 13 | 14 | @override 15 | String get description => 'Command for running dart related commands.'; 16 | 17 | @override 18 | String get name => 'dart'; 19 | } 20 | -------------------------------------------------------------------------------- /site/docs/templates/flutter_pkg.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 6 3 | --- 4 | 5 | # Flutter Package 🦋 6 | 7 | This template is for a Flutter package. 8 | 9 | ## Usage 10 | 11 | ```sh 12 | # Create a new Flutter package named my_flutter_package 13 | very_good create flutter_package my_flutter_package --desc "My new Flutter package" 14 | 15 | # Create a new Flutter package named my_flutter_package that is publishable 16 | very_good create flutter_package my_flutter_package --desc "My new Flutter package" --publishable 17 | 18 | # Create a new Flutter package named with the name of the current directory 19 | very_good create flutter_package . --desc "My new Flutter package" 20 | ``` 21 | -------------------------------------------------------------------------------- /.github/workflows/release_please.yaml: -------------------------------------------------------------------------------- 1 | name: release_please 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | workflow_dispatch: 9 | push: 10 | branches: 11 | - main 12 | paths: 13 | - "**" 14 | - "!.github/workflows/site.yaml" 15 | - "!site/**" 16 | 17 | jobs: 18 | create_release_pr: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - uses: googleapis/release-please-action@v4 23 | with: 24 | token: ${{ secrets.RELEASE_PLEASE_TOKEN }} 25 | manifest-file: ".release-please-manifest.json" 26 | config-file: ".release-please-config.json" 27 | -------------------------------------------------------------------------------- /.github/workflows/pub_publish.yaml: -------------------------------------------------------------------------------- 1 | name: pub_publish 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v[0-9]+.[0-9]+.[0-9]+*" # tag pattern on pub.dev: 'v{{version}' 7 | workflow_dispatch: 8 | 9 | jobs: 10 | publish: 11 | permissions: 12 | id-token: write # Required for authentication using OIDC 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: 📚 Git Checkout 16 | uses: actions/checkout@v6 17 | - name: 🎯 Setup Dart 18 | uses: dart-lang/setup-dart@v1 19 | with: 20 | sdk: "3.10.0" 21 | - name: 📦 Install Dependencies 22 | run: dart pub get 23 | - name: 📢 Publish 24 | run: dart pub publish --force 25 | -------------------------------------------------------------------------------- /.github/dependabot.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | - package-ecosystem: "npm" 8 | directory: "/site" 9 | schedule: 10 | interval: "weekly" 11 | - package-ecosystem: "pub" 12 | directory: "/bricks/test_optimizer/hooks" 13 | schedule: 14 | interval: "daily" 15 | - package-ecosystem: "pub" 16 | directory: "/tool/spdx_license/hooks" 17 | schedule: 18 | interval: "daily" 19 | - package-ecosystem: "pub" 20 | directory: "/" 21 | schedule: 22 | interval: "daily" 23 | - package-ecosystem: "pub" 24 | directory: "/e2e" 25 | schedule: 26 | interval: "daily" 27 | -------------------------------------------------------------------------------- /bin/very_good.dart: -------------------------------------------------------------------------------- 1 | import 'package:universal_io/io.dart'; 2 | import 'package:very_good_cli/src/command_runner.dart'; 3 | 4 | Future main(List args) async { 5 | await _flushThenExit(await VeryGoodCommandRunner().run(args)); 6 | } 7 | 8 | /// Flushes the stdout and stderr streams, then exits the program with the given 9 | /// status code. 10 | /// 11 | /// This returns a Future that will never complete, since the program will have 12 | /// exited already. This is useful to prevent Future chains from proceeding 13 | /// after you've decided to exit. 14 | Future _flushThenExit(int status) { 15 | return Future.wait([ 16 | stdout.close(), 17 | stderr.close(), 18 | ]).then((_) => exit(status)); 19 | } 20 | -------------------------------------------------------------------------------- /site/docs/templates/dart_cli.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 4 3 | --- 4 | 5 | # Dart CLI 💻 6 | 7 | This template is for a Dart Command-Line Interface. 8 | 9 | ![Very Good Dart CLI][dart_cli] 10 | 11 | ## Usage 12 | 13 | ```sh 14 | # Create a new Dart CLI application named my_dart_cli 15 | very_good create dart_cli my_dart_cli --desc "My new Dart CLI package" 16 | 17 | # Create a new Dart CLI application named my_dart_cli with a custom executable name 18 | very_good create dart_cli my_dart_cli --desc "My new Dart CLI package" --executable-name my_executable_name 19 | 20 | # Create a new Dart CLI named with the name of the current directory 21 | very_good create dart_cli . --desc "My new Dart CLI package" 22 | ``` 23 | 24 | [dart_cli]: /img/dart_cli_hero.png 25 | -------------------------------------------------------------------------------- /lib/src/commands/packages/commands/check/check.dart: -------------------------------------------------------------------------------- 1 | import 'package:args/command_runner.dart'; 2 | import 'package:mason/mason.dart'; 3 | import 'package:very_good_cli/src/commands/packages/commands/check/commands/commands.dart'; 4 | 5 | /// {@template packages_check_command} 6 | /// `very_good packages check` command for performing checks in a Dart or 7 | /// Flutter project. 8 | /// {@endtemplate} 9 | class PackagesCheckCommand extends Command { 10 | /// {@macro packages_check_command} 11 | PackagesCheckCommand({Logger? logger}) { 12 | addSubcommand(PackagesCheckLicensesCommand(logger: logger)); 13 | } 14 | 15 | @override 16 | String get description => 'Perform checks in a Dart or Flutter project.'; 17 | 18 | @override 19 | String get name => 'check'; 20 | } 21 | -------------------------------------------------------------------------------- /lib/src/commands/packages/packages.dart: -------------------------------------------------------------------------------- 1 | import 'package:args/command_runner.dart'; 2 | import 'package:mason/mason.dart'; 3 | import 'package:very_good_cli/src/commands/packages/commands/check/check.dart'; 4 | import 'package:very_good_cli/src/commands/packages/commands/commands.dart'; 5 | 6 | /// {@template packages_command} 7 | /// `very_good packages` command for managing packages. 8 | /// {@endtemplate} 9 | class PackagesCommand extends Command { 10 | /// {@macro packages_command} 11 | PackagesCommand({Logger? logger}) { 12 | addSubcommand(PackagesGetCommand(logger: logger)); 13 | addSubcommand(PackagesCheckCommand(logger: logger)); 14 | } 15 | 16 | @override 17 | String get description => 'Command for managing packages.'; 18 | 19 | @override 20 | String get name => 'packages'; 21 | } 22 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | ## Status 8 | 9 | **READY/IN DEVELOPMENT/HOLD** 10 | 11 | ## Description 12 | 13 | 14 | 15 | ## Type of Change 16 | 17 | 18 | 19 | - [ ] ✨ New feature (non-breaking change which adds functionality) 20 | - [ ] 🛠️ Bug fix (non-breaking change which fixes an issue) 21 | - [ ] ❌ Breaking change (fix or feature that would cause existing functionality to change) 22 | - [ ] 🧹 Code refactor 23 | - [ ] ✅ Build configuration change 24 | - [ ] 📝 Documentation 25 | - [ ] 🗑️ Chore 26 | -------------------------------------------------------------------------------- /e2e/helpers/expect_successful_process_result.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:mason/mason.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | Future expectSuccessfulProcessResult( 7 | String executable, 8 | List arguments, { 9 | required String workingDirectory, 10 | bool validateStderr = true, 11 | }) async { 12 | final result = await Process.run( 13 | executable, 14 | arguments, 15 | workingDirectory: workingDirectory, 16 | runInShell: true, 17 | ); 18 | expect( 19 | result.exitCode, 20 | equals(ExitCode.success.code), 21 | reason: 22 | '''`$executable ${arguments.join(' ')}` in $workingDirectory failed with "${result.stderr}" and "${result.stdout}"''', 23 | ); 24 | if (validateStderr) { 25 | expect(result.stderr, isEmpty); 26 | } 27 | 28 | return result; 29 | } 30 | -------------------------------------------------------------------------------- /lib/src/commands/create/commands/dart_package.dart: -------------------------------------------------------------------------------- 1 | import 'package:very_good_cli/src/commands/commands.dart'; 2 | import 'package:very_good_cli/src/commands/create/templates/templates.dart'; 3 | 4 | /// {@template very_good_create_dart_package_command} 5 | /// A [CreateSubCommand] for creating Dart packages. 6 | /// {@endtemplate} 7 | class CreateDartPackage extends CreateSubCommand with Publishable { 8 | /// {@macro very_good_create_dart_package_command} 9 | CreateDartPackage({ 10 | required super.logger, 11 | required super.generatorFromBundle, 12 | required super.generatorFromBrick, 13 | }); 14 | 15 | @override 16 | String get name => 'dart_package'; 17 | 18 | @override 19 | List get aliases => ['dart_pkg']; 20 | 21 | @override 22 | String get description => 'Generate a Very Good Dart package.'; 23 | 24 | @override 25 | Template get template => DartPkgTemplate(); 26 | } 27 | -------------------------------------------------------------------------------- /lib/src/commands/create/commands/flutter_package.dart: -------------------------------------------------------------------------------- 1 | import 'package:very_good_cli/src/commands/commands.dart'; 2 | import 'package:very_good_cli/src/commands/create/templates/templates.dart'; 3 | 4 | /// {@template very_good_create_flutter_package_command} 5 | /// A [CreateSubCommand] for creating Flutter packages. 6 | /// {@endtemplate} 7 | class CreateFlutterPackage extends CreateSubCommand with Publishable { 8 | /// {@macro very_good_create_flutter_package_command} 9 | CreateFlutterPackage({ 10 | required super.logger, 11 | required super.generatorFromBundle, 12 | required super.generatorFromBrick, 13 | }); 14 | 15 | @override 16 | String get name => 'flutter_package'; 17 | 18 | @override 19 | List get aliases => ['flutter_pkg']; 20 | 21 | @override 22 | String get description => 'Generate a Very Good Flutter package.'; 23 | 24 | @override 25 | Template get template => FlutterPkgTemplate(); 26 | } 27 | -------------------------------------------------------------------------------- /lib/src/commands/create/templates/template.dart: -------------------------------------------------------------------------------- 1 | import 'package:mason/mason.dart'; 2 | import 'package:universal_io/io.dart'; 3 | 4 | /// {@template template} 5 | /// Dart class that represents a VeryGoodCLI supported template. 6 | /// Each template consists of a [MasonBundle], name, 7 | /// and help text describing the template. 8 | /// {@endtemplate} 9 | abstract class Template { 10 | /// {@macro template} 11 | const Template({ 12 | required this.name, 13 | required this.bundle, 14 | required this.help, 15 | }); 16 | 17 | /// The name associated with this template. 18 | final String name; 19 | 20 | /// The [MasonBundle] used to generate this template. 21 | final MasonBundle bundle; 22 | 23 | /// The help text shown in the usage information for the CLI. 24 | final String help; 25 | 26 | /// Callback invoked after template generation has completed. 27 | Future onGenerateComplete(Logger logger, Directory outputDir); 28 | } 29 | -------------------------------------------------------------------------------- /site/README.md: -------------------------------------------------------------------------------- 1 | # 📚 Very Good ClI Docs 2 | 3 | This website is built using [Docusaurus 3](https://docusaurus.io/), a modern static website generator. 4 | 5 | ### ⚙️ Installation 6 | 7 | ``` 8 | $ npm install 9 | ``` 10 | 11 | ### 🧑‍💻 Local Development 12 | 13 | ``` 14 | $ npm start 15 | ``` 16 | 17 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. 18 | 19 | ### 📦 Build 20 | 21 | ``` 22 | $ npm run build 23 | ``` 24 | 25 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 26 | 27 | ### ☁️ Deployment 28 | 29 | Using SSH: 30 | 31 | ``` 32 | $ USE_SSH=true yarn deploy 33 | ``` 34 | 35 | Not using SSH: 36 | 37 | ``` 38 | $ GIT_USER= yarn deploy 39 | ``` 40 | 41 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. 42 | -------------------------------------------------------------------------------- /.github/workflows/site.yaml: -------------------------------------------------------------------------------- 1 | name: site 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - ".github/workflows/site.yaml" 7 | - "site/**" 8 | push: 9 | paths: 10 | - ".github/workflows/site.yaml" 11 | - "site/**" 12 | branches: 13 | - main 14 | 15 | jobs: 16 | build: 17 | runs-on: ubuntu-latest 18 | 19 | defaults: 20 | run: 21 | working-directory: site 22 | 23 | steps: 24 | - name: 📚 Git Checkout 25 | uses: actions/checkout@v6 26 | 27 | - name: ⚙️ Setup Node 28 | uses: actions/setup-node@v6 29 | with: 30 | node-version: 20.x 31 | cache: npm 32 | cache-dependency-path: site/package-lock.json 33 | 34 | - name: 📦 Install Dependencies 35 | run: npm ci 36 | 37 | - name: ✨ Check Format 38 | run: npm run format:check 39 | 40 | - name: 🧹 Lint 41 | run: npm run lint 42 | 43 | - name: 👷 Build website 44 | run: npm run build 45 | -------------------------------------------------------------------------------- /lib/src/commands/create/templates/very_good_docs_site/very_good_docs_site_template.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:mason/mason.dart'; 4 | import 'package:very_good_cli/src/commands/create/templates/templates.dart'; 5 | import 'package:very_good_cli/src/logger_extension.dart'; 6 | 7 | /// {@template docs_site_template} 8 | /// A documentation site template. 9 | /// {@endtemplate} 10 | class VeryGoodDocsSiteTemplate extends Template { 11 | /// {@macro docs_site_template} 12 | VeryGoodDocsSiteTemplate() 13 | : super( 14 | name: 'docs_site', 15 | bundle: veryGoodDocsSiteBundle, 16 | help: 'Generate a Very Good documentation site.', 17 | ); 18 | 19 | @override 20 | Future onGenerateComplete(Logger logger, Directory outputDir) async { 21 | _logSummary(logger); 22 | } 23 | 24 | void _logSummary(Logger logger) { 25 | logger 26 | ..info('\n') 27 | ..created('Created a Very Good documentation site! 🦄') 28 | ..info('\n'); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.github/workflows/bump_templates.yaml: -------------------------------------------------------------------------------- 1 | name: update_templates 2 | 3 | on: 4 | schedule: 5 | # weekly on mondays at 8 am utc 6 | - cron: "0 8 * * 1" 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v6 14 | 15 | - uses: dart-lang/setup-dart@v1 16 | with: 17 | sdk: "3.10.0" 18 | 19 | - name: Install mason 20 | run: dart pub global activate mason_cli 21 | 22 | - name: Bump templates 23 | run: tool/generate_bundles.sh 24 | 25 | - name: Create Pull Request 26 | uses: peter-evans/create-pull-request@v8.0.0 27 | with: 28 | base: main 29 | labels: bot 30 | branch: feat/bump-template-bundles 31 | title: "feat: bump template bundles" 32 | body: Please squash and merge me! 33 | commit-message: "feat: bump template bundles" 34 | token: ${{ secrets.VGV_BOT_PAT }} 35 | sign-commits: true 36 | -------------------------------------------------------------------------------- /.github/cspell.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2", 3 | "$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json", 4 | "dictionaries": ["vgv_allowed", "vgv_forbidden"], 5 | "dictionaryDefinitions": [ 6 | { 7 | "name": "vgv_allowed", 8 | "path": "https://raw.githubusercontent.com/verygoodopensource/very_good_dictionaries/main/allowed.txt", 9 | "description": "Allowed VGV Spellings" 10 | }, 11 | { 12 | "name": "vgv_forbidden", 13 | "path": "https://raw.githubusercontent.com/verygoodopensource/very_good_dictionaries/main/forbidden.txt", 14 | "description": "Forbidden VGV Spellings" 15 | } 16 | ], 17 | "useGitignore": true, 18 | "words": [ 19 | "codeowners", 20 | "contador", 21 | "goldens", 22 | "localizable", 23 | "mipmap", 24 | "mostrado", 25 | "página", 26 | "pregen", 27 | "srealmoreno", 28 | "texto", 29 | "verygoodcore", 30 | "xcassets", 31 | "gradlew", 32 | "fluttium", 33 | "clsx", 34 | "mockingjay" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /lib/src/cli/git_cli.dart: -------------------------------------------------------------------------------- 1 | part of 'cli.dart'; 2 | 3 | /// {@template unreachable_git_dependency} 4 | /// Thrown when `flutter pub get` encounters an unreachable git dependency. 5 | /// {@endtemplate} 6 | class UnreachableGitDependency implements Exception { 7 | /// {@macro unreachable_git_dependency} 8 | const UnreachableGitDependency({required this.remote}); 9 | 10 | /// The associated git remote [Uri]. 11 | final Uri remote; 12 | 13 | @override 14 | String toString() { 15 | return ''' 16 | $remote is unreachable. 17 | Make sure the remote exists and you have the correct access rights.'''; 18 | } 19 | } 20 | 21 | /// Git CLI 22 | class Git { 23 | /// Determine whether the [remote] is reachable. 24 | static Future reachable(Uri remote, {required Logger logger}) async { 25 | try { 26 | await _Cmd.run('git', [ 27 | 'ls-remote', 28 | '$remote', 29 | '--exit-code', 30 | ], logger: logger); 31 | } on Exception catch (_) { 32 | throw UnreachableGitDependency(remote: remote); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /bricks/test_optimizer/hooks/lib/dart_identifier_generator.dart: -------------------------------------------------------------------------------- 1 | /// {@template dart_identifier_generator} 2 | /// A class that generates valid Dart identifiers. 3 | /// 4 | /// See also: 5 | /// 6 | /// * Section 17.37 from [Dart Language Specification](https://dart.dev/guides/language/specifications/DartLangSpec-v2.10.pdf) 7 | /// {@endtemplate} 8 | class DartIdentifierGenerator { 9 | /// {@macro dart_identifier_generator} 10 | DartIdentifierGenerator([ 11 | this._chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', 12 | ]) : _nextId = [0]; 13 | 14 | final String _chars; 15 | final List _nextId; 16 | 17 | /// Generate the next short identifier. 18 | String next() { 19 | final r = ['_', for (final char in _nextId) _chars[char]]; 20 | _increment(); 21 | return r.join(); 22 | } 23 | 24 | void _increment() { 25 | for (var i = 0; i < _nextId.length; i++) { 26 | final val = ++_nextId[i]; 27 | if (val >= _chars.length) { 28 | _nextId[i] = 0; 29 | } else { 30 | return; 31 | } 32 | } 33 | _nextId.add(0); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /.release-please-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", 3 | "changelog-sections": [ 4 | { "type": "feat", "section": "Features" }, 5 | { "type": "fix", "section": "Bug Fixes" }, 6 | { "type": "refactor","section": "Refactors" }, 7 | { "type": "chore", "section": "Miscellaneous Chores" }, 8 | { "type": "docs", "section": "Docs" } 9 | ], 10 | "pull-request-header": ":rotating_light: There are changes ready for release :rocket:\n\nℹ Merge this PR once the team confirms the release is ready.\n", 11 | "pull-request-title-pattern": "chore: ${version}", 12 | "include-component-in-tag": false, 13 | "extra-files": [ 14 | "lib/src/version.dart" 15 | ], 16 | "packages": { 17 | ".": { 18 | "release-type": "dart", 19 | "changelog-path": "CHANGELOG.md", 20 | "version-file": "pubspec.yaml" 21 | } 22 | }, 23 | "exclude-paths": [ 24 | ".github", 25 | "site", 26 | ".release-please-manifest.json", 27 | ".release-please-config.json", 28 | "CONTRIBUTING.md", 29 | "tool" 30 | ] 31 | } -------------------------------------------------------------------------------- /lib/src/commands/create/templates/very_good_dart_package/very_good_dart_package_template.dart: -------------------------------------------------------------------------------- 1 | import 'package:mason/mason.dart'; 2 | import 'package:universal_io/io.dart'; 3 | import 'package:very_good_cli/src/commands/create/templates/templates.dart'; 4 | import 'package:very_good_cli/src/logger_extension.dart'; 5 | 6 | /// {@template dart_pkg_template} 7 | /// A Dart package template. 8 | /// {@endtemplate} 9 | class DartPkgTemplate extends Template { 10 | /// {@macro dart_pkg_template} 11 | DartPkgTemplate() 12 | : super( 13 | name: 'dart_pkg', 14 | bundle: veryGoodDartPackageBundle, 15 | help: 'Generate a Very Good Dart package.', 16 | ); 17 | 18 | @override 19 | Future onGenerateComplete(Logger logger, Directory outputDir) async { 20 | if (await installDartPackages(logger, outputDir)) { 21 | await applyDartFixes(logger, outputDir); 22 | } 23 | _logSummary(logger); 24 | } 25 | 26 | void _logSummary(Logger logger) { 27 | logger 28 | ..info('\n') 29 | ..created('Created a Very Good Dart Package! 🦄') 30 | ..info('\n'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /bricks/test_optimizer/README.md: -------------------------------------------------------------------------------- 1 | # test_optimizer 2 | 3 | [![Powered by Mason](https://img.shields.io/endpoint?url=https%3A%2F%2Ftinyurl.com%2Fmason-badge)](https://github.com/felangel/mason) 4 | 5 | A brick that generates a single entrypoint for Dart tests. 6 | 7 | _Generated by [mason][1] 🧱_ 8 | 9 | ## Getting Started 🚀 10 | 11 | ```sh 12 | mason make test_optimizer --package-root ./path/to/package --on-conflict overwrite 13 | ``` 14 | 15 | The above command will generate a `.test_optimizer.dart` in the `test` directory that imports and executes all tests 16 | 17 | ```dart 18 | // GENERATED CODE - DO NOT MODIFY BY HAND 19 | // Consider adding this file to your .gitignore. 20 | 21 | import 'app/view/app_test.dart' as _a; 22 | import 'counter/cubit/counter_cubit_test.dart' as _b; 23 | import 'counter/view/counter_page_test.dart' as _c; 24 | 25 | void main() { 26 | group('app_view_app_test_dart', () { _a.main(); }); 27 | group('counter_cubit_counter_cubit_test_dart', () { _b.main(); }); 28 | group('counter_view_counter_page_test_dart', () { _c.main(); }); 29 | } 30 | ``` 31 | 32 | [1]: https://github.com/felangel/mason 33 | -------------------------------------------------------------------------------- /lib/src/commands/create/templates/very_good_wear_app/very_good_wear_app_template.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:mason/mason.dart'; 4 | import 'package:very_good_cli/src/commands/create/templates/templates.dart'; 5 | import 'package:very_good_cli/src/logger_extension.dart'; 6 | 7 | /// {@template wear_app_template} 8 | /// A template for Wear OS apps. 9 | /// {@endtemplate} 10 | class VeryGoodWearAppTemplate extends Template { 11 | /// {@macro wear_app_template} 12 | VeryGoodWearAppTemplate() 13 | : super( 14 | name: 'wear', 15 | bundle: veryGoodWearAppBundle, 16 | help: 'Generate a Very Good Flutter Wear OS application.', 17 | ); 18 | 19 | @override 20 | Future onGenerateComplete(Logger logger, Directory outputDir) async { 21 | if (await installFlutterPackages(logger, outputDir)) { 22 | await applyDartFixes(logger, outputDir); 23 | } 24 | _logSummary(logger); 25 | } 26 | 27 | void _logSummary(Logger logger) { 28 | logger 29 | ..info('\n') 30 | ..created('Created a Very Good Wear OS app! ⌚️🦄') 31 | ..info('\n'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/src/commands/create/templates/very_good_dart_cli/very_good_dart_cli_template.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:mason/mason.dart'; 4 | import 'package:very_good_cli/src/commands/create/templates/templates.dart'; 5 | import 'package:very_good_cli/src/logger_extension.dart'; 6 | 7 | /// {@template dart_cli_template} 8 | /// A Dart CLI application template. 9 | /// {@endtemplate} 10 | class VeryGoodDartCLITemplate extends Template { 11 | /// {@macro dart_cli_template} 12 | VeryGoodDartCLITemplate() 13 | : super( 14 | name: 'dart_cli', 15 | bundle: veryGoodDartCliBundle, 16 | help: 'Generate a Very Good Dart CLI application.', 17 | ); 18 | 19 | @override 20 | Future onGenerateComplete(Logger logger, Directory outputDir) async { 21 | if (await installDartPackages(logger, outputDir)) { 22 | await applyDartFixes(logger, outputDir); 23 | } 24 | _logSummary(logger); 25 | } 26 | 27 | void _logSummary(Logger logger) { 28 | logger 29 | ..info('\n') 30 | ..created('Created a Very Good Dart CLI application! 🦄') 31 | ..info('\n'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/src/commands/create/templates/very_good_flame_game/very_good_flame_game_template.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:mason/mason.dart'; 4 | import 'package:very_good_cli/src/commands/create/templates/templates.dart'; 5 | import 'package:very_good_cli/src/logger_extension.dart'; 6 | 7 | /// {@template flame_game_template} 8 | /// A Flame Game template. 9 | /// {@endtemplate} 10 | class VeryGoodFlameGameTemplate extends Template { 11 | /// {@macro flame_game_template} 12 | VeryGoodFlameGameTemplate() 13 | : super( 14 | name: 'flame_game', 15 | bundle: veryGoodFlameGameBundle, 16 | help: 'Generate a Very Good Flame game.', 17 | ); 18 | 19 | @override 20 | Future onGenerateComplete(Logger logger, Directory outputDir) async { 21 | if (await installFlutterPackages(logger, outputDir)) { 22 | await applyDartFixes(logger, outputDir); 23 | } 24 | _logSummary(logger); 25 | } 26 | 27 | void _logSummary(Logger logger) { 28 | logger 29 | ..info('\n') 30 | ..created('Created a Very Good Game powered by Flame! 🔥🦄') 31 | ..info('\n'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Very Good Ventures 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /lib/src/commands/create/templates/very_good_flutter_package/very_good_flutter_package_template.dart: -------------------------------------------------------------------------------- 1 | import 'package:mason/mason.dart'; 2 | import 'package:universal_io/io.dart'; 3 | import 'package:very_good_cli/src/commands/create/templates/templates.dart'; 4 | import 'package:very_good_cli/src/logger_extension.dart'; 5 | 6 | /// {@template flutter_pkg_template} 7 | /// A Flutter package template. 8 | /// {@endtemplate} 9 | class FlutterPkgTemplate extends Template { 10 | /// {@macro flutter_pkg_template} 11 | FlutterPkgTemplate() 12 | : super( 13 | name: 'flutter_pkg', 14 | bundle: veryGoodFlutterPackageBundle, 15 | help: 'Generate a Very Good Flutter package.', 16 | ); 17 | 18 | @override 19 | Future onGenerateComplete(Logger logger, Directory outputDir) async { 20 | if (await installFlutterPackages(logger, outputDir)) { 21 | await applyDartFixes(logger, outputDir); 22 | } 23 | _logSummary(logger); 24 | } 25 | 26 | void _logSummary(Logger logger) { 27 | logger 28 | ..info('\n') 29 | ..created('Created a Very Good Flutter Package! 🦄') 30 | ..info('\n'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /coverage_badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | coverage 16 | coverage 17 | 100% 18 | 100% 19 | 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/build.yaml: -------------------------------------------------------------------------------- 1 | name: Build System 2 | description: Changes that affect the build system or external dependencies 3 | title: "build: " 4 | labels: [build] 5 | body: 6 | - type: textarea 7 | id: description 8 | attributes: 9 | label: Description 10 | description: Describe what changes need to be done to the build system and why 11 | placeholder: "Describe the build system change." 12 | validations: 13 | required: true 14 | - type: textarea 15 | id: requirements 16 | attributes: 17 | label: Requirements 18 | description: The list of requirements that need to be met in order to consider the ticket to be completed. Please be as explicit as possible. 19 | value: | 20 | - [ ] All CI/CD checks are passing. 21 | - [ ] There is no drop in the test coverage percentage. 22 | validations: 23 | required: true 24 | - type: textarea 25 | id: additional-context 26 | attributes: 27 | label: Additional Context 28 | description: Add any other context, including links/screenshots/video recordings/etc about the problem here. 29 | placeholder: "Provide context here." 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yaml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: A new feature to be added to the project 3 | title: "feat: " 4 | labels: [feature] 5 | body: 6 | - type: textarea 7 | id: description 8 | attributes: 9 | label: Description 10 | description: Clearly describe what you are looking to add. The more business/user context the better. 11 | placeholder: "Provide a description of the feature." 12 | validations: 13 | required: true 14 | - type: textarea 15 | id: requirements 16 | attributes: 17 | label: Requirements 18 | description: The list of requirements that need to be met in order to consider the ticket to be completed. Please be as explicit as possible. 19 | value: | 20 | - [ ] All CI/CD checks are passing. 21 | - [ ] There is no drop in the test coverage percentage. 22 | validations: 23 | required: true 24 | - type: textarea 25 | id: additional-context 26 | attributes: 27 | label: Additional Context 28 | description: Add any other context, including links/screenshots/video recordings/etc about the problem here. 29 | placeholder: "Provide context here." 30 | -------------------------------------------------------------------------------- /lib/src/commands/create/templates/very_good_flutter_plugin/very_good_flutter_plugin_template.dart: -------------------------------------------------------------------------------- 1 | import 'package:mason/mason.dart'; 2 | import 'package:universal_io/io.dart'; 3 | import 'package:very_good_cli/src/commands/create/templates/templates.dart'; 4 | import 'package:very_good_cli/src/logger_extension.dart'; 5 | 6 | /// {@template flutter_plugin_template} 7 | /// A Flutter plugin template. 8 | /// {@endtemplate} 9 | class FlutterPluginTemplate extends Template { 10 | /// {@macro flutter_pkg_template} 11 | FlutterPluginTemplate() 12 | : super( 13 | name: 'flutter_plugin', 14 | bundle: veryGoodFlutterPluginBundle, 15 | help: 'Generate a Very Good Flutter plugin.', 16 | ); 17 | 18 | @override 19 | Future onGenerateComplete(Logger logger, Directory outputDir) async { 20 | if (await installFlutterPackages(logger, outputDir, recursive: true)) { 21 | await applyDartFixes(logger, outputDir, recursive: true); 22 | } 23 | _logSummary(logger); 24 | } 25 | 26 | void _logSummary(Logger logger) { 27 | logger 28 | ..info('\n') 29 | ..created('Created a Very Good Flutter Plugin! 🦄') 30 | ..info('\n'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/ci.yaml: -------------------------------------------------------------------------------- 1 | name: Continuous Integration 2 | description: Changes to the CI configuration files and scripts 3 | title: "ci: " 4 | labels: [ci] 5 | body: 6 | - type: textarea 7 | id: description 8 | attributes: 9 | label: Description 10 | description: Describe what changes need to be done to the CI/CD system and why. 11 | placeholder: "Provide a description of the changes that need to be done to the CI/CD system." 12 | validations: 13 | required: true 14 | - type: textarea 15 | id: requirements 16 | attributes: 17 | label: Requirements 18 | description: The list of requirements that need to be met in order to consider the ticket to be completed. Please be as explicit as possible. 19 | value: | 20 | - [ ] All CI/CD checks are passing. 21 | - [ ] There is no drop in the test coverage percentage. 22 | validations: 23 | required: true 24 | - type: textarea 25 | id: additional-context 26 | attributes: 27 | label: Additional Context 28 | description: Add any other context, including links/screenshots/video recordings/etc about the problem here. 29 | placeholder: "Provide context here." 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/style.yaml: -------------------------------------------------------------------------------- 1 | name: Style 2 | description: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc) 3 | title: "style: " 4 | labels: [style] 5 | body: 6 | - type: textarea 7 | id: description 8 | attributes: 9 | label: Description 10 | description: Clearly describe what you are looking to change and why. 11 | placeholder: "Provide a description of the style changes." 12 | validations: 13 | required: true 14 | - type: textarea 15 | id: requirements 16 | attributes: 17 | label: Requirements 18 | description: The list of requirements that need to be met in order to consider the ticket to be completed. Please be as explicit as possible. 19 | value: | 20 | - [ ] All CI/CD checks are passing. 21 | - [ ] There is no drop in the unit or widget test coverage percentage. 22 | validations: 23 | required: true 24 | - type: textarea 25 | id: additional-context 26 | attributes: 27 | label: Additional Context 28 | description: Add any other context, including links/screenshots/video recordings/etc about the problem here. 29 | placeholder: "Provide context here." 30 | -------------------------------------------------------------------------------- /.github/workflows/site_deploy.yaml: -------------------------------------------------------------------------------- 1 | name: site_deploy 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v[0-9]+.[0-9]+.[0-9]+*" 7 | workflow_dispatch: 8 | 9 | jobs: 10 | deploy: 11 | runs-on: ubuntu-latest 12 | 13 | defaults: 14 | run: 15 | working-directory: site 16 | 17 | steps: 18 | - name: 📚 Git Checkout 19 | uses: actions/checkout@v6 20 | 21 | - name: ⚙️ Setup Node 22 | uses: actions/setup-node@v6 23 | with: 24 | node-version: 20.x 25 | cache: npm 26 | cache-dependency-path: site/package-lock.json 27 | 28 | - name: 📦 Install Dependencies 29 | run: npm ci 30 | 31 | - name: ✨ Check Format 32 | run: npm run format:check 33 | 34 | - name: 🧹 Lint 35 | run: npm run lint 36 | 37 | - name: 👷 Build website 38 | run: npm run build 39 | 40 | - name: ☁️ Deploy to GitHub Pages 41 | uses: peaceiris/actions-gh-pages@v4 42 | with: 43 | github_token: ${{ secrets.GITHUB_TOKEN }} 44 | publish_dir: ./site/build 45 | user_name: github-actions[bot] 46 | user_email: 41898282+github-actions[bot]@users.noreply.github.com 47 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: very_good_cli 2 | description: A Very Good Command-Line Interface for Dart created by Very Good Ventures. 3 | version: 0.28.0 4 | homepage: https://cli.vgv.dev/ 5 | repository: https://github.com/VeryGoodOpenSource/very_good_cli 6 | issue_tracker: https://github.com/VeryGoodOpenSource/very_good_cli/issues 7 | documentation: https://cli.vgv.dev/docs/overview 8 | topics: [cli, codegen, test, template, boilerplate] 9 | 10 | environment: 11 | sdk: ^3.10.0 12 | 13 | dependencies: 14 | args: ^2.6.0 15 | cli_completion: ^0.5.1 16 | collection: ^1.19.0 17 | coverage: ^1.15.0 18 | dart_mcp: ^0.4.0 19 | equatable: ^2.0.5 20 | glob: ^2.1.2 21 | lcov_parser: ^0.1.2 22 | mason: ^0.1.0 23 | mason_logger: ^0.3.0 24 | meta: ^1.15.0 25 | package_config: ^2.1.0 26 | pana: ^0.23.0 27 | path: ^1.9.0 28 | pub_updater: ^0.5.0 29 | pubspec_parse: ^1.3.0 30 | stack_trace: ^1.11.1 31 | stream_channel: ^2.1.4 32 | universal_io: ^2.2.2 33 | very_good_test_runner: ^0.3.0 34 | yaml: ^3.1.2 35 | 36 | dev_dependencies: 37 | build_runner: ^2.4.12 38 | build_verify: ^3.1.0 39 | mocktail: ^1.0.4 40 | test: ^1.25.8 41 | very_good_analysis: ^10.0.0 42 | 43 | executables: 44 | very_good: 45 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/chore.yaml: -------------------------------------------------------------------------------- 1 | name: Chore 2 | description: Other changes that don't modify source or test files 3 | title: "chore: " 4 | labels: [chore] 5 | body: 6 | - type: textarea 7 | id: description 8 | attributes: 9 | label: Description 10 | description: Clearly describe what change is needed and why. If this changes code then please use another issue type. 11 | placeholder: "Provide a description of the chore." 12 | validations: 13 | required: true 14 | - type: textarea 15 | id: requirements 16 | attributes: 17 | label: Requirements 18 | description: The list of requirements that need to be met in order to consider the ticket to be completed. Please be as explicit as possible. 19 | value: | 20 | - [ ] No functional changes to the code. 21 | - [ ] All CI/CD checks are passing. 22 | - [ ] There is no drop in the test coverage percentage. 23 | validations: 24 | required: true 25 | - type: textarea 26 | id: additional-context 27 | attributes: 28 | label: Additional Context 29 | description: Add any other context, including links/screenshots/video recordings/etc about the problem here. 30 | placeholder: "Provide context here." 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/test.yaml: -------------------------------------------------------------------------------- 1 | name: Test 2 | description: Adding missing tests or correcting existing tests 3 | title: "test: " 4 | labels: [test] 5 | body: 6 | - type: textarea 7 | id: description 8 | attributes: 9 | label: Description 10 | description: List out the tests that need to be added or changed. Please also include any information as to why this was not covered in the past. 11 | placeholder: "Provide a description of the tests that need to be added or changed." 12 | validations: 13 | required: true 14 | - type: textarea 15 | id: requirements 16 | attributes: 17 | label: Requirements 18 | description: The list of requirements that need to be met in order to consider the ticket to be completed. Please be as explicit as possible. 19 | value: | 20 | - [ ] All CI/CD checks are passing. 21 | - [ ] There is no drop in the test coverage percentage. 22 | validations: 23 | required: true 24 | - type: textarea 25 | id: additional-context 26 | attributes: 27 | label: Additional Context 28 | description: Add any other context, including links/screenshots/video recordings/etc about the problem here. 29 | placeholder: "Provide context here." 30 | -------------------------------------------------------------------------------- /e2e/test/commands/test/no_project/no_project_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:mason/mason.dart'; 2 | import 'package:mocktail/mocktail.dart'; 3 | import 'package:test/test.dart'; 4 | import 'package:universal_io/io.dart'; 5 | 6 | import '../../../../helpers/helpers.dart'; 7 | 8 | void main() { 9 | test( 10 | 'fails if the project does not exist', 11 | withRunner((commandRunner, logger, updater, logs, progressLogs) async { 12 | final tempDirectory = Directory.systemTemp.createTempSync('no_project'); 13 | addTearDown(() => tempDirectory.deleteSync(recursive: true)); 14 | 15 | await copyDirectory( 16 | Directory('test/commands/test/no_project/fixture'), 17 | tempDirectory, 18 | ); 19 | 20 | await expectSuccessfulProcessResult('flutter', [ 21 | 'pub', 22 | 'get', 23 | ], workingDirectory: tempDirectory.path); 24 | 25 | final cwd = Directory.current; 26 | Directory.current = tempDirectory; 27 | addTearDown(() { 28 | Directory.current = cwd; 29 | }); 30 | 31 | final result = await commandRunner.run(['test']); 32 | 33 | verifyNever(() => logger.err(any())); 34 | expect(result, equals(ExitCode.success.code)); 35 | }), 36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/refactor.yaml: -------------------------------------------------------------------------------- 1 | name: Refactor 2 | description: A code change that neither fixes a bug nor adds a feature 3 | title: "refactor: " 4 | labels: [refactor] 5 | body: 6 | - type: textarea 7 | id: description 8 | attributes: 9 | label: Description 10 | description: Clearly describe what needs to be refactored and why. Please provide links to related issues (bugs or upcoming features) in order to help prioritize. 11 | placeholder: "Provide a description of the refactor." 12 | validations: 13 | required: true 14 | - type: textarea 15 | id: requirements 16 | attributes: 17 | label: Requirements 18 | description: The list of requirements that need to be met in order to consider the ticket to be completed. Please be as explicit as possible. 19 | value: | 20 | - [ ] All CI/CD checks are passing. 21 | - [ ] There is no drop in the test coverage percentage. 22 | validations: 23 | required: true 24 | - type: textarea 25 | id: additional-context 26 | attributes: 27 | label: Additional Context 28 | description: Add any other context, including links/screenshots/video recordings/etc about the problem here. 29 | placeholder: "Provide context here." 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/revert.yaml: -------------------------------------------------------------------------------- 1 | name: Revert 2 | description: Revert a previous commit 3 | title: "revert: " 4 | labels: [revert] 5 | body: 6 | - type: textarea 7 | id: description 8 | attributes: 9 | label: Description 10 | description: Provide a link to a PR/Commit that you are looking to revert and why. 11 | placeholder: "Provide a description of and link to the commit that needs to be reverted." 12 | validations: 13 | required: true 14 | - type: textarea 15 | id: requirements 16 | attributes: 17 | label: Requirements 18 | description: The list of requirements that need to be met in order to consider the ticket to be completed. Please be as explicit as possible. 19 | value: | 20 | - [ ] Change has been reverted. 21 | - [ ] No change in unit/widget test coverage has happened. 22 | - [ ] A new ticket is created for any follow on work that needs to happen. 23 | validations: 24 | required: true 25 | - type: textarea 26 | id: additional-context 27 | attributes: 28 | label: Additional Context 29 | description: Add any other context, including links/screenshots/video recordings/etc about the problem here. 30 | placeholder: "Provide context here." 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/performance.yaml: -------------------------------------------------------------------------------- 1 | name: Performance Update 2 | description: A code change that improves performance 3 | title: "perf: " 4 | labels: [performance] 5 | body: 6 | - type: textarea 7 | id: description 8 | attributes: 9 | label: Description 10 | description: Clearly describe what code needs to be changed and what the performance impact is going to be. Bonus point's if you can tie this directly to user experience. 11 | placeholder: " Provide a description of the performance update." 12 | validations: 13 | required: true 14 | - type: textarea 15 | id: requirements 16 | attributes: 17 | label: Requirements 18 | description: The list of requirements that need to be met in order to consider the ticket to be completed. Please be as explicit as possible. 19 | value: | 20 | - [ ] All CI/CD checks are passing. 21 | - [ ] There is no drop in the test coverage percentage. 22 | validations: 23 | required: true 24 | - type: textarea 25 | id: additional-context 26 | attributes: 27 | label: Additional Context 28 | description: Add any other context, including links/screenshots/video recordings/etc about the problem here. 29 | placeholder: "Provide context here." 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/documentation.yaml: -------------------------------------------------------------------------------- 1 | name: Documentation 2 | description: Improve the documentation so all collaborators have a common understanding 3 | title: "docs: " 4 | labels: [documentation] 5 | body: 6 | - type: textarea 7 | id: description 8 | attributes: 9 | label: Description 10 | description: Clearly describe what documentation you are looking to add or improve. 11 | placeholder: "Provide a description of the documentation changes." 12 | validations: 13 | required: true 14 | - type: textarea 15 | id: requirements 16 | attributes: 17 | label: Requirements 18 | description: The list of requirements that need to be met in order to consider the ticket to be completed. Please be as explicit as possible. 19 | value: | 20 | - [ ] No functional changes to the code. 21 | - [ ] All CI/CD checks are passing. 22 | - [ ] There is no drop in the test coverage percentage. 23 | validations: 24 | required: true 25 | - type: textarea 26 | id: additional-context 27 | attributes: 28 | label: Additional Context 29 | description: Add any other context, including links/screenshots/video recordings/etc about the problem here. 30 | placeholder: "Provide context here." 31 | -------------------------------------------------------------------------------- /lib/src/commands/create/commands/docs_site.dart: -------------------------------------------------------------------------------- 1 | import 'package:very_good_cli/src/commands/commands.dart'; 2 | import 'package:very_good_cli/src/commands/create/templates/templates.dart'; 3 | 4 | /// {@template very_good_create_docs_site} 5 | /// A [CreateSubCommand] for creating Dart command line interfaces. 6 | /// {@endtemplate} 7 | class CreateDocsSite extends CreateSubCommand { 8 | /// {@macro very_good_create_docs_site} 9 | CreateDocsSite({ 10 | required super.logger, 11 | required super.generatorFromBundle, 12 | required super.generatorFromBrick, 13 | }) { 14 | argParser.addOption( 15 | 'org-name', 16 | help: 'The organization for this new project.', 17 | defaultsTo: _defaultOrgName, 18 | aliases: ['org'], 19 | ); 20 | } 21 | 22 | static const _defaultOrgName = 'my-org'; 23 | 24 | @override 25 | String get name => 'docs_site'; 26 | 27 | @override 28 | String get description => 'Generate a Very Good documentation site.'; 29 | 30 | @override 31 | Map getTemplateVars() { 32 | return { 33 | ...super.getTemplateVars(), 34 | 'org_name': argResults['org-name'], 35 | }; 36 | } 37 | 38 | @override 39 | Template get template => VeryGoodDocsSiteTemplate(); 40 | } 41 | -------------------------------------------------------------------------------- /lib/src/commands/create/commands/dart_cli.dart: -------------------------------------------------------------------------------- 1 | import 'package:very_good_cli/src/commands/create/commands/commands.dart'; 2 | import 'package:very_good_cli/src/commands/create/templates/templates.dart'; 3 | 4 | /// {@template very_good_create_dart_cli_command} 5 | /// A [CreateSubCommand] for creating Dart command line interfaces. 6 | /// {@endtemplate} 7 | class CreateDartCLI extends CreateSubCommand with Publishable { 8 | /// {@macro very_good_create_dart_cli_command} 9 | CreateDartCLI({ 10 | required super.logger, 11 | required super.generatorFromBundle, 12 | required super.generatorFromBrick, 13 | }) { 14 | argParser.addOption( 15 | 'executable-name', 16 | help: 'The CLI executable name (defaults to the project name)', 17 | ); 18 | } 19 | 20 | @override 21 | String get name => 'dart_cli'; 22 | 23 | @override 24 | String get description => 'Generate a Very Good Dart CLI application.'; 25 | 26 | @override 27 | Template get template => VeryGoodDartCLITemplate(); 28 | 29 | @override 30 | Map getTemplateVars() { 31 | final vars = super.getTemplateVars(); 32 | 33 | final executableName = 34 | argResults['executable-name'] as String? ?? projectName; 35 | 36 | vars['executable_name'] = executableName; 37 | 38 | return vars; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /e2e/test/commands/test/async_main/async_main_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:mason/mason.dart'; 2 | import 'package:path/path.dart' as path; 3 | import 'package:test/test.dart'; 4 | import 'package:universal_io/io.dart'; 5 | 6 | import '../../../../helpers/helpers.dart'; 7 | 8 | void main() { 9 | test( 10 | 'supports async main methods', 11 | timeout: const Timeout(Duration(minutes: 2)), 12 | withRunner((commandRunner, logger, updater, logs, progressLogs) async { 13 | final tempDirectory = Directory.systemTemp.createTempSync('async_main'); 14 | addTearDown(() => tempDirectory.deleteSync(recursive: true)); 15 | 16 | final fixture = Directory( 17 | path.join( 18 | Directory.current.path, 19 | 'test/commands/test/async_main/fixture', 20 | ), 21 | ); 22 | 23 | await copyDirectory(fixture, tempDirectory); 24 | 25 | await expectSuccessfulProcessResult( 26 | 'flutter', 27 | ['pub', 'get'], 28 | workingDirectory: tempDirectory.path, 29 | ); 30 | 31 | final cwd = Directory.current; 32 | Directory.current = tempDirectory; 33 | addTearDown(() => Directory.current = cwd); 34 | 35 | final result = await commandRunner.run(['test']); 36 | expect(result, equals(ExitCode.success.code)); 37 | }), 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /.github/workflows/test_optimizer.yaml: -------------------------------------------------------------------------------- 1 | name: test_optimizer_ci 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | push: 9 | paths: 10 | - .github/workflows/test_optimizer.yaml 11 | - "bricks/test_optimizer/**" 12 | branches: 13 | - main 14 | pull_request: 15 | paths: 16 | - .github/workflows/test_optimizer.yaml 17 | - "bricks/test_optimizer/**" 18 | branches: 19 | - main 20 | 21 | jobs: 22 | build_hooks: 23 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_package.yml@v1 24 | with: 25 | dart_sdk: "3.10.0" 26 | working_directory: bricks/test_optimizer/hooks 27 | 28 | verify_bundle: 29 | runs-on: ubuntu-latest 30 | steps: 31 | - uses: actions/checkout@v6 32 | 33 | - uses: dart-lang/setup-dart@v1 34 | with: 35 | sdk: "3.10.0" 36 | 37 | - name: Install mason 38 | run: dart pub global activate mason_cli 39 | 40 | - name: Run bundle generate 41 | run: tool/generate_test_optimizer_bundle.sh 42 | 43 | - name: Check for unbundled changes 44 | run: git diff --exit-code --quiet || { echo "::error::Changes detected on the test_optimizer brick. Please run tool/generate_test_optimizer_bundle.sh to bundle these changes"; exit 1; } 45 | -------------------------------------------------------------------------------- /test/src/commands/dart/dart_test.dart: -------------------------------------------------------------------------------- 1 | // Expected usage of the plugin will need to be adjacent strings due to format 2 | // and also be longer than 80 chars. 3 | // ignore_for_file: no_adjacent_strings_in_list 4 | 5 | import 'package:mason/mason.dart'; 6 | import 'package:test/test.dart'; 7 | 8 | import '../../../helpers/command_helper.dart'; 9 | 10 | const _expectedDartUsage = [ 11 | 'Command for running dart related commands.\n' 12 | '\n' 13 | 'Usage: very_good dart [arguments]\n' 14 | '-h, --help Print this usage information.\n' 15 | '\n' 16 | 'Available subcommands:\n' 17 | ' test Run tests in a Dart project.\n' 18 | '\n' 19 | 'Run "very_good help" to see global options.', 20 | ]; 21 | 22 | void main() { 23 | group('dart', () { 24 | test( 25 | 'help', 26 | withRunner((commandRunner, logger, pubUpdater, printLogs) async { 27 | final result = await commandRunner.run(['dart', '--help']); 28 | expect(printLogs, equals(_expectedDartUsage)); 29 | expect(result, equals(ExitCode.success.code)); 30 | 31 | printLogs.clear(); 32 | 33 | final resultAbbr = await commandRunner.run(['dart', '-h']); 34 | expect(printLogs, equals(_expectedDartUsage)); 35 | expect(resultAbbr, equals(ExitCode.success.code)); 36 | }), 37 | ); 38 | }); 39 | } 40 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yaml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: Create a report to help us improve 3 | title: "fix: " 4 | labels: [bug] 5 | body: 6 | - type: textarea 7 | id: description 8 | attributes: 9 | label: Description 10 | description: A clear and concise description of what the bug is. 11 | placeholder: "Describe the bug." 12 | validations: 13 | required: true 14 | - type: textarea 15 | id: setps-to-reproduce 16 | attributes: 17 | label: Steps To Reproduce 18 | description: A set of instructions, step by step, explaining how to reproduce the bug. 19 | placeholder: | 20 | 1. Go to '...' 21 | 2. Click on '....' 22 | 3. Scroll down to '....' 23 | 4. See error 24 | validations: 25 | required: true 26 | - type: textarea 27 | id: expected-behavior 28 | attributes: 29 | label: Expected Behavior 30 | description: A clear and concise description of what you expected to happen. 31 | placeholder: "Describe what you expected to happen." 32 | validations: 33 | required: true 34 | - type: textarea 35 | id: additional-context 36 | attributes: 37 | label: Additional Context 38 | description: Add any other context, including links/screenshots/video recordings/etc about the problem here. 39 | placeholder: "Provide context here." 40 | -------------------------------------------------------------------------------- /e2e/test/commands/test/spaced_golden_file_name/spaced_golden_file_name_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:mason/mason.dart'; 2 | import 'package:mocktail/mocktail.dart'; 3 | import 'package:test/test.dart'; 4 | import 'package:universal_io/io.dart'; 5 | 6 | import '../../../../helpers/helpers.dart'; 7 | 8 | void main() { 9 | test( 10 | 'allows golden files with spaces in the name', 11 | timeout: const Timeout(Duration(minutes: 2)), 12 | withRunner((commandRunner, logger, updater, logs, progressLogs) async { 13 | final tempDirectory = Directory.systemTemp.createTempSync('async_main'); 14 | addTearDown(() => tempDirectory.deleteSync(recursive: true)); 15 | 16 | await copyDirectory( 17 | Directory('test/commands/test/spaced_golden_file_name/fixture'), 18 | tempDirectory, 19 | ); 20 | 21 | await expectSuccessfulProcessResult( 22 | 'flutter', 23 | ['pub', 'get'], 24 | workingDirectory: tempDirectory.path, 25 | ); 26 | 27 | await expectSuccessfulProcessResult( 28 | 'flutter', 29 | ['test', '--update-goldens'], 30 | workingDirectory: tempDirectory.path, 31 | ); 32 | 33 | Directory.current = tempDirectory; 34 | final result = await commandRunner.run(['test']); 35 | 36 | verifyNever(() => logger.err(any())); 37 | expect(result, equals(ExitCode.success.code)); 38 | }), 39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /site/docs/templates/wear.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | --- 4 | 5 | # Flutter Wear OS app 🤖⌚️ 6 | 7 | Template for a Wear OS app based on the [Core][core_link]. It includes VGV best practices with additional setup to make Flutter apps stand out on Wear OS devices. 8 | 9 | ![Very Good Wear_App][wear_os_photo] 10 | 11 | :::note 12 | Read more about this app template [in our blog][blog]. 13 | ::: 14 | 15 | ## App Features ✨ 16 | 17 | - **Condensed Layout** - The layout is optimized for the small screen size of Wear OS devices. 18 | 19 | - **Hooked into the Hardware** - The app has a sample usage of the hardware resources of the device. 20 | 21 | - **Ambient Mode** - The app has a sample usage of the ambient mode of the device. 22 | 23 | - **100% Test Coverage** — Each line is executed at least once by a test. 24 | 25 | - **Based on the Core** - This project contains all the best practices of the [Core][core_link]. 26 | 27 | ## Usage 28 | 29 | ```sh 30 | # Create a new Wear OS app named my_wear_app 31 | very_good create flutter_app my_wear_app --desc "My new Wear OS app" --template wear 32 | 33 | # Create a new Wear OS named with the name of the current directory 34 | very_good create flutter_app . --desc "My new Wear OS app" --template wear 35 | ``` 36 | 37 | [blog]: https://verygood.ventures/blog/building-wear-os-apps-with-flutter-a-very-good-guide 38 | [core_link]: /docs/templates/core 39 | [wear_os_photo]: /img/watch.jpeg 40 | -------------------------------------------------------------------------------- /tool/spdx_license/test/spdx_license_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:test/test.dart'; 2 | import 'spdx_license.gen.dart'; 3 | 4 | void main() { 5 | group('SpdxLicense', () { 6 | const invalidLicenseSource = 'invalid'; 7 | 8 | group('parse', () { 9 | test('can parse a valid SPDX license', () { 10 | expect(SpdxLicense.parse('MIT'), SpdxLicense.$MIT); 11 | }); 12 | 13 | test('can parse "unknown"', () { 14 | expect(SpdxLicense.parse('unknown'), SpdxLicense.$unknown); 15 | }); 16 | 17 | test('throws on invalid SPDX license', () { 18 | expect( 19 | () => SpdxLicense.parse(invalidLicenseSource), 20 | throwsA( 21 | isA().having( 22 | (exception) => exception.message, 23 | 'message', 24 | 'Failed to parse $invalidLicenseSource as SpdxLicense.', 25 | ), 26 | ), 27 | ); 28 | }); 29 | }); 30 | 31 | group('tryParse', () { 32 | test('can parse a valid SPDX license', () { 33 | expect(SpdxLicense.tryParse('MIT'), SpdxLicense.$MIT); 34 | }); 35 | 36 | test('can parse "unknown"', () { 37 | expect(SpdxLicense.tryParse('unknown'), SpdxLicense.$unknown); 38 | }); 39 | 40 | test('returns null on invalid SPDX license', () { 41 | expect(SpdxLicense.tryParse(invalidLicenseSource), isNull); 42 | }); 43 | }); 44 | }); 45 | } 46 | -------------------------------------------------------------------------------- /e2e/test/commands/test/compilation_error/compilation_error_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:mason/mason.dart'; 2 | import 'package:mocktail/mocktail.dart'; 3 | import 'package:test/test.dart'; 4 | import 'package:universal_io/io.dart'; 5 | 6 | import '../../../../helpers/helpers.dart'; 7 | 8 | void main() { 9 | test( 10 | 'fails when there is a compilation error, but does not crash', 11 | timeout: const Timeout(Duration(minutes: 2)), 12 | withRunner((commandRunner, logger, updater, logs, progressLogs) async { 13 | final tempDirectory = Directory.systemTemp.createTempSync( 14 | 'compilation_error', 15 | ); 16 | addTearDown(() => tempDirectory.deleteSync(recursive: true)); 17 | 18 | await copyDirectory( 19 | Directory('test/commands/test/compilation_error/fixture'), 20 | tempDirectory, 21 | ); 22 | 23 | await expectSuccessfulProcessResult( 24 | 'flutter', 25 | ['pub', 'get'], 26 | workingDirectory: tempDirectory.path, 27 | ); 28 | 29 | final cwd = Directory.current; 30 | Directory.current = tempDirectory; 31 | addTearDown(() => Directory.current = cwd); 32 | 33 | final result = await commandRunner.run(['test']); 34 | 35 | expect(result, equals(ExitCode.unavailable.code)); 36 | verify( 37 | () => logger.err( 38 | any(that: contains('- test/.test_optimizer.dart')), 39 | ), 40 | ).called(1); 41 | }), 42 | ); 43 | } 44 | -------------------------------------------------------------------------------- /test/src/commands/packages/packages_test.dart: -------------------------------------------------------------------------------- 1 | // Expected usage of the plugin will need to be adjacent strings due to format 2 | // and also be longer than 80 chars. 3 | // ignore_for_file: no_adjacent_strings_in_list 4 | 5 | import 'package:mason/mason.dart'; 6 | import 'package:test/test.dart'; 7 | 8 | import '../../../helpers/command_helper.dart'; 9 | 10 | const _expectedPackagesUsage = [ 11 | 'Command for managing packages.\n' 12 | '\n' 13 | 'Usage: very_good packages [arguments]\n' 14 | '-h, --help Print this usage information.\n' 15 | '\n' 16 | 'Available subcommands:\n' 17 | ' check Perform checks in a Dart or Flutter project.\n' 18 | ' get Get packages in a Dart or Flutter project.\n' 19 | '\n' 20 | 'Run "very_good help" to see global options.', 21 | ]; 22 | 23 | void main() { 24 | group('packages', () { 25 | test( 26 | 'help', 27 | withRunner((commandRunner, logger, pubUpdater, printLogs) async { 28 | final result = await commandRunner.run(['packages', '--help']); 29 | expect(printLogs, equals(_expectedPackagesUsage)); 30 | expect(result, equals(ExitCode.success.code)); 31 | 32 | printLogs.clear(); 33 | 34 | final resultAbbr = await commandRunner.run(['packages', '-h']); 35 | expect(printLogs, equals(_expectedPackagesUsage)); 36 | expect(resultAbbr, equals(ExitCode.success.code)); 37 | }), 38 | ); 39 | }); 40 | } 41 | -------------------------------------------------------------------------------- /lib/src/commands/create/commands/flutter_app.dart: -------------------------------------------------------------------------------- 1 | import 'package:very_good_cli/src/commands/create/commands/create_subcommand.dart'; 2 | import 'package:very_good_cli/src/commands/create/templates/templates.dart'; 3 | 4 | /// {@template very_good_create_flutter_app_command} 5 | /// A [CreateSubCommand] for creating Flutter apps. 6 | /// {@endtemplate} 7 | class CreateFlutterApp extends CreateSubCommand with OrgName, MultiTemplates { 8 | /// {@macro very_good_create_flutter_app_command} 9 | CreateFlutterApp({ 10 | required super.logger, 11 | required super.generatorFromBundle, 12 | required super.generatorFromBrick, 13 | }) { 14 | argParser.addOption( 15 | 'application-id', 16 | help: 17 | 'The bundle identifier on iOS or application id on Android. ' 18 | '(defaults to .)', 19 | ); 20 | } 21 | 22 | @override 23 | String get name => 'flutter_app'; 24 | 25 | @override 26 | String get description => 'Generate a Very Good Flutter application.'; 27 | 28 | @override 29 | Map getTemplateVars() { 30 | final vars = super.getTemplateVars(); 31 | 32 | final applicationId = argResults['application-id'] as String?; 33 | if (applicationId != null) { 34 | vars['application_id'] = applicationId; 35 | } 36 | 37 | return vars; 38 | } 39 | 40 | @override 41 | final List