PatchEligibilityResult.evaluate constructor

PatchEligibilityResult.evaluate(
  1. Map<PatchChangeCategory, List<String>> categorizedFiles
)

Factory resolving eligibility from a categorizedFiles map.

Implementation

factory PatchEligibilityResult.evaluate(
    Map<PatchChangeCategory, List<String>> categorizedFiles) {
  final blockers = <String>[];
  final warnings = <String>[];

  final androidFiles =
      categorizedFiles[PatchChangeCategory.nativeAndroid] ?? [];
  if (androidFiles.isNotEmpty) {
    blockers.add(
      'Native Android changes detected (${androidFiles.length} files, e.g. ${androidFiles.first}). Native Android code requires a full store release.',
    );
  }

  final iosFiles = categorizedFiles[PatchChangeCategory.nativeIos] ?? [];
  if (iosFiles.isNotEmpty) {
    blockers.add(
      'Native iOS changes detected (${iosFiles.length} files, e.g. ${iosFiles.first}). Native iOS code requires a full store release.',
    );
  }

  final depFiles = categorizedFiles[PatchChangeCategory.dependencies] ?? [];
  if (depFiles.isNotEmpty) {
    warnings.add(
      'Dependency changes detected (${depFiles.join(", ")}). Verify that updated packages do not include new native plugin C/Kotlin/Swift bindings.',
    );
  }

  final assetFiles = categorizedFiles[PatchChangeCategory.assets] ?? [];
  if (assetFiles.isNotEmpty) {
    warnings.add(
      'Asset changes detected (${assetFiles.length} files). Note: Shorebird patch supports assets, but asset modifications should be tested thoroughly.',
    );
  }

  final unknownFiles = categorizedFiles[PatchChangeCategory.unknown] ?? [];
  if (unknownFiles.isNotEmpty) {
    warnings.add(
      'Unclassified file changes detected (${unknownFiles.length} files, e.g. ${unknownFiles.first}). Review changes before releasing patch.',
    );
  }

  final isEligible = blockers.isEmpty;

  String explanation;
  if (!isEligible) {
    explanation =
        'Patch execution blocked: Project contains native code modifications that cannot be applied via OTA patch.';
  } else if (warnings.isNotEmpty) {
    explanation =
        'Patch is eligible, but contains non-Dart files requiring review.';
  } else {
    explanation =
        'Patch is eligible: All modifications are safe Dart / generated Dart changes.';
  }

  return PatchEligibilityResult(
    isEligible: isEligible,
    categorizedFiles: categorizedFiles,
    blockers: blockers,
    warnings: warnings,
    explanation: explanation,
  );
}