Skip to content

Commit

Permalink
feat(extension): initial per-extension provisioning (#5749)
Browse files Browse the repository at this point in the history
  • Loading branch information
rigor789 authored Jul 28, 2023
1 parent c40e217 commit c564e18
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 35 deletions.
34 changes: 33 additions & 1 deletion lib/services/ios/export-options-plist-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,39 @@ import { IProjectData, IBuildConfig } from "../../definitions/project";
import { IFileSystem } from "../../common/declarations";
import { injector } from "../../common/yok";
import { ITempService } from "../../definitions/temp-service";
import * as constants from "../../constants";

export class ExportOptionsPlistService implements IExportOptionsPlistService {
constructor(private $fs: IFileSystem, private $tempService: ITempService) {}
constructor(
private $fs: IFileSystem,
private $tempService: ITempService,
private $projectData: IProjectData
) {}

private getExtensionProvisions() {
const provisioningJSONPath = path.join(
this.$projectData.getAppResourcesDirectoryPath(),
"iOS",
constants.NATIVE_EXTENSION_FOLDER,
"provisioning.json"
);
if (!this.$fs.exists(provisioningJSONPath)) {
return "";
}

interface IProvisioningJSON {
[identifier: string]: string;
}
const provisioningJSON = this.$fs.readJson(
provisioningJSONPath
) as IProvisioningJSON;

return Object.entries(provisioningJSON)
.map(([id, provision]) => {
return `<key>${id}</key>\n <string>${provision}</string>`;
})
.join("\n");
}

public async createDevelopmentExportOptionsPlist(
archivePath: string,
Expand All @@ -31,6 +61,7 @@ export class ExportOptionsPlistService implements IExportOptionsPlistService {
<dict>
<key>${projectData.projectIdentifiers.ios}</key>
<string>${provision}</string>
${this.getExtensionProvisions()}
</dict>`;
}
plistTemplate += `
Expand Down Expand Up @@ -87,6 +118,7 @@ export class ExportOptionsPlistService implements IExportOptionsPlistService {
<dict>
<key>${projectData.projectIdentifiers.ios}</key>
<string>${provision}</string>
${this.getExtensionProvisions()}
</dict>`;
}
plistTemplate += ` <key>method</key>
Expand Down
123 changes: 89 additions & 34 deletions test/services/ios/export-options-plist-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,49 @@ import { Yok } from "../../../lib/common/yok";
import { ExportOptionsPlistService } from "../../../lib/services/ios/export-options-plist-service";
import { assert } from "chai";
import * as _ from "lodash";
import { TempServiceStub } from "../../stubs";
import { TempServiceStub, ProjectDataStub } from "../../stubs";

let actualPlistTemplate: string = null;
const projectName = "myProjectName";
const projectRoot = "/my/test/project/platforms/ios";
const archivePath = "/my/test/archive/path";

let provisioningJSON: Record<string, any> | undefined;

function createTestInjector() {
const injector = new Yok();
provisioningJSON = undefined;
injector.register("fs", {
exists(path: string) {
return path.endsWith("provisioning.json");
},
writeFile: (exportPath: string, plistTemplate: string) => {
actualPlistTemplate = plistTemplate;
},
readJson() {
return provisioningJSON ?? {};
},
});
injector.register("exportOptionsPlistService", ExportOptionsPlistService);
injector.register("tempService", TempServiceStub);
const projectData = new ProjectDataStub();
projectData.initializeProjectData(projectRoot);
projectData.projectName = projectName;

injector.register("projectData", projectData);

return injector;
}

function expectPlistTemplateToContain(template: string, expected: string) {
const trimmedTemplate = template.replace(/\s/g, "");
const trimmedExpected = expected.replace(/\s/g, "");
assert.isTrue(
trimmedTemplate.indexOf(trimmedExpected) !== -1,
`Expected plist template to contain:\n\n${expected}\n\nbut it was:\n\n${template}`
);
}

describe("ExportOptionsPlistService", () => {
describe("createDevelopmentExportOptionsPlist", () => {
const testCases = [
Expand All @@ -33,21 +56,29 @@ describe("ExportOptionsPlistService", () => {
name: "should create export options plist with provision",
buildConfig: { provision: "myTestProvision" },
expectedPlist:
"<key>provisioningProfiles</key> <dict> <key>org.nativescript.myTestApp</key> <string>myTestProvision</string> </dict>",
"<key>provisioningProfiles</key><dict><key>org.nativescript.myTestApp</key><string>myTestProvision</string></dict>",
},
{
name:
"should create export options plist with mobileProvisionIdentifier",
name: "should create export options plist with mobileProvisionIdentifier",
buildConfig: { mobileProvisionIdentifier: "myTestProvision" },
expectedPlist:
"<key>provisioningProfiles</key> <dict> <key>org.nativescript.myTestApp</key> <string>myTestProvision</string> </dict>",
"<key>provisioningProfiles</key><dict><key>org.nativescript.myTestApp</key><string>myTestProvision</string></dict>",
},
{
name:
"should create export options plist with Production iCloudContainerEnvironment",
name: "should create export options plist with Production iCloudContainerEnvironment",
buildConfig: { iCloudContainerEnvironment: "Production" },
expectedPlist:
"<key>iCloudContainerEnvironment</key> <string>Production</string>",
"<key>iCloudContainerEnvironment</key><string>Production</string>",
},
{
name: "should add extension provisioning profiles if there are any",
buildConfig: { provision: "myTestProvision" },
provisioningJSON: {
"org.nativescript.myTestApp.SampleExtension":
"mySampleExtensionTestProvision",
},
expectedPlist:
"<key>provisioningProfiles</key><dict><key>org.nativescript.myTestApp</key><string>myTestProvision</string><key>org.nativescript.myTestApp.SampleExtension</key><string>mySampleExtensionTestProvision</string></dict>",
},
];

Expand All @@ -57,6 +88,9 @@ describe("ExportOptionsPlistService", () => {
(provisionType) => {
it(testCase.name, async () => {
const injector = createTestInjector();
if (testCase.provisioningJSON) {
provisioningJSON = testCase.provisioningJSON;
}
const exportOptionsPlistService = injector.resolve(
"exportOptionsPlistService"
);
Expand All @@ -73,20 +107,23 @@ describe("ExportOptionsPlistService", () => {
testCase.buildConfig
);

const template = actualPlistTemplate.split("\n").join(" ");
assert.isTrue(
template.indexOf(
`<key>method</key> <string>${provisionType}</string>`
) > 0
expectPlistTemplateToContain(
actualPlistTemplate,
`<key>method</key><string>${provisionType}</string>`
);
assert.isTrue(
template.indexOf("<key>uploadBitcode</key> <false/>") > 0
expectPlistTemplateToContain(
actualPlistTemplate,
`<key>uploadBitcode</key><false/>`
);
assert.isTrue(
template.indexOf("<key>compileBitcode</key> <false/>") > 0
expectPlistTemplateToContain(
actualPlistTemplate,
`<key>compileBitcode</key><false/>`
);
if (testCase.expectedPlist) {
assert.isTrue(template.indexOf(testCase.expectedPlist) > 0);
expectPlistTemplateToContain(
actualPlistTemplate,
testCase.expectedPlist
);
}
});
}
Expand All @@ -103,25 +140,37 @@ describe("ExportOptionsPlistService", () => {
name: "should create export options plist with provision",
buildConfig: { provision: "myTestProvision" },
expectedPlist:
"<key>provisioningProfiles</key> <dict> <key>org.nativescript.myTestApp</key> <string>myTestProvision</string> </dict>",
"<key>provisioningProfiles</key><dict><key>org.nativescript.myTestApp</key><string>myTestProvision</string></dict>",
},
{
name:
"should create export options plist with mobileProvisionIdentifier",
name: "should create export options plist with mobileProvisionIdentifier",
buildConfig: { mobileProvisionIdentifier: "myTestProvision" },
expectedPlist:
"<key>provisioningProfiles</key> <dict> <key>org.nativescript.myTestApp</key> <string>myTestProvision</string> </dict>",
"<key>provisioningProfiles</key><dict><key>org.nativescript.myTestApp</key><string>myTestProvision</string></dict>",
},
{
name: "should create export options plist with teamID",
buildConfig: { teamId: "myTeamId" },
expectedPlist: "<key>teamID</key> <string>myTeamId</string>",
expectedPlist: "<key>teamID</key><string>myTeamId</string>",
},
{
name: "should add extension provisioning profiles if there are any",
buildConfig: { provision: "myTestProvision" },
provisioningJSON: {
"org.nativescript.myTestApp.SampleExtension":
"mySampleExtensionTestProvision",
},
expectedPlist:
"<key>provisioningProfiles</key><dict><key>org.nativescript.myTestApp</key><string>myTestProvision</string><key>org.nativescript.myTestApp.SampleExtension</key><string>mySampleExtensionTestProvision</string></dict>",
},
];

_.each(testCases, (testCase) => {
it(testCase.name, async () => {
const injector = createTestInjector();
if (testCase.provisioningJSON) {
provisioningJSON = testCase.provisioningJSON;
}
const exportOptionsPlistService = injector.resolve(
"exportOptionsPlistService"
);
Expand All @@ -137,22 +186,28 @@ describe("ExportOptionsPlistService", () => {
testCase.buildConfig
);

const template = actualPlistTemplate.split("\n").join(" ");
assert.isTrue(
template.indexOf("<key>method</key> <string>app-store</string>") >
0
expectPlistTemplateToContain(
actualPlistTemplate,
`<key>method</key><string>app-store</string>`
);
assert.isTrue(
template.indexOf("<key>uploadBitcode</key> <false/>") > 0
expectPlistTemplateToContain(
actualPlistTemplate,
`<key>uploadBitcode</key><false/>`
);
assert.isTrue(
template.indexOf("<key>compileBitcode</key> <false/>") > 0
expectPlistTemplateToContain(
actualPlistTemplate,
`<key>compileBitcode</key><false/>`
);
assert.isTrue(
template.indexOf("<key>uploadSymbols</key> <false/>") > 0
expectPlistTemplateToContain(
actualPlistTemplate,
`<key>uploadSymbols</key><false/>`
);

if (testCase.expectedPlist) {
assert.isTrue(template.indexOf(testCase.expectedPlist) > 0);
expectPlistTemplateToContain(
actualPlistTemplate,
testCase.expectedPlist
);
}
});
});
Expand Down

0 comments on commit c564e18

Please sign in to comment.