Skip to content

Commit 1377ef6

Browse files
feat: implement build-mpk script and update workflow for artifact handling
1 parent d02c965 commit 1377ef6

6 files changed

Lines changed: 256 additions & 138 deletions

File tree

.github/workflows/BuildMpk.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ jobs:
5454
- name: "Upload MPK artifact"
5555
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4
5656
with:
57-
name: ${{ inputs.module }}-${{ steps.bump_version.outputs.VERSION }}
58-
path: ${{ inputs.module == 'mobile-resources-native' && 'tmp/mobile-resources-native/NativeMobileResources.mpk' || 'tmp/nanoflow-actions-native/NanoflowCommons.mpk' }}
57+
name: ${{ env.ARTIFACT_NAME }}
58+
path: ${{ env.ARTIFACT_PATH }}
5959
if-no-files-found: error
6060

6161
- name: "Cleanup tmp folder"

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"release:marketplace": "pnpm -r run release:marketplace",
2727
"release-github:widget": "node ./scripts/release/createWidgetRelease.js",
2828
"create-modules": "node ./scripts/release/createNativeModules.js",
29-
"build-mpk": "node ./scripts/release/buildMpk.js",
29+
"build-mpk": "ts-node --project ./scripts/tsconfig.json ./scripts/release/build-mpk.ts",
3030
"version": "ts-node --project ./scripts/tsconfig.json ./scripts/release/BumpVersion.ts",
3131
"validate-staged-widget-versions": "node scripts/validation/validate-versions-staged-files.js",
3232
"setup-mobile": "pnpm setup-android && pnpm setup-ios",

