inspect method

Future<CIDoctorReport> inspect(
  1. String projectPath
)

Run comprehensive CI health inspection on projectPath.

Implementation

Future<CIDoctorReport> inspect(String projectPath) async {
  final checks = <CIDoctorCheck>[];

  // 1. Environment Check
  final ctx = _ciEnv.createContext();
  checks.add(CIDoctorCheck(
    category: 'Environment',
    title: 'CI Environment',
    status: ctx.isCi ? 'Configured' : 'Passed',
    details: 'Provider: ${ctx.providerName} (isCi: ${ctx.isCi})',
  ));

  // 2. Workflows Check
  final workflowsDir = Directory('$projectPath/.github/workflows');
  final hasWorkflowsDir = await workflowsDir.exists();
  if (hasWorkflowsDir) {
    checks.add(const CIDoctorCheck(
      category: 'Workflows',
      title: 'Workflows Directory',
      status: 'Configured',
      details: 'Found .github/workflows directory',
    ));

    for (final name in [
      'flutter_verify.yml',
      'flutter_release.yml',
      'flutter_patch.yml'
    ]) {
      final file = File('${workflowsDir.path}/$name');
      final exists = await file.exists();
      checks.add(CIDoctorCheck(
        category: 'Workflows',
        title: 'Workflow: $name',
        status: exists ? 'Configured' : 'Missing',
        details: exists
            ? 'File exists'
            : 'File missing (run "flutter_setup ci init")',
      ));
    }
  } else {
    checks.add(const CIDoctorCheck(
      category: 'Workflows',
      title: 'Workflows Directory',
      status: 'Missing',
      details: 'No .github/workflows directory found',
    ));
  }

  // 3. Fastlane Check
  final fastlaneAvailable = await _fastlaneRunner.isFastlaneAvailable();
  checks.add(CIDoctorCheck(
    category: 'Deployment',
    title: 'Fastlane CLI Tool',
    status: fastlaneAvailable ? 'Configured' : 'Warning',
    details: fastlaneAvailable
        ? 'Fastlane executable found on PATH'
        : 'Fastlane not installed on local machine (required for local store deployment)',
  ));

  final androidFastfile = File('$projectPath/android/fastlane/Fastfile');
  final iosFastfile = File('$projectPath/ios/fastlane/Fastfile');
  final rootFastfile = File('$projectPath/fastlane/Fastfile');

  final hasFastfile = await androidFastfile.exists() ||
      await iosFastfile.exists() ||
      await rootFastfile.exists();
  checks.add(CIDoctorCheck(
    category: 'Deployment',
    title: 'Fastlane Configuration',
    status: hasFastfile ? 'Configured' : 'Warning',
    details:
        hasFastfile ? 'Fastfile detected' : 'No Fastfile found in project',
  ));

  // 4. Shorebird Check
  final shorebirdAvailable = await _shorebirdClient.isShorebirdAvailable();
  checks.add(CIDoctorCheck(
    category: 'Shorebird',
    title: 'Shorebird CLI Tool',
    status: shorebirdAvailable ? 'Configured' : 'Warning',
    details: shorebirdAvailable
        ? 'Shorebird executable found on PATH'
        : 'Shorebird not installed (required for OTA patches)',
  ));

  final hasShorebirdYaml = _shorebirdClient.isProjectConfigured(projectPath);
  checks.add(CIDoctorCheck(
    category: 'Shorebird',
    title: 'Shorebird Project Configuration',
    status: hasShorebirdYaml ? 'Configured' : 'Warning',
    details: hasShorebirdYaml
        ? 'shorebird.yaml detected'
        : 'shorebird.yaml not found',
  ));

  // 5. Secret Configuration Status (Never exposes values!)
  final env = ctx.environment;
  for (final secretKey in [
    'GOOGLE_PLAY_SERVICE_ACCOUNT',
    'APP_STORE_CONNECT_API_KEY',
    'SHOREBIRD_TOKEN',
    'KEYSTORE_PASSWORD',
  ]) {
    final isPresent =
        env.containsKey(secretKey) && env[secretKey]!.isNotEmpty;
    checks.add(CIDoctorCheck(
      category: 'Secrets',
      title: 'Secret: $secretKey',
      status: isPresent ? 'Configured' : 'Missing',
      details: isPresent
          ? 'Configured in environment'
          : 'Not set in current environment (Required in CI GitHub Secrets)',
    ));
  }

  final isHealthy = checks.every((c) => c.status != 'Failed');
  return CIDoctorReport(checks: checks, isHealthy: isHealthy);
}