func determineIcloudContainerEnvironment(desiredIcloudContainerEnvironment string, bundleIDEntitlementsMap map[string]plistutil.PlistData, exportMethod exportoptions.Method, xcodeMajorVersion int64) (string, error) {
	usesCloudKit := projectUsesCloudKit(bundleIDEntitlementsMap)
	if !usesCloudKit {
		return "", nil
	}
	if xcodeMajorVersion < 9 && exportMethod == exportoptions.MethodAppStore {
		return "", nil
	}
	if exportMethod == exportoptions.MethodAppStore {
		return "Production", nil
	}
	if desiredIcloudContainerEnvironment == "" {
		return "", fmt.Errorf("Your project uses CloudKit but \"iCloud container environment\" input not specified.\n"+
			"Export method is: %s (For app-store export method Production container environment is implied.)", exportMethod)
	}
	return desiredIcloudContainerEnvironment, nil
}
determineIcloudContainerEnvironment calculates the value of iCloudContainerEnvironment.
package main
import (
	"fmt"
	"os"
	"github.com/bitrise-io/go-utils/log"
	"github.com/bitrise-io/go-utils/sliceutil"
	"github.com/bitrise-io/go-xcode/certificateutil"
	"github.com/bitrise-io/go-xcode/export"
	"github.com/bitrise-io/go-xcode/exportoptions"
	"github.com/bitrise-io/go-xcode/plistutil"
	"github.com/bitrise-io/go-xcode/profileutil"
	"github.com/bitrise-io/go-xcode/xcodeproject/serialized"
	"github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj"
	"github.com/bitrise-io/go-xcode/xcodeproject/xcscheme"
	"github.com/bitrise-steplib/steps-xcode-archive/utils"
)
const (
	appClipProductType = "com.apple.product-type.application.on-demand-install-capable"
	manualSigningStyle = "manual"
)
type ExportOptionsGenerator struct {
	xcodeProj     *xcodeproj.XcodeProj
	scheme        *xcscheme.Scheme
	configuration string
	certificateProvider CodesignIdentityProvider
	profileProvider     ProvisioningProfileProvider
	targetInfoProvider  TargetInfoProvider
	logger              log.Logger
}
func NewExportOptionsGenerator(xcodeProj *xcodeproj.XcodeProj, scheme *xcscheme.Scheme, configuration string, logger log.Logger) ExportOptionsGenerator {
	g := ExportOptionsGenerator{
		xcodeProj:     xcodeProj,
		scheme:        scheme,
		configuration: configuration,
	}
	g.certificateProvider = LocalCodesignIdentityProvider{}
	g.profileProvider = LocalProvisioningProfileProvider{}
	g.targetInfoProvider = XcodebuildTargetInfoProvider{xcodeProj: xcodeProj}
	g.logger = logger
	return g
}
func (g ExportOptionsGenerator) GenerateApplicationExportOptions(exportMethod exportoptions.Method, containerEnvironment string, teamID string, uploadBitcode bool, compileBitcode bool, xcodeManaged bool,
	xcodeMajorVersion int64) (exportoptions.ExportOptions, error) {
	mainTarget, err := archivableApplicationTarget(g.xcodeProj, g.scheme)
	if err != nil {
		return nil, err
	}
	dependentTargets := dependentApplicationBundleTargetsOf(exportMethod, *mainTarget)
	targets := append([]xcodeproj.Target{*mainTarget}, dependentTargets...)
	var mainTargetBundleID string
	entitlementsByBundleID := map[string]plistutil.PlistData{}
	for i, target := range targets {
		bundleID, err := g.targetInfoProvider.TargetBundleID(target.Name, g.configuration)
		if err != nil {
			return nil, fmt.Errorf("failed to get target (%s) bundle id: %s", target.Name, err)
		}
		entitlements, err := g.targetInfoProvider.TargetCodeSignEntitlements(target.Name, g.configuration)
		if err != nil && !serialized.IsKeyNotFoundError(err) {
			return nil, fmt.Errorf("failed to get target (%s) bundle id: %s", target.Name, err)
		}
		entitlementsByBundleID[bundleID] = plistutil.PlistData(entitlements)
		if i == 0 {
			mainTargetBundleID = bundleID
		}
	}
	return g.generateExportOptions(exportMethod, containerEnvironment, teamID, uploadBitcode, compileBitcode,
		xcodeManaged, entitlementsByBundleID, xcodeMajorVersion, mainTargetBundleID)
}
type TargetInfoProvider interface {
	TargetBundleID(target, configuration string) (string, error)
	TargetCodeSignEntitlements(target, configuration string) (serialized.Object, error)
}
type XcodebuildTargetInfoProvider struct {
	xcodeProj *xcodeproj.XcodeProj
}
func (b XcodebuildTargetInfoProvider) TargetBundleID(target, configuration string) (string, error) {
	return b.xcodeProj.TargetBundleID(target, configuration)
}
func (b XcodebuildTargetInfoProvider) TargetCodeSignEntitlements(target, configuration string) (serialized.Object, error) {
	return b.xcodeProj.TargetCodeSignEntitlements(target, configuration)
}
func archivableApplicationTarget(xcodeProj *xcodeproj.XcodeProj, scheme *xcscheme.Scheme) (*xcodeproj.Target, error) {
	archiveEntry, ok := scheme.AppBuildActionEntry()
	if !ok {
		return nil, fmt.Errorf("archivable entry not found in project: %s for scheme: %s", xcodeProj.Path, scheme.Name)
	}
	mainTarget, ok := xcodeProj.Proj.Target(archiveEntry.BuildableReference.BlueprintIdentifier)
	if !ok {
		return nil, fmt.Errorf("target not found: %s", archiveEntry.BuildableReference.BlueprintIdentifier)
	}
	return &mainTarget, nil
}
func dependentApplicationBundleTargetsOf(exportMethod exportoptions.Method, applicationtarget xcodeproj.Target) (dependentTargets []xcodeproj.Target) {
	for _, target := range applicationtarget.DependentExecutableProductTargets() {
		if exportMethod != exportoptions.MethodAppStore &&
			target.ProductType == appClipProductType {
			continue
		}
		dependentTargets = append(dependentTargets, target)
	}
	return
}
func projectUsesCloudKit(bundleIDEntitlementsMap map[string]plistutil.PlistData) bool {
	for _, entitlements := range bundleIDEntitlementsMap {
		if entitlements == nil {
			continue
		}
		services, ok := entitlements.GetStringArray("com.apple.developer.icloud-services")
		if !ok {
			continue
		}
		if sliceutil.IsStringInSlice("CloudKit", services) || sliceutil.IsStringInSlice("CloudDocuments", services) {
			return true
		}
	}
	return false
}