diff --git a/docs/cli/index.mdx b/docs/cli/index.mdx index aa46275..a8c9896 100644 --- a/docs/cli/index.mdx +++ b/docs/cli/index.mdx @@ -45,3 +45,6 @@ All CLI commands have global flags that can be used to modify the behavior of th - `--help` - Display help information for the command. - `--verbose` - Display verbose output for the command, such as API calls and debug information. +- `--token` - Use API token for CLI Auth. +- `--project` - Set the Project ID used by this command. Defaults to what was previously linked using `globe link`. +- `--org` - Set the Organization ID used by this command. Defaults to what was previously linked using `globe link`. diff --git a/packages/globe_cli/lib/src/utils/api.dart b/packages/globe_cli/lib/src/utils/api.dart index e8f16a1..9b6d2e7 100644 --- a/packages/globe_cli/lib/src/utils/api.dart +++ b/packages/globe_cli/lib/src/utils/api.dart @@ -604,8 +604,8 @@ class FrameworkPresetOptions { { 'id': final String id, 'name': final String name, - 'buildCommand': final String buildCommand, 'entrypoint': final String entrypoint, + 'buildCommand': final String? buildCommand, } => FrameworkPresetOptions( id: id, @@ -628,7 +628,7 @@ class FrameworkPresetOptions { final String id; final String name; - final String buildCommand; + final String? buildCommand; final String entrypoint; } diff --git a/packages/globe_cli/lib/src/utils/prompts.dart b/packages/globe_cli/lib/src/utils/prompts.dart index 4f68751..c092249 100644 --- a/packages/globe_cli/lib/src/utils/prompts.dart +++ b/packages/globe_cli/lib/src/utils/prompts.dart @@ -29,13 +29,6 @@ Future linkProject({ )) { exitOverride(0); } - } else { - if (!logger.confirm( - '❓ Link this project to Globe ${cyan.wrap('"${Directory.current.path}"')}?', - defaultValue: true, - )) { - exitOverride(0); - } } try { @@ -184,52 +177,53 @@ Future selectProject( defaultValue: parsed.name, ); - final discoveredPreset = await api.discoverPreset(pubspecContent); + final (discoveredPreset, entryPoints) = await ( + api.discoverPreset(pubspecContent), + findMainEntryPoint(rootDirectoryDir) + ).wait; String? buildCommand; String? entrypoint; - if (discoveredPreset != null) { - final useDefaultSettings = logger.confirm( - '❓ Detected "${discoveredPreset.name}" preset, would you like to use the default build settings?', - defaultValue: true, - ); - - if (!useDefaultSettings) { - buildCommand = logger.prompt( - '❓ Enter a build command:', - defaultValue: discoveredPreset.buildCommand, - ); + if (entryPoints.isNotEmpty) { + entrypoint = switch (entryPoints.length) { + 1 => entryPoints.first, + > 1 => logger.chooseOne( + '❓ Choose Dart entrypoint file:', + choices: entryPoints, + ), + _ => null, + }; + logger.detail('Using entry point in `$entrypoint`'); + } - entrypoint = logger.prompt( - '❓ Enter a Dart entrypoint file:', - defaultValue: discoveredPreset.entrypoint, - ); + if (discoveredPreset != null) { + logger.detail('Detected "${discoveredPreset.name}" preset'); + if (discoveredPreset.buildCommand != null) { + buildCommand = discoveredPreset.buildCommand; + logger.detail('Using preset build command: `$buildCommand`'); + } - // If it's the same as the preset, don't send it. - buildCommand = - buildCommand == discoveredPreset.buildCommand ? null : buildCommand; - entrypoint = - entrypoint == discoveredPreset.entrypoint ? null : entrypoint; + if (discoveredPreset.entrypoint.isNotEmpty && entrypoint == null) { + entrypoint = discoveredPreset.entrypoint; + logger.detail('Using preset entry point: `$entrypoint`'); } - } else { + } + + // Check if project has build_runner, if not skip. + const buildRunner = 'build_runner'; + if (parsed.devDependencies.keys.any((p) => p == buildRunner) || + parsed.dependencies.keys.any((p) => p == buildRunner)) { if (logger.confirm('❓ Would you like to run a custom build command?')) { buildCommand = logger.prompt( '❓ Enter a build command:', + defaultValue: buildCommand, ); } - - entrypoint = logger.prompt( - '❓ Enter a Dart entrypoint file:', - defaultValue: 'lib/main.dart', - ); } final envVarFile = File( - p.join( - rootDirectoryDir.absolute.path, - '.env', - ), + p.join(rootDirectoryDir.absolute.path, '.env'), ); Map? environmentVariables; @@ -392,3 +386,28 @@ Future> selectProjects( return selections.map((e) => projectsBySlug[e]!).toList(); } + +/// Asynchronously finds the main entry point of a Dart project. +Future> findMainEntryPoint(Directory rootDir) async { + final dartFiles = rootDir.list(recursive: true).where((entity) { + if (entity is! File) return false; + + final relativePath = p.relative(entity.path, from: rootDir.path); + final segments = p.split(relativePath); + + return p.extension(entity.path) == '.dart' && + !segments.contains('.dart_tool') && + !segments.contains('test') && + !p.basename(entity.path).startsWith('test_'); + }); + final entryPoints = []; + + await for (final (entity as File) in dartFiles) { + final contents = await entity.readAsString(); + if (RegExp(r'\bmain\s*\([^)]*\)').hasMatch(contents)) { + entryPoints.add(p.relative(entity.path)); + } + } + + return entryPoints; +}