Skip to content

feat(extension): initial per-extension provisioning #5749

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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