execute method

  1. @override
Future<int> execute(
  1. List<String> args
)
override

Executes the command with the provided arguments. Returns an integer exit code (0 for success).

Implementation

@override
Future<int> execute(List<String> args) async {
  final parser = buildArgParser();
  ArgResults results;

  try {
    results = parser.parse(args);
  } catch (e) {
    _output.error('Invalid arguments for build command: $e');
    _output.info('\nUsage:');
    _output.info(parser.usage);
    return 1;
  }

  final projectPath = results['path'] as String;
  final pubspecFile = File('$projectPath/pubspec.yaml');
  if (!pubspecFile.existsSync()) {
    _output.error(
        'Flutter project not found at path "$projectPath". Missing pubspec.yaml.');
    return 1;
  }

  final platformStr = results['platform'] as String;
  final platform = BuildPlatform.parse(platformStr);

  BuildFormat format;
  if (results.wasParsed('format')) {
    format = BuildFormat.parse(results['format'] as String);
  } else {
    format = BuildFormat.defaultForPlatform(platform);
  }

  try {
    format.validateForPlatform(platform);
  } on ValidationException catch (e) {
    _output.error('Format validation failed: ${e.message}');
    return 1;
  }

  final isDryRun = results['dry-run'] as bool;
  final isDebug = results['debug'] as bool;
  final isRelease = isDebug ? false : (results['release'] as bool);

  String? versionName = results['version'] as String?;
  int? buildNumber;
  if (results.wasParsed('build-number')) {
    buildNumber = int.tryParse(results['build-number'] as String);
    if (buildNumber == null || buildNumber <= 0) {
      _output.error('Build number must be a positive integer.');
      return 1;
    }
  }

  // Attempt reading project version if explicit overrides not provided
  if (versionName == null || buildNumber == null) {
    try {
      final currentVer = _versionManager.getCurrentVersion(projectPath);
      versionName ??= currentVer.versionName;
      buildNumber ??= currentVer.buildNumber;
    } catch (_) {
      // Fallback silently if pubspec parsing fails
    }
  }

  final envArg =
      results['environment'] as String? ?? results['env'] as String?;
  final rawDefines =
      (results['dart-define'] as List<String>?) ?? const <String>[];
  final parsedDefines = EnvironmentResolver.parseDartDefines(rawDefines);

  final resolver = const EnvironmentResolver();
  final envConfig = resolver.resolve(
    cliEnvironment: envArg,
    cliFlavor: results['flavor'] as String?,
    cliDartDefines: parsedDefines,
    envVars: Platform.environment,
  );

  final extraArgs = <String>[];
  for (final entry in envConfig.dartDefines.entries) {
    extraArgs.addAll(['--dart-define', '${entry.key}=${entry.value}']);
  }

  final context = BuildContext(
    projectPath: projectPath,
    platform: platform,
    format: format,
    versionName: versionName,
    buildNumber: buildNumber,
    dryRun: isDryRun,
    isReleaseMode: isRelease,
    flavor: envConfig.flavor,
    target: results['target'] as String?,
    extraArgs: extraArgs,
  );

  _output.info('Flutter Build Automation');
  _output.info('Platform: $platform');
  _output.info('Format:   $format');
  if (versionName != null && buildNumber != null) {
    _output.info('Version:  $versionName+$buildNumber');
  }

  final buildResults = await _buildManager.executeBuild(context);
  final allPassed = buildResults.every((r) => r.success);

  _output.info('\n--- BUILD SUMMARY ---');
  for (final res in buildResults) {
    if (res.success) {
      _output.success('${res.platform} (${res.format}): SUCCESS');
      if (res.artifactPath != null) {
        _output.info('  Artifact: ${res.artifactPath}');
      }
    } else {
      _output.error('${res.platform} (${res.format}): FAILED');
      for (final err in res.errors) {
        _output.error('  • $err');
      }
    }
  }

  return allPassed ? 0 : 1;
}