run method

  1. @override
Future<void> run()
override

Runs this command.

The return value is wrapped in a Future if necessary and returned by CommandRunner.runCommand.

Implementation

@override
Future<void> run() async {
  buildStartTime = DateTime.now();

  // 1. Initialize Services
  config = ConfigService(projectDir);
  whiteLabel = WhiteLabelService(projectDir: projectDir, config: config);
  cleanup = CleanupService(projectDir: projectDir, config: config);

  final client = argResults?['client'] as String;
  final isTest = argResults?['test'] as bool;
  final enableSlack = argResults?['slack'] as bool;

  String? version;
  String? errorMessage;

  if (enableSlack) {
    slackService =
        await _initializeSlackService(argResults!['slack-channel']);
  }

  try {
    // -----------------------------------------------------------------------
    // PHASE 1: VALIDATION & SETUP
    // -----------------------------------------------------------------------
    Logger.phase('1: Validation & Setup');

    version = await _step('Reading pubspec version', () async {
      return await config.getPubspecVersion();
    });

    await _notifyBuildStep('Whitelabel Started', client, '', 'started',
        additionalInfo: 'Version: $version');

    final envFileName = isTest ? '.env_test' : '.env';
    final envFile = File('$projectDir/clients/$client/$envFileName');

    if (!envFile.existsSync()) {
      throw BuildException(
        'Environment file missing for client "$client": $envFileName',
        fix: 'Create the missing file at "${envFile.path}".',
      );
    }

    final envVars = await config.parseEnvFile(envFile);
    // await config.copyToRootEnv(envFile);

    final appName = envVars['APP_NAME_PROD'];
    final bundleId = envVars['BUNDLE_ID'];
    final clientAssetsPath = envVars['ASSETS_PATH'];
    final appIconPath = envVars['APP_ICON_PATH'];

    _validateEnvVariables(client, envFileName, {
      'APP_NAME_PROD': appName,
      'BUNDLE_ID': bundleId,
      'ASSETS_PATH': clientAssetsPath,
      'APP_ICON_PATH': appIconPath,
    });

    appNameForCleanup = appName;
    Logger.success('Validated configuration for "$client" ($version)');

    // -----------------------------------------------------------------------
    // PHASE 2: PROJECT CONFIGURATION
    // -----------------------------------------------------------------------
    Logger.phase('2: Project Configuration');
    await _notifyBuildStep('Project Configuration', client, '', 'started');

    /* await _step('Creating backups', () async {
      await config.createBackup(File('$projectDir/pubspec.yaml'));
      await config
          .createBackup(File('$projectDir/flutter_launcher_icons.yaml'));

      final pbxprojFile =
          File('$projectDir/ios/Runner.xcodeproj/project.pbxproj');
      if (pbxprojFile.existsSync()) {
        await config.createBackup(pbxprojFile);
      }
    }); */

    await _step('Updating asset and launcher configs', () async {
      await config.updateYamlValue(
          File('$projectDir/flutter_launcher_icons.yaml'),
          ['flutter_launcher_icons', 'image_path'],
          appIconPath!);

      await config.updateYamlValue(File('$projectDir/pubspec.yaml'),
          ['splash_master', 'image'], appIconPath);
    });

    await _step('Syncing client branding assets & fonts', () async {
      await whiteLabel.syncBrandingAssets(client, clientAssetsPath!);
      await whiteLabel.applyClientFonts(clientAssetsPath);
      await config.updatePubspecAssets(
          clientAssetPath: client,
          requiredExtraAssets: ['clients/$client/.env']);
    });

    Logger.success('Project dynamic assets configured successfully');

    // -----------------------------------------------------------------------
    // PHASE 3: RUNNING EXTERNAL TOOLS
    // -----------------------------------------------------------------------
    Logger.phase('3: Running Tools & Generating Assets');

    await _step('Resolving dependencies (pub get)',
        () => runShell('flutter pub get'));

    await _step(
        'Updating Bundle ID ($bundleId)',
        () => runShell(
            'dart run rename setBundleId --targets ios,android --value "$bundleId"'));

    await _step(
        'Updating App Name ($appName)',
        () => runShell(
            'dart run rename setAppName --targets ios,android --value "$appName"'));

    await _step('Generating Launcher Icons',
        () => runShell('dart run flutter_launcher_icons'));

    await _step('Generating Native Splash Screens',
        () => runShell('dart run splash_master create'));

    await _step('Cleaning Android icon cache',
        () => whiteLabel.cleanAndroidIconCache());

    Logger.success('Whitelabeling process completed successfully!');
  } catch (e, s) {
    if (e is BuildException) {
      errorMessage = e.message;
      Logger.error(e.message,
          cause: e.fix, stackTrace: e.originalStackTrace ?? s);
    } else {
      errorMessage = e.toString();
      Logger.error('An unexpected error occurred during whitelabeling.',
          cause: e, stackTrace: s);
    }

    await _notifyBuildStep('Whitelabel Process', client, '', 'failed',
        errorMessage: errorMessage);
    rethrow;
  } finally {
    // -----------------------------------------------------------------------
    // FINAL PHASE: CLEANUP (ALWAYS RUNS)
    // -----------------------------------------------------------------------
    // Logger.phase('🧹 Final Phase: Cleaning Up Project State');

    /* try {
      await cleanup.performFullCleanup(
        appNameForCleanup: appNameForCleanup,
        fontsWereChanged: true,
      );
      Logger.info('Project restored to default state.');
    } catch (cleanupError) {
      Logger.warning('Cleanup encountered an issue: $cleanupError');
    } */
  }
}