Skip to content
This repository has been archived by the owner on Jan 18, 2024. It is now read-only.

Commit

Permalink
[expo-cli][config] EAS Build tweaks (#2485)
Browse files Browse the repository at this point in the history
* [expo-cli] initialize git repo if it doesn't exist

* [config] improve reading bundle identfier from xcode project

* [expo-cli] address code review suggestions

* [expo-cli] address pr feedback
  • Loading branch information
dsokal authored Aug 25, 2020
1 parent 7cd8e3f commit ffaf58e
Show file tree
Hide file tree
Showing 8 changed files with 1,136 additions and 58 deletions.
71 changes: 40 additions & 31 deletions packages/config/src/ios/BundleIdentifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,8 @@ import { ExpoConfig } from '../Config.types';
import { InfoPlist } from './IosConfig.types';
import {
ConfigurationSectionEntry,
Pbxproj,
getXCBuildConfigurationSection,
getXCConfigurationLists,
isBuildConfig,
isNotComment,
isNotTestHost,
findFirstNativeTarget,
getBuildConfigurationForId,
} from './utils/Xcodeproj';

function getBundleIdentifier(config: ExpoConfig): string | null {
Expand Down Expand Up @@ -56,10 +52,29 @@ function getBundleIdentifierFromPbxproj(projectRoot: string): string | null {
}
const project = Project(pbxprojPath);
project.parseSync();
for (const [, item] of getBuildConfigurationSectionEntires(project)) {
const bundleIdentifier = item.buildSettings.PRODUCT_BUNDLE_IDENTIFIER;
if (bundleIdentifier) {
return bundleIdentifier[0] === '"' ? bundleIdentifier.slice(1, -1) : bundleIdentifier;

const nativeTarget = findFirstNativeTarget(project);

for (const [, item] of getBuildConfigurationForId(project, nativeTarget.buildConfigurationList)) {
const bundleIdentifierRaw = item.buildSettings.PRODUCT_BUNDLE_IDENTIFIER;
if (bundleIdentifierRaw) {
const bundleIdentifier =
bundleIdentifierRaw[0] === '"' ? bundleIdentifierRaw.slice(1, -1) : bundleIdentifierRaw;
// it's possible to use interpolation for the bundle identifier
// the most common case is when the last part of the id is set to `$(PRODUCT_NAME:rfc1034identifier)`
// in this case, PRODUCT_NAME should be replaced with its value
// the `rfc1034identifier` modifier replaces all non-alphanumeric characters with dashes
const bundleIdentifierParts = bundleIdentifier.split('.');
if (
bundleIdentifierParts[bundleIdentifierParts.length - 1] ===
'$(PRODUCT_NAME:rfc1034identifier)' &&
item.buildSettings.PRODUCT_NAME
) {
bundleIdentifierParts[
bundleIdentifierParts.length - 1
] = item.buildSettings.PRODUCT_NAME.replace(/[^a-zA-Z0-9]/g, '-');
}
return bundleIdentifierParts.join('.');
}
}
return null;
Expand All @@ -79,32 +94,26 @@ function updateBundleIdentifierForPbxproj(
): void {
const project = Project(pbxprojPath);
project.parseSync();
getBuildConfigurationSectionEntires(project).forEach(([, item]: ConfigurationSectionEntry) => {
if (item.buildSettings.PRODUCT_BUNDLE_IDENTIFIER === bundleIdentifier) {
return;
}

item.buildSettings.PRODUCT_BUNDLE_IDENTIFIER = `"${bundleIdentifier}"`;
const nativeTarget = findFirstNativeTarget(project);

if (updateProductName) {
const productName = bundleIdentifier.split('.').pop();
if (!productName?.includes('$')) {
item.buildSettings.PRODUCT_NAME = productName;
getBuildConfigurationForId(project, nativeTarget.buildConfigurationList).forEach(
([, item]: ConfigurationSectionEntry) => {
if (item.buildSettings.PRODUCT_BUNDLE_IDENTIFIER === bundleIdentifier) {
return;
}
}
});
fs.writeFileSync(pbxprojPath, project.writeSync());
}

function getBuildConfigurationSectionEntires(project: Pbxproj): ConfigurationSectionEntry[] {
const configurationLists = getXCConfigurationLists(project);
const buildConfigurations = configurationLists[0].buildConfigurations.map(i => i.value);
item.buildSettings.PRODUCT_BUNDLE_IDENTIFIER = `"${bundleIdentifier}"`;

return Object.entries(getXCBuildConfigurationSection(project))
.filter(isNotComment)
.filter(isBuildConfig)
.filter(isNotTestHost)
.filter(([key]: ConfigurationSectionEntry) => buildConfigurations.includes(key));
if (updateProductName) {
const productName = bundleIdentifier.split('.').pop();
if (!productName?.includes('$')) {
item.buildSettings.PRODUCT_NAME = productName;
}
}
}
);
fs.writeFileSync(pbxprojPath, project.writeSync());
}

/**
Expand Down
17 changes: 4 additions & 13 deletions packages/config/src/ios/ProvisioningProfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@ import fs from 'fs-extra';
import {
ConfigurationSectionEntry,
ProjectSectionEntry,
findFirstNativeTarget,
getBuildConfigurationForId,
getPbxproj,
getProjectSection,
getXCBuildConfigurationSection,
getXCConfigurationLists,
isBuildConfig,
isNotComment,
isNotTestHost,
} from './utils/Xcodeproj';

type ProvisioningProfileSettings = {
Expand All @@ -22,17 +20,10 @@ function setProvisioningProfileForPbxproj(
{ profileName, appleTeamId }: ProvisioningProfileSettings
): void {
const project = getPbxproj(projectRoot);
const nativeTarget = findFirstNativeTarget(project);

const configurationLists = getXCConfigurationLists(project);
// TODO(dsokal): figure out if configuring only the entries from the first configuration list is fine
const buildConfigurations = configurationLists[0].buildConfigurations.map(i => i.value);

Object.entries(getXCBuildConfigurationSection(project))
.filter(isNotComment)
.filter(isBuildConfig)
.filter(isNotTestHost)
getBuildConfigurationForId(project, nativeTarget.buildConfigurationList)
.filter(([, item]: ConfigurationSectionEntry) => item.buildSettings.PRODUCT_NAME)
.filter(([key]: ConfigurationSectionEntry) => buildConfigurations.includes(key))
.forEach(([, item]: ConfigurationSectionEntry) => {
item.buildSettings.PROVISIONING_PROFILE_SPECIFIER = `"${profileName}"`;
item.buildSettings.DEVELOPMENT_TEAM = appleTeamId;
Expand Down
13 changes: 13 additions & 0 deletions packages/config/src/ios/__tests__/BundleIdentifier-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,19 @@ describe('BundleIdentifier module', () => {
);
expect(getBundleIdentifierFromPbxproj(projectRoot)).toBe('org.name.testproject');
});

it('returns the bundle identifier for the first native target in project.pbxproj (project initialized with react-native init)', () => {
vol.fromJSON(
{
'ios/testproject.xcodeproj/project.pbxproj': originalFs.readFileSync(
path.join(__dirname, 'fixtures/project-rni.pbxproj'),
'utf-8'
),
},
projectRoot
);
expect(getBundleIdentifierFromPbxproj(projectRoot)).toBe('org.reactjs.native.example.rni');
});
});

describe(setBundleIdentifier, () => {
Expand Down
Loading

0 comments on commit ffaf58e

Please sign in to comment.