scripts/release/build-mpk.ts

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
import { basename, join, dirname } from "path";
2+
import { readdir, copyFile, rm, mkdir } from "fs/promises";
3+
import {
4+
execShellCommand,
5+
getFiles,
6+
getPackageInfo,
7+
cloneRepo,
8+
createMPK,
9+
exportModuleWithWidgets,
10+
regex,
11+
copyFilesToMpk,
12+
getOssFiles
13+
} from "./module-automation/commons";
14+
15+
const repoRootPath = join(__dirname, "../../");
16+
17+
const LOG_PREFIX = "[buildMpk]";
18+
function log(message: string): void {
19+
console.log(`${LOG_PREFIX} ${message}`);
20+
}
21+
22+
type ArtifactResult = {
23+
artifactPath: string;
24+
artifactName: string;
25+
};
26+
27+
type InputVariables = {
28+
module: string;
29+
version: string;
30+
};
31+
32+
const inputs: InputVariables = {
33+
module: "",
34+
version: ""
35+
};
36+
37+
main()
38+
.then(writeArtifactEnvVariable)
39+
.catch(e => {
40+
console.error(e);
41+
process.exit(1);
42+
});
43+
44+
function writeArtifactEnvVariable(artifact: ArtifactResult): void {
45+
if (!artifact?.artifactPath || !artifact?.artifactName) {
46+
throw new Error(`${LOG_PREFIX} Expected an artifact result from main(), but got: ${JSON.stringify(artifact)}`);
47+
}
48+
49+
log(`Setting environment variable ARTIFACT_PATH=${artifact.artifactPath}`);
50+
process.env.ARTIFACT_PATH = artifact.artifactPath;
51+
log(`Setting environment variable ARTIFACT_NAME=${artifact.artifactName}`);
52+
process.env.ARTIFACT_NAME = artifact.artifactName;
53+
log("Artifact environment variables set successfully.");
54+
}
55+
56+
function validateInput(): void {
57+
const moduleName = process.env.MODULE;
58+
let version = process.env.VERSION;
59+
60+
const modules = ["mobile-resources-native", "nanoflow-actions-native"];
61+
if (!moduleName || !modules.includes(moduleName)) {
62+
throw new Error(`${LOG_PREFIX} Invalid MODULE="${moduleName}". Expected one of: ${modules.join(", ")}`);
63+
}
64+
if (!version) {
65+
throw new Error(`${LOG_PREFIX} Invalid VERSION="${version}"`);
66+
}
67+
if (version?.startsWith("v")) {
68+
version = version.split("v")[1];
69+
}
70+
inputs.module = moduleName;
71+
inputs.version = version;
72+
log(`Starting (MODULE=${inputs.module}, VERSION=${inputs.version})`);
73+
}
74+
75+
async function main(): Promise<ArtifactResult> {
76+
validateInput();
77+
switch (inputs.module) {
78+
case "mobile-resources-native":
79+
return createNativeMobileResourcesModule();
80+
case "nanoflow-actions-native":
81+
return createNanoflowCommonsModule();
82+
}
83+
throw new Error(`${LOG_PREFIX} No implementation for MODULE="${inputs.module}"`);
84+
}
85+
86+
async function createNativeMobileResourcesModule(): Promise<ArtifactResult> {
87+
log("Creating the Native Mobile Resource module...");
88+
const moduleFolder = join(repoRootPath, "packages/jsActions", inputs.module);
89+
log(`Module folder: ${moduleFolder}`);
90+
const ossFiles = await getOssFiles(moduleFolder, true);
91+
log(`OSS files to include: ${ossFiles.length}`);
92+
const tmpFolder = join(repoRootPath, "tmp", inputs.module);
93+
log(`Temp folder: ${tmpFolder}`);
94+
const widgetFolders = await readdir(join(repoRootPath, "packages/pluggableWidgets"));
95+
const nativeWidgetFolders = widgetFolders
96+
.filter(folder => folder.includes("-native"))
97+
.map(folder => join(repoRootPath, "packages/pluggableWidgets", folder));
98+
log(`Native widget folders found: ${nativeWidgetFolders.length}`);
99+
const moduleInfo = {
100+
...(await getPackageInfo(moduleFolder)),
101+
moduleNameInModeler: "NativeMobileResources",
102+
moduleFolderNameInModeler: "nativemobileresources"
103+
};
104+
log(
105+
`Module info: nameWithSpace=${moduleInfo.nameWithSpace ?? "<unknown>"}, minimumMXVersion=${
106+
moduleInfo.minimumMXVersion ?? "<unknown>"
107+
}, moduleNameInModeler=${moduleInfo.moduleNameInModeler}`
108+
);
109+
await updateNativeComponentsTestProject(moduleInfo, tmpFolder, nativeWidgetFolders);
110+
log("Creating MPK...");
111+
const mpkOutput = await createMPK(tmpFolder, moduleInfo, regex.excludeFiles);
112+
log(`MPK created at: ${mpkOutput}`);
113+
log("Exporting module with widgets into MPK...");
114+
await exportModuleWithWidgets(moduleInfo.moduleNameInModeler, mpkOutput, nativeWidgetFolders, ossFiles);
115+
return {
116+
artifactPath: mpkOutput,
117+
artifactName: moduleInfo.moduleNameInModeler
118+
};
119+
}
120+
121+
async function createNanoflowCommonsModule(): Promise<ArtifactResult> {
122+
log("Creating the Nanoflow Commons module...");
123+
const moduleFolder = join(repoRootPath, "packages/jsActions", inputs.module);
124+
log(`Module folder: ${moduleFolder}`);
125+
const ossFiles = await getOssFiles(moduleFolder, true);
126+
log(`OSS files to include: ${ossFiles.length}`);
127+
const tmpFolder = join(repoRootPath, "tmp", inputs.module);
128+
log(`Temp folder: ${tmpFolder}`);
129+
const moduleInfo = {
130+
...(await getPackageInfo(moduleFolder)),
131+
moduleNameInModeler: "NanoflowCommons",
132+
moduleFolderNameInModeler: "nanoflowcommons"
133+
};
134+
135+
log(
136+
`Module info: nameWithSpace=${moduleInfo.nameWithSpace ?? "<unknown>"}, minimumMXVersion=${
137+
moduleInfo.minimumMXVersion ?? "<unknown>"
138+
}, moduleNameInModeler=${moduleInfo.moduleNameInModeler}`
139+
);
140+
141+
await updateNativeComponentsTestProject(moduleInfo, tmpFolder);
142+
log("Creating MPK...");
143+
const mpkOutput = await createMPK(tmpFolder, moduleInfo, regex.excludeFiles);
144+
log(`MPK created at: ${mpkOutput}`);
145+
log("Copying OSS files into MPK...");
146+
await copyFilesToMpk(ossFiles, mpkOutput, moduleInfo.moduleNameInModeler);
147+
return {
148+
artifactPath: mpkOutput,
149+
artifactName: moduleInfo.moduleNameInModeler
150+
};
151+
}
152+
153+
// Update test project with latest changes and update version in themesource
154+
async function updateNativeComponentsTestProject(
155+
moduleInfo: any,
156+
tmpFolder: string,
157+
nativeWidgetFolders?: string[]
158+
): Promise<void> {
159+
const jsActionsPath = join(repoRootPath, `packages/jsActions/${inputs.module}/dist`);
160+
const jsActions: string[] = await getFiles(jsActionsPath);
161+
const tmpFolderActions = join(tmpFolder, `javascriptsource/${moduleInfo.moduleFolderNameInModeler}/actions`);
162+
163+
log(`Updating NativeComponentsTestProject (repo=${moduleInfo.testProjectUrl ?? "<unknown>"})...`);
164+
log(`JS actions dist path: ${jsActionsPath}`);
165+
log(`JS actions files found: ${jsActions.length}`);
166+
await cloneRepo(moduleInfo.testProjectUrl, tmpFolder);
167+
168+
log(`Deleting existing JS Actions from test project: ${tmpFolderActions}`);
169+
await rm(tmpFolderActions, { force: true, recursive: true }); // this is useful to avoid retaining stale dependencies in the test project.
170+
await mkdir(tmpFolderActions);
171+
log("Copying widget resources JS actions into test project...");
172+
await Promise.all([
173+
...jsActions.map(async file => {
174+
const dest = join(tmpFolderActions, file.replace(jsActionsPath, ""));
175+
await mkdir(dirname(dest), { recursive: true });
176+
await copyFile(file, dest);
177+
})
178+
]);
179+
if (nativeWidgetFolders) {
180+
log(`Deleting existing widgets from test project (widgets=${nativeWidgetFolders.length})...`);
181+
const widgetsDir = join(tmpFolder, "widgets");
182+
183+
// backup two web widgets that are used in the test project
184+
const tempBackup = join(tmpFolder, "widgets-backup");
185+
await mkdir(tempBackup);
186+
187+
const htmlSnippetWidgetName = "HTMLSnippet.mpk";
188+
const htmlSnippetTempPath = join(tempBackup, htmlSnippetWidgetName);
189+
const htmlSnippetPath = join(widgetsDir, htmlSnippetWidgetName);
190+
await copyFile(htmlSnippetPath, htmlSnippetTempPath);
191+
192+
const sprintrFeedbackWidgetName = "SprintrFeedbackWidget.mpk";
193+
const sprintFeedbackTempPath = join(tempBackup, sprintrFeedbackWidgetName);
194+
const sprintrFeedbackPath = join(widgetsDir, sprintrFeedbackWidgetName);
195+
await copyFile(sprintrFeedbackPath, sprintFeedbackTempPath);
196+
197+
await rm(widgetsDir, { force: true, recursive: true }); // this is useful to avoid retaining stale widgets in the test project.
198+
await mkdir(widgetsDir);
199+
200+
await copyFile(htmlSnippetTempPath, htmlSnippetPath);
201+
await copyFile(sprintFeedbackTempPath, sprintrFeedbackPath);
202+
await rm(tempBackup, { force: true, recursive: true });
203+
204+
log("Copying widget resources widgets into test project...");
205+
await Promise.all([
206+
...nativeWidgetFolders.map(async folder => {
207+
const src = (await getFiles(folder, [`.mpk`]))[0];
208+
const dest = join(widgetsDir, basename(src));
209+
await copyFile(src, dest);
210+
})
211+
]);
212+
}
213+
log(`Writing themesource version file for ${moduleInfo.moduleFolderNameInModeler}...`);
214+
await execShellCommand(
215+
`echo ${inputs.version} > themesource/${moduleInfo.moduleFolderNameInModeler}/.version`,
216+
tmpFolder
217+
);
218+
}

scripts/release/buildMpk.js

Lines changed: 0 additions & 135 deletions
This file was deleted.

0 commit comments

Comments
 (0)