From 5b6ac4a669ea5d933ddfbda54992940caf6f490b Mon Sep 17 00:00:00 2001 From: Roman Vyakhirev Date: Wed, 28 Jan 2026 17:21:34 +0100 Subject: [PATCH 1/6] chore: print mendix version for test project is sqlite3 is available --- automation/run-e2e/lib/dev.mjs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/automation/run-e2e/lib/dev.mjs b/automation/run-e2e/lib/dev.mjs index 0a4b20e389..589ffacf7e 100644 --- a/automation/run-e2e/lib/dev.mjs +++ b/automation/run-e2e/lib/dev.mjs @@ -1,14 +1,17 @@ -import { spawnSync } from "node:child_process"; +import { spawnSync, execSync } from "node:child_process"; import { delimiter } from "node:path"; import { fileURLToPath } from "node:url"; import parseArgs from "yargs-parser"; import c from "ansi-colors"; import enquirer from "enquirer"; +import sh from "shelljs"; import { setupTestProject } from "./setup-test-project.mjs"; import { updateTestProject } from "./update-test-project.mjs"; import { await200 } from "./utils.mjs"; import * as config from "./config.mjs"; +const { ls } = sh; + export async function dev() { console.log(c.cyan("Run e2e tests in development environment")); @@ -53,6 +56,29 @@ export async function dev() { ) ); + // Print out Mendix version from MPR file + try { + const mprFiles = ls(config.mprFileGlob); + if (mprFiles.length > 0) { + const mprFile = mprFiles[0]; + try { + const version = execSync(`sqlite3 "${mprFile}" "select _ProductVersion from _MetaData;"`, { + encoding: "utf-8", + stdio: ["pipe", "pipe", "pipe"] + }).trim(); + console.log(c.cyan(`Test project was created with Mendix version: ${c.bold(version)}`)); + } catch (error) { + if (error.message.includes("sqlite3") || error.code === "ENOENT") { + console.log(c.gray("sqlite3 command not found, unable to get Mendix version info")); + } else { + console.log(c.gray("Unable to read Mendix version from project file")); + } + } + } + } catch { + console.log(c.gray("Unable to determine Mendix version")); + } + await enquirer.prompt({ type: "confirm", name: "__ignore__", From 88fa74ea4d676b5635f14e5523da82f4e7c07c0c Mon Sep 17 00:00:00 2001 From: Roman Vyakhirev Date: Fri, 30 Jan 2026 11:48:24 +0100 Subject: [PATCH 2/6] chore: set token from gh util --- automation/run-e2e/lib/dev.mjs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/automation/run-e2e/lib/dev.mjs b/automation/run-e2e/lib/dev.mjs index 589ffacf7e..68c897d59c 100644 --- a/automation/run-e2e/lib/dev.mjs +++ b/automation/run-e2e/lib/dev.mjs @@ -10,7 +10,7 @@ import { updateTestProject } from "./update-test-project.mjs"; import { await200 } from "./utils.mjs"; import * as config from "./config.mjs"; -const { ls } = sh; +const { ls, exec } = sh; export async function dev() { console.log(c.cyan("Run e2e tests in development environment")); @@ -32,6 +32,20 @@ export async function dev() { } }; + if (!process.env.GITHUB_TOKEN) { + console.log("GITHUB_TOKEN not found. Fetching from GitHub CLI..."); + + const result = exec("gh auth token", { silent: true }); + + if (result.code === 0) { + process.env.GITHUB_TOKEN = result.stdout.trim(); + console.log("Successfully set GITHUB_TOKEN from gh CLI."); + } else { + console.error('Error: Could not retrieve token. Ensure you are logged in via "gh auth login".'); + process.exit(1); + } + } + // We add local node_modules/.bin to PATH to make cypress bin is available for // any package in monorepo. const packageBinariesPath = fileURLToPath(new URL("../node_modules/.bin", import.meta.url)); From 0a800c812350068d523b746248f9fcefdb73cc34 Mon Sep 17 00:00:00 2001 From: Roman Vyakhirev Date: Fri, 30 Jan 2026 12:07:03 +0100 Subject: [PATCH 3/6] chore: select action interactively --- automation/utils/bin/rui-oss-clearance.ts | 238 ++++++++++++---------- 1 file changed, 128 insertions(+), 110 deletions(-) diff --git a/automation/utils/bin/rui-oss-clearance.ts b/automation/utils/bin/rui-oss-clearance.ts index 793e837eab..3ef5f898e8 100755 --- a/automation/utils/bin/rui-oss-clearance.ts +++ b/automation/utils/bin/rui-oss-clearance.ts @@ -84,34 +84,61 @@ async function verifyGitHubAuth(): Promise { async function selectRelease(): Promise { printStep(2, 5, "Fetching draft releases..."); - const releases = await gh.getDraftReleases(); - printSuccess(`Found ${releases.length} draft release${releases.length !== 1 ? "s" : ""}`); - - if (releases.length === 0) { - printWarning( - "No draft releases found. Please create a draft release before trying again using `prepare-release` tool" - ); - throw new Error("No draft releases found"); - } + while (true) { + const releases = await gh.getDraftReleases(); + printSuccess(`Found ${releases.length} draft release${releases.length !== 1 ? "s" : ""}`); - console.log(); // spacing - const { tag_name } = await prompt<{ tag_name: string }>({ - type: "select", - name: "tag_name", - message: "Select a release to process:", - choices: releases.map(r => ({ - name: r.tag_name, - message: `${r.name} ${chalk.gray(`(${r.tag_name})`)}` - })) - }); + if (releases.length === 0) { + printWarning("No draft releases found. Please create a draft release before trying again."); - const release = releases.find(r => r.tag_name === tag_name); - if (!release) { - throw new Error(`Release not found: ${tag_name}`); - } + console.log(); // spacing + const { action } = await prompt<{ action: string }>({ + type: "select", + name: "action", + message: "What would you like to do?", + choices: [ + { name: "refresh", message: "--- Refresh the list ---" }, + { name: "exit", message: "āŒ Exit" } + ] + }); - printInfo(`Selected release: ${chalk.bold(release.name)}`); - return release; + if (action === "exit") { + throw new Error("No draft releases found"); + } + // If "refresh", continue the loop + continue; + } + + console.log(); // spacing + const { tag_name } = await prompt<{ tag_name: string }>({ + type: "select", + name: "tag_name", + message: "Select a release to process:", + choices: [ + ...releases.map(r => ({ + name: r.tag_name, + message: `${r.name} ${chalk.gray(`(${r.tag_name})`)}` + })), + { + name: "__refresh__", + message: chalk.cyan("--- Refresh the list ---") + } + ] + }); + + if (tag_name === "__refresh__") { + printInfo("Refreshing draft releases list..."); + continue; // Loop again to fetch fresh data + } + + const release = releases.find(r => r.tag_name === tag_name); + if (!release) { + throw new Error(`Release not found: ${tag_name}`); + } + + printInfo(`Selected release: ${chalk.bold(release.name)}`); + return release; + } } async function findAndValidateMpkAsset(release: GitHubDraftRelease): Promise { @@ -178,41 +205,86 @@ async function computeHash(filepath: string): Promise { // Command Handlers // ============================================================================ -async function handlePrepareCommand(): Promise { - printHeader("OSS Clearance Artifacts Preparation"); +async function selectAction(): Promise<"prepare" | "include"> { + console.log(); // spacing + const { action } = await prompt<{ action: "prepare" | "include" }>({ + type: "select", + name: "action", + message: "What would you like to do with this release?", + choices: [ + { + name: "prepare", + message: "Prepare OSS clearance SBOM" + }, + { + name: "include", + message: "Include OSS Readme" + } + ] + }); - try { - // Step 1: Verify authentication - await verifyGitHubAuth(); + return action; +} - // Step 2: Select release - const release = await selectRelease(); +async function handlePrepareAction(release: GitHubDraftRelease, mpkAsset: GitHubReleaseAsset): Promise { + printHeader("OSS Clearance Artifacts Preparation"); - // Step 3: Find MPK asset - const mpkAsset = await findAndValidateMpkAsset(release); + // Prepare folder structure + const [tmpFolder, downloadPath] = await createSBomGeneratorFolderStructure(release.name); + printInfo(`Working directory: ${tmpFolder}`); - // Prepare folder structure - const [tmpFolder, downloadPath] = await createSBomGeneratorFolderStructure(release.name); - printInfo(`Working directory: ${tmpFolder}`); + // Step 4: Download and verify + const fileHash = await downloadAndVerifyAsset(mpkAsset, downloadPath); - // Step 4: Download and verify - const fileHash = await downloadAndVerifyAsset(mpkAsset, downloadPath); + // Step 5: Run SBOM Generator + const finalPath = await runSbomGenerator(tmpFolder, release.name, fileHash); - // Step 5: Run SBOM Generator - const finalPath = await runSbomGenerator(tmpFolder, release.name, fileHash); + console.log(chalk.bold.green(`\nšŸŽ‰ Success! Output file:`)); + console.log(chalk.cyan(` ${finalPath}\n`)); +} - console.log(chalk.bold.green(`\nšŸŽ‰ Success! Output file:`)); - console.log(chalk.cyan(` ${finalPath}\n`)); - } catch (error) { - console.log("\n" + chalk.bold.red("═".repeat(60))); - printError(`Process failed: ${(error as Error).message}`); - console.log(chalk.bold.red("═".repeat(60)) + "\n"); - process.exit(1); +async function handleIncludeAction(release: GitHubDraftRelease): Promise { + printHeader("OSS Clearance Readme Include"); + + // Step 4: Find and select OSS Readme + const readmes = findAllReadmeOssLocally(); + const recommendedReadmeOss = getRecommendedReadmeOss( + release.name.split(" ")[0], + release.name.split(" ")[1], + readmes + ); + + let readmeToInclude: string; + + if (!recommendedReadmeOss) { + const { selectedReadme } = await prompt<{ selectedReadme: string }>({ + type: "select", + name: "selectedReadme", + message: "Select a README_OSS file to include:", + choices: readmes.map(r => ({ + name: r, + message: basename(r) + })) + }); + + readmeToInclude = selectedReadme; + } else { + readmeToInclude = recommendedReadmeOss; } + + printInfo(`Readme to include: ${readmeToInclude}`); + + // Step 5: Upload asset to the draft release + const newAsset = await gh.uploadReleaseAsset(release.id, readmeToInclude, basename(readmeToInclude)); + printSuccess(`Successfully uploaded asset ${newAsset.name} (ID: ${newAsset.id})`); } -async function handleIncludeCommand(): Promise { - printHeader("OSS Clearance Readme Include"); +// ============================================================================ +// Main Function +// ============================================================================ + +async function main(): Promise { + printHeader("OSS Clearance Tool"); try { // Step 1: Verify authentication @@ -224,39 +296,15 @@ async function handleIncludeCommand(): Promise { // Step 3: Find MPK asset const mpkAsset = await findAndValidateMpkAsset(release); - // Step 4: Find and select OSS Readme - const readmes = findAllReadmeOssLocally(); - const recommendedReadmeOss = getRecommendedReadmeOss( - release.name.split(" ")[0], - release.name.split(" ")[1], - readmes - ); - - let readmeToInclude: string; + // Step 4: Select action + const action = await selectAction(); - if (!recommendedReadmeOss) { - const { selectedReadme } = await prompt<{ selectedReadme: string }>({ - type: "select", - name: "selectedReadme", - message: "Select a release to process:", - choices: readmes.map(r => ({ - name: r, - message: basename(r) - })) - }); - - readmeToInclude = selectedReadme; + // Step 5: Execute selected action + if (action === "prepare") { + await handlePrepareAction(release, mpkAsset); } else { - readmeToInclude = recommendedReadmeOss; + await handleIncludeAction(release); } - - printInfo(`Readme to include: ${readmeToInclude}`); - - // Step 7: Upload updated asses to the draft release - const newAsset = await gh.uploadReleaseAsset(release.id, readmeToInclude, basename(readmeToInclude)); - console.log(`Successfully uploaded asset ${newAsset.name} (ID: ${newAsset.id})`); - - console.log(release.id); } catch (error) { console.log("\n" + chalk.bold.red("═".repeat(60))); printError(`Process failed: ${(error as Error).message}`); @@ -265,36 +313,6 @@ async function handleIncludeCommand(): Promise { } } -// ============================================================================ -// Main Function -// ============================================================================ - -async function main(): Promise { - const command = process.argv[2]; - - switch (command) { - case "prepare": - await handlePrepareCommand(); - break; - case "include": - await handleIncludeCommand(); - break; - default: - printError(command ? `Unknown command: ${command}` : "No command specified"); - console.log(chalk.white("\nUsage:")); - console.log( - chalk.cyan(" rui-oss-clearance.ts prepare ") + - chalk.gray("- Prepare OSS clearance artifact from draft release") - ); - console.log( - chalk.cyan(" rui-oss-clearance.ts include ") + - chalk.gray("- Include OSS Readme file into a draft release") - ); - console.log(); - process.exit(1); - } -} - // ============================================================================ // Entry Point // ============================================================================ From 6a1b037ca0043452430d9e7e2262a269b0150936 Mon Sep 17 00:00:00 2001 From: Roman Vyakhirev Date: Fri, 30 Jan 2026 13:40:10 +0100 Subject: [PATCH 4/6] chore: print artifacts sizes --- automation/utils/bin/rui-include-oss-in-artifact.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/automation/utils/bin/rui-include-oss-in-artifact.ts b/automation/utils/bin/rui-include-oss-in-artifact.ts index c325e80b14..ea00dab908 100755 --- a/automation/utils/bin/rui-include-oss-in-artifact.ts +++ b/automation/utils/bin/rui-include-oss-in-artifact.ts @@ -3,7 +3,7 @@ import { gh } from "../src/github"; import { includeReadmeOssIntoMpk } from "../src/oss-clearance"; import { rm } from "../src/shell"; -import { mkdtemp } from "node:fs/promises"; +import { mkdtemp, stat } from "node:fs/promises"; import { join } from "node:path"; import { tmpdir } from "node:os"; import chalk from "chalk"; @@ -48,7 +48,7 @@ async function main(): Promise { throw new Error(`No MPK file found in release '${releaseTag}'`); } - console.log(chalk.green(`āœ… Found MPK: ${mpkAsset.name}`)); + console.log(chalk.green(`āœ… Found MPK: ${mpkAsset.name} (${mpkAsset.size} bytes)`)); // Step 2: Check if HTML file exists if (!htmlAsset) { @@ -57,7 +57,7 @@ async function main(): Promise { return; } - console.log(chalk.green(`āœ… Found HTML: ${htmlAsset.name}`)); + console.log(chalk.green(`āœ… Found HTML: ${htmlAsset.name} (${htmlAsset.size} bytes)`)); // Step 3: Download both files to temp directory console.log(chalk.blue("\nšŸ“„ Downloading artifacts...")); @@ -80,6 +80,11 @@ async function main(): Promise { await includeReadmeOssIntoMpk(htmlPath, mpkPath); console.log(chalk.green("āœ… Merge completed")); + // Get modified MPK size + const modifiedMpkStats = await stat(mpkPath); + const sizeDiff = modifiedMpkStats.size - mpkAsset.size; + console.log(chalk.cyan(`ā„¹ļø Modified MPK size: ${modifiedMpkStats.size} bytes (+${sizeDiff} bytes)`)); + // Step 5: Remove old assets and upload patched MPK console.log(chalk.blue("\nšŸ”„ Replacing assets in release...")); @@ -93,6 +98,7 @@ async function main(): Promise { const newAsset = await gh.uploadReleaseAsset(releaseId, mpkPath, mpkAsset.name); console.log(chalk.green(`āœ… Successfully replaced MPK asset (ID: ${newAsset.id})`)); + console.log(chalk.cyan(`ā„¹ļø New MPK size: ${newAsset.size} bytes`)); // Summary console.log(chalk.bold.green(`\nšŸŽ‰ Process completed successfully!`)); From 219bf734e3df3244886381e81f016fa2cfa74678 Mon Sep 17 00:00:00 2001 From: Roman Vyakhirev Date: Fri, 30 Jan 2026 13:41:44 +0100 Subject: [PATCH 5/6] chore: make it possible to embed artifacts manually --- automation/utils/bin/rui-oss-clearance.ts | 120 +++++++++++++++++++++- automation/utils/src/github.ts | 30 +++++- 2 files changed, 146 insertions(+), 4 deletions(-) diff --git a/automation/utils/bin/rui-oss-clearance.ts b/automation/utils/bin/rui-oss-clearance.ts index 3ef5f898e8..16eb8aab0e 100755 --- a/automation/utils/bin/rui-oss-clearance.ts +++ b/automation/utils/bin/rui-oss-clearance.ts @@ -12,7 +12,8 @@ import { createSBomGeneratorFolderStructure, findAllReadmeOssLocally, generateSBomArtifactsInFolder, - getRecommendedReadmeOss + getRecommendedReadmeOss, + includeReadmeOssIntoMpk } from "../src/oss-clearance"; // ============================================================================ @@ -274,9 +275,124 @@ async function handleIncludeAction(release: GitHubDraftRelease): Promise { printInfo(`Readme to include: ${readmeToInclude}`); - // Step 5: Upload asset to the draft release + // Step 5: Ask how to include the README + console.log(); // spacing + const { includeMethod } = await prompt<{ includeMethod: "asset" | "embedded" }>({ + type: "select", + name: "includeMethod", + message: "How would you like to include the OSS Readme?", + choices: [ + { + name: "asset", + message: "Upload as separate asset (adds HTML file to release)" + }, + { + name: "embedded", + message: "Embed into MPK (modifies MPK to include HTML inside)" + } + ] + }); + + if (includeMethod === "asset") { + await handleIncludeAsAssetAction(release, readmeToInclude); + } else { + await handleIncludeAsEmbeddedAction(release, readmeToInclude); + } +} + +async function handleIncludeAsAssetAction(release: GitHubDraftRelease, readmeToInclude: string): Promise { + printStep(5, 5, "Uploading README as separate asset..."); + const newAsset = await gh.uploadReleaseAsset(release.id, readmeToInclude, basename(readmeToInclude)); printSuccess(`Successfully uploaded asset ${newAsset.name} (ID: ${newAsset.id})`); + printInfo(`Size: ${newAsset.size} bytes`); +} + +async function handleIncludeAsEmbeddedAction(release: GitHubDraftRelease, readmeToInclude: string): Promise { + printStep(5, 5, "Embedding README into MPK..."); + + // Find MPK asset + const mpkAsset = release.assets.find(asset => asset.name.endsWith(".mpk")); + if (!mpkAsset) { + printError("No MPK asset found in release"); + throw new Error("MPK asset not found"); + } + + printInfo(`Found MPK: ${mpkAsset.name} (${mpkAsset.size} bytes)`); + + // Create temp folder + const { mkdtemp } = await import("node:fs/promises"); + const { tmpdir } = await import("node:os"); + const tmpFolder = await mkdtemp(join(tmpdir(), "mpk-oss-embed-")); + const mpkPath = join(tmpFolder, mpkAsset.name); + const htmlPath = join(tmpFolder, basename(readmeToInclude)); + + try { + // Download MPK to temp folder + printProgress(`Downloading ${mpkAsset.name}...`); + await gh.downloadReleaseAsset(mpkAsset.id, mpkPath); + printSuccess("Download completed"); + + // Copy HTML to temp folder + const { cp } = await import("../src/shell"); + await cp(readmeToInclude, htmlPath); + + // Embed HTML into MPK + printProgress("Merging HTML into MPK..."); + await includeReadmeOssIntoMpk(htmlPath, mpkPath); + printSuccess("Merge completed"); + + // Get modified MPK size + const { stat } = await import("node:fs/promises"); + const modifiedMpkStats = await stat(mpkPath); + const sizeDiff = modifiedMpkStats.size - mpkAsset.size; + printInfo(`Modified MPK size: ${modifiedMpkStats.size} bytes (+${sizeDiff} bytes)`); + + // Confirm before uploading + console.log(); // spacing + console.log(chalk.yellow("āš ļø This will modify the release assets:")); + console.log( + chalk.gray( + ` 1. Original MPK will be renamed: ${mpkAsset.name} → ${mpkAsset.name.replace(".mpk", "._mpk")}` + ) + ); + console.log(chalk.gray(` 2. Modified MPK will be uploaded: ${mpkAsset.name}`)); + + const { confirmed } = await prompt<{ confirmed: boolean }>({ + type: "confirm", + name: "confirmed", + message: "Do you want to proceed with these changes?", + initial: false + }); + + if (!confirmed) { + printWarning("Operation cancelled by user"); + return; + } + + printProgress("Updating release assets..."); + + // Rename original MPK + const backupName = mpkAsset.name.replace(".mpk", "._mpk"); + printProgress(`Renaming original MPK to ${backupName}...`); + await gh.updateReleaseAsset(mpkAsset.id, backupName); + printSuccess("Original MPK renamed"); + + // Upload modified MPK + printProgress(`Uploading modified MPK...`); + const newMpkAsset = await gh.uploadReleaseAsset(release.id, mpkPath, mpkAsset.name); + printSuccess(`Modified MPK uploaded (ID: ${newMpkAsset.id})`); + + console.log(chalk.bold.green(`\nšŸŽ‰ Successfully embedded OSS Readme into MPK!`)); + console.log(chalk.gray(` Release: ${release.name}`)); + console.log(chalk.gray(` Modified MPK: ${newMpkAsset.name} (${newMpkAsset.size} bytes)`)); + console.log(chalk.gray(` Backup MPK: ${backupName}`)); + } finally { + // Cleanup temp files + printProgress("Cleaning up temporary files..."); + const { rm } = await import("../src/shell"); + await rm("-rf", tmpFolder); + } } // ============================================================================ diff --git a/automation/utils/src/github.ts b/automation/utils/src/github.ts index bb3d7f2580..984e39d23f 100644 --- a/automation/utils/src/github.ts +++ b/automation/utils/src/github.ts @@ -339,9 +339,35 @@ export class GitHub { ); } - const asset = (await response.json()) as GitHubReleaseAsset; + return (await response.json()) as GitHubReleaseAsset; + } + + /** + * Update a release asset's name + */ + async updateReleaseAsset(assetId: string, newName: string): Promise { + await this.ensureAuth(); + + const response = await nodefetch( + `https://api.github.com/repos/${this.owner}/${this.repo}/releases/assets/${assetId}`, + { + method: "PATCH", + headers: { + ...this.ghAPIHeaders, + "Content-Type": "application/json" + }, + body: JSON.stringify({ name: newName }) + } + ); + + if (!response.ok) { + const errorText = await response.text(); + throw new Error( + `Failed to update asset ${assetId}: ${response.status} ${response.statusText} - ${errorText}` + ); + } - return asset; + return (await response.json()) as GitHubReleaseAsset; } } From a5533cf0a7490687372b56517c9dbec61d9cc2f1 Mon Sep 17 00:00:00 2001 From: Roman Vyakhirev Date: Fri, 30 Jan 2026 14:45:38 +0100 Subject: [PATCH 6/6] chore: improve autoselect and formatting --- automation/utils/bin/rui-oss-clearance.ts | 26 ++++++++++++----------- automation/utils/src/oss-clearance.ts | 14 ++++++------ 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/automation/utils/bin/rui-oss-clearance.ts b/automation/utils/bin/rui-oss-clearance.ts index 16eb8aab0e..65b3e0a52f 100755 --- a/automation/utils/bin/rui-oss-clearance.ts +++ b/automation/utils/bin/rui-oss-clearance.ts @@ -56,6 +56,10 @@ function printProgress(message: string): void { console.log(chalk.gray(` → ${message}`)); } +function printProgressCheck(message: string): void { + console.log(chalk.gray(` ā˜‘ ${message}`)); +} + // ============================================================================ // Core Functions // ============================================================================ @@ -163,11 +167,11 @@ async function downloadAndVerifyAsset(mpkAsset: GitHubReleaseAsset, downloadPath printProgress(`Downloading to: ${downloadPath}`); await gh.downloadReleaseAsset(mpkAsset.id, downloadPath); - printSuccess("Download completed"); + printProgressCheck("Download completed"); printProgress("Computing SHA-256 hash..."); const fileHash = await computeHash(downloadPath); - printInfo(`Computed hash: ${fileHash}`); + printProgressCheck(`Computed hash: ${fileHash}`); const expectedDigest = mpkAsset.digest.replace("sha256:", ""); if (fileHash !== expectedDigest) { @@ -177,7 +181,7 @@ async function downloadAndVerifyAsset(mpkAsset: GitHubReleaseAsset, downloadPath throw new Error("Asset integrity verification failed"); } - printSuccess("Hash verification passed"); + printProgressCheck("Hash verification passed"); return fileHash; } @@ -249,11 +253,7 @@ async function handleIncludeAction(release: GitHubDraftRelease): Promise { // Step 4: Find and select OSS Readme const readmes = findAllReadmeOssLocally(); - const recommendedReadmeOss = getRecommendedReadmeOss( - release.name.split(" ")[0], - release.name.split(" ")[1], - readmes - ); + const recommendedReadmeOss = getRecommendedReadmeOss(release.name, readmes); let readmeToInclude: string; @@ -270,6 +270,8 @@ async function handleIncludeAction(release: GitHubDraftRelease): Promise { readmeToInclude = selectedReadme; } else { + printSuccess(`Auto selected based on release name:`); + printSuccess(`${chalk.bold(basename(recommendedReadmeOss))}`); readmeToInclude = recommendedReadmeOss; } @@ -331,7 +333,7 @@ async function handleIncludeAsEmbeddedAction(release: GitHubDraftRelease, readme // Download MPK to temp folder printProgress(`Downloading ${mpkAsset.name}...`); await gh.downloadReleaseAsset(mpkAsset.id, mpkPath); - printSuccess("Download completed"); + printProgressCheck("Download completed"); // Copy HTML to temp folder const { cp } = await import("../src/shell"); @@ -340,7 +342,7 @@ async function handleIncludeAsEmbeddedAction(release: GitHubDraftRelease, readme // Embed HTML into MPK printProgress("Merging HTML into MPK..."); await includeReadmeOssIntoMpk(htmlPath, mpkPath); - printSuccess("Merge completed"); + printProgressCheck("Merge completed"); // Get modified MPK size const { stat } = await import("node:fs/promises"); @@ -376,12 +378,12 @@ async function handleIncludeAsEmbeddedAction(release: GitHubDraftRelease, readme const backupName = mpkAsset.name.replace(".mpk", "._mpk"); printProgress(`Renaming original MPK to ${backupName}...`); await gh.updateReleaseAsset(mpkAsset.id, backupName); - printSuccess("Original MPK renamed"); + printProgressCheck("Original MPK renamed"); // Upload modified MPK printProgress(`Uploading modified MPK...`); const newMpkAsset = await gh.uploadReleaseAsset(release.id, mpkPath, mpkAsset.name); - printSuccess(`Modified MPK uploaded (ID: ${newMpkAsset.id})`); + printProgressCheck(`Modified MPK uploaded (ID: ${newMpkAsset.id})`); console.log(chalk.bold.green(`\nšŸŽ‰ Successfully embedded OSS Readme into MPK!`)); console.log(chalk.gray(` Release: ${release.name}`)); diff --git a/automation/utils/src/oss-clearance.ts b/automation/utils/src/oss-clearance.ts index c60d49360a..4d96d3e791 100644 --- a/automation/utils/src/oss-clearance.ts +++ b/automation/utils/src/oss-clearance.ts @@ -16,12 +16,14 @@ export function findAllReadmeOssLocally(): string[] { return matchingFiles1.concat(matchingFiles2); } -export function getRecommendedReadmeOss( - packageName: string, - packageVersion: string, - availableReadmes: string[] -): string | undefined { - const fileNames = availableReadmes.map(r => [basename(r), r]); +export function getRecommendedReadmeOss(packageNameAndVersion: string, availableReadmes: string[]): string | undefined { + const fileNames = availableReadmes.map(r => [basename(r).toLowerCase(), r]); + + const nameParts = packageNameAndVersion.split(" "); + const version = nameParts.pop()!; + + const packageName = nameParts.join("").toLowerCase(); + const packageVersion = version.replace("v", ""); return fileNames.find(([name]) => name.includes(packageName) && name.includes(packageVersion))?.at(1); }