addBuildToGroups method

  1. @override
Future<void> addBuildToGroups({
  1. required String appId,
  2. required String buildId,
  3. required List<String> names,
  4. required bool isInternal,
})
override

Adds an exact build to the named internal or external TestFlight groups.

Implementation

@override
Future<void> addBuildToGroups({
  required String appId,
  required String buildId,
  required List<String> names,
  required bool isInternal,
}) async {
  if (names.isEmpty) return;
  final query = Uri(
    queryParameters: <String, String>{'filter[app]': appId, 'limit': '200'},
  ).query;
  final groups = (await _collection(
    '/v1/betaGroups?$query',
  )).map(_genericResource).toList();
  for (final name in names) {
    final group = groups
        .where(
          (item) => item.attributes['name'] == name,
        )
        .firstOrNull;
    if (group == null) {
      throw SmfError(
        'TestFlight group "$name" was not found for this app.',
        SmfErrorCode.betaGroupNotFound,
      );
    }
    final isInternalGroup = group.attributes['isInternalGroup'];
    SmfError.check(
      isInternalGroup is bool,
      'App Store Connect did not identify the audience for TestFlight group '
      '"$name".',
      SmfErrorCode.betaGroupInvalid,
    );
    SmfError.check(
      isInternalGroup == isInternal,
      'TestFlight group "$name" does not match the configured '
      '${isInternal ? 'internal-testing' : 'external-testing'} target.',
      SmfErrorCode.betaGroupAudienceMismatch,
    );
    final linked = (await _collection(
      '/v1/betaGroups/${group.id}/relationships/builds?limit=200',
    )).map(_mapResourceIdentifier);
    if (linked.any((item) => item.id == buildId)) {
      continue;
    }
    await _request(
      'POST',
      '/v1/betaGroups/${group.id}/relationships/builds',
      body: <String, Object?>{
        'data': <Object?>[
          <String, Object?>{'type': 'builds', 'id': buildId},
        ],
      },
    );
  }
}