eas-cli
Version:
EAS command line tool
152 lines (151 loc) • 9.27 kB
JavaScript
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;
}
;