UNPKG

eas-cli

Version:
152 lines (151 loc) 9.27 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isWildcardBundleIdentifier = exports.warnIfBundleIdentifierDefinedInAppConfigForBareWorkflowProject = exports.isBundleIdentifierValid = exports.getBundleIdentifierAsync = exports.AmbiguousBundleIdentifierError = exports.ensureBundleIdentifierIsDefinedForManagedProjectAsync = exports.INVALID_BUNDLE_IDENTIFIER_MESSAGE = void 0; const tslib_1 = require("tslib"); const config_1 = require("@expo/config"); const config_plugins_1 = require("@expo/config-plugins"); const eas_build_job_1 = require("@expo/eas-build-job"); const assert_1 = tslib_1.__importDefault(require("assert")); const chalk_1 = tslib_1.__importDefault(require("chalk")); const fs_extra_1 = tslib_1.__importDefault(require("fs-extra")); const appJson_1 = require("../../build/utils/appJson"); const env_1 = tslib_1.__importDefault(require("../../env")); const log_1 = tslib_1.__importStar(require("../../log")); const prompts_1 = require("../../prompts"); const projectUtils_1 = require("../projectUtils"); const workflow_1 = require("../workflow"); exports.INVALID_BUNDLE_IDENTIFIER_MESSAGE = `Invalid format of iOS bundle identifier. Only alphanumeric characters, '.' and '-' are allowed, and each '.' must be followed by a letter.`; async function ensureBundleIdentifierIsDefinedForManagedProjectAsync({ graphqlClient, projectDir, projectId, exp, vcsClient, nonInteractive, }) { const workflow = await (0, workflow_1.resolveWorkflowAsync)(projectDir, eas_build_job_1.Platform.IOS, vcsClient); (0, assert_1.default)(workflow === eas_build_job_1.Workflow.MANAGED, 'This function should be called only for managed projects'); try { return await getBundleIdentifierAsync(projectDir, exp, vcsClient); } catch { return await configureBundleIdentifierAsync({ graphqlClient, projectDir, exp, projectId, nonInteractive, }); } } exports.ensureBundleIdentifierIsDefinedForManagedProjectAsync = ensureBundleIdentifierIsDefinedForManagedProjectAsync; class AmbiguousBundleIdentifierError extends Error { constructor(message) { super(message ?? 'Could not resolve bundle identifier.'); } } exports.AmbiguousBundleIdentifierError = AmbiguousBundleIdentifierError; async function getBundleIdentifierAsync(projectDir, exp, vcsClient, xcodeContext) { if (env_1.default.overrideIosBundleIdentifier) { return env_1.default.overrideIosBundleIdentifier; } const workflow = await (0, workflow_1.resolveWorkflowAsync)(projectDir, eas_build_job_1.Platform.IOS, vcsClient); if (workflow === eas_build_job_1.Workflow.GENERIC) { warnIfBundleIdentifierDefinedInAppConfigForBareWorkflowProject(projectDir, exp); const xcodeProject = config_plugins_1.IOSConfig.XcodeUtils.getPbxproj(projectDir); const isMultiScheme = config_plugins_1.IOSConfig.BuildScheme.getSchemesFromXcodeproj(projectDir).length > 1; const isMultiTarget = config_plugins_1.IOSConfig.Target.getNativeTargets(xcodeProject).filter(([, target]) => config_plugins_1.IOSConfig.Target.isTargetOfType(target, config_plugins_1.IOSConfig.Target.TargetType.APPLICATION)).length > 1; if (!xcodeContext && isMultiScheme && isMultiTarget) { throw new AmbiguousBundleIdentifierError("Multiple schemes and targets found in Xcode project, bundle identifier couldn't be resolved."); } const bundleIdentifier = config_plugins_1.IOSConfig.BundleIdentifier.getBundleIdentifierFromPbxproj(projectDir, xcodeContext ?? {}); const buildConfigurationDesc = xcodeContext?.targetName && xcodeContext?.buildConfiguration ? ` (target = ${xcodeContext.targetName}, build configuration = ${xcodeContext.buildConfiguration})` : ''; (0, assert_1.default)(bundleIdentifier, `Could not read bundle identifier from Xcode project${buildConfigurationDesc}.`); if (!isBundleIdentifierValid(bundleIdentifier)) { throw new Error(`Bundle identifier "${bundleIdentifier}" is not valid${buildConfigurationDesc}. Open the project in Xcode to fix it.`); } return bundleIdentifier; } else { // TODO: the following asserts are only temporary until we support app extensions in managed projects (0, assert_1.default)(!xcodeContext?.targetName || xcodeContext?.targetName === config_plugins_1.IOSConfig.XcodeUtils.sanitizedName(exp.name), 'targetName cannot be set to an arbitrary value for managed projects.'); (0, assert_1.default)(!xcodeContext?.buildConfiguration, 'buildConfiguration cannot be passed for managed projects.'); const bundleIdentifier = config_plugins_1.IOSConfig.BundleIdentifier.getBundleIdentifier(exp); if (!bundleIdentifier || !isBundleIdentifierValid(bundleIdentifier)) { if (bundleIdentifier) { log_1.default.warn(exports.INVALID_BUNDLE_IDENTIFIER_MESSAGE); } throw new Error(`Specify "ios.bundleIdentifier" in ${(0, projectUtils_1.getProjectConfigDescription)(projectDir)} and run this command again.`); } else { return bundleIdentifier; } } } exports.getBundleIdentifierAsync = getBundleIdentifierAsync; async function configureBundleIdentifierAsync({ graphqlClient, projectDir, projectId, exp, nonInteractive, }) { if (nonInteractive) { throw new Error(`The "ios.bundleIdentifier" is required to be set in app config when running in non-interactive mode. ${(0, log_1.learnMore)('https://docs.expo.dev/versions/latest/config/app/#bundleidentifier')}`); } const paths = (0, config_1.getConfigFilePaths)(projectDir); // we can't automatically update app.config.js if (paths.dynamicConfigPath) { throw new Error(`"ios.bundleIdentifier" is not defined in your app.config.js and we can't update this file programmatically. Add the value on your own and run this command again.`); } (0, assert_1.default)(paths.staticConfigPath, 'app.json must exist'); log_1.default.addNewLineIfNone(); log_1.default.log(`${chalk_1.default.bold(`📝 iOS Bundle Identifier`)} ${chalk_1.default.dim((0, log_1.learnMore)('https://expo.fyi/bundle-identifier'))}`); const suggestedBundleIdentifier = await getSuggestedBundleIdentifierAsync(graphqlClient, exp, projectId); const { bundleIdentifier } = await (0, prompts_1.promptAsync)({ name: 'bundleIdentifier', type: 'text', message: `What would you like your iOS bundle identifier to be?`, initial: suggestedBundleIdentifier, validate: value => (isBundleIdentifierValid(value) ? true : exports.INVALID_BUNDLE_IDENTIFIER_MESSAGE), }); const rawStaticConfig = (0, appJson_1.readAppJson)(paths.staticConfigPath); rawStaticConfig.expo = { ...rawStaticConfig.expo, ios: { ...rawStaticConfig.expo?.ios, bundleIdentifier }, }; await fs_extra_1.default.writeJson(paths.staticConfigPath, rawStaticConfig, { spaces: 2 }); exp.ios = { ...exp.ios, bundleIdentifier }; return bundleIdentifier; } function isBundleIdentifierValid(bundleIdentifier) { return /^[a-zA-Z0-9-.]+$/.test(bundleIdentifier); } exports.isBundleIdentifierValid = isBundleIdentifierValid; let warnPrinted = false; function warnIfBundleIdentifierDefinedInAppConfigForBareWorkflowProject(projectDir, exp) { if (config_plugins_1.IOSConfig.BundleIdentifier.getBundleIdentifier(exp) && !warnPrinted) { log_1.default.warn(`Specified value for "ios.bundleIdentifier" in ${(0, projectUtils_1.getProjectConfigDescription)(projectDir)} is ignored because an ${chalk_1.default.bold('ios')} directory was detected in the project.\n` + 'EAS Build will use the value found in the native code.'); warnPrinted = true; } } exports.warnIfBundleIdentifierDefinedInAppConfigForBareWorkflowProject = warnIfBundleIdentifierDefinedInAppConfigForBareWorkflowProject; function isWildcardBundleIdentifier(bundleIdentifier) { const wildcardRegex = /^[A-Za-z0-9.-]+\*$/; return wildcardRegex.test(bundleIdentifier); } exports.isWildcardBundleIdentifier = isWildcardBundleIdentifier; async function getSuggestedBundleIdentifierAsync(graphqlClient, exp, projectId) { // Attempt to use the android package name first since it's convenient to have them aligned. const maybeAndroidPackage = config_plugins_1.AndroidConfig.Package.getPackage(exp); if (maybeAndroidPackage && isBundleIdentifierValid(maybeAndroidPackage)) { return maybeAndroidPackage; } else { // the only callsite is heavily interactive const account = await (0, projectUtils_1.getOwnerAccountForProjectIdAsync)(graphqlClient, projectId); let possibleId; // It's common to use dashes in your node project name, strip them from the suggested package name. if (account.name) { possibleId = `com.${account.name}.${exp.slug}`.split('-').join(''); } else { possibleId = `com.${exp.slug}`.split('-').join(''); } if (isBundleIdentifierValid(possibleId)) { return possibleId; } } return undefined; }