UNPKG

@soleil-se/run

Version:

Run various utility scripts for creating apps, configs or migration tasks.

151 lines (139 loc) 6.08 kB
import { readFileSync, readdirSync, statSync } from 'fs'; import chalk from 'chalk'; import path from 'path'; import config from '@soleil-se/build-config'; import getAddonVersions from './install-check/getAddonVersions.js'; // Config files project.config/user.config can include settings to exclude apps from install checks // This array of strings is provided in property `installCheckExcludedApps`. const { installCheckExcludedApps } = config.env; const MAINPATH = '.'; /** * Recursively traverses a directory and collects all file paths. * @param {string} dir - The directory to traverse. * @param {string[]} fileList - The list of collected file paths this far. * @returns The list of collected file paths. */ function traverseDirectory(dir, fileList = []) { const files = readdirSync(dir); files.forEach((file) => { const filePath = path.join(dir, file); const stats = statSync(filePath); if (stats.isDirectory()) { // Skip dist and node_modules directories if (file === 'dist' || file === 'node_modules') { return; } traverseDirectory(filePath, fileList); } else { fileList.push(filePath); } }); return fileList; } /** * Retrieves the manifest files of repository applications by traversing the main path, * filtering for files ending with 'manifest.json', and checking if their type is * 'WebApp', 'RESTApp', or 'Widget'. * * @returns {string[]} An array of manifest file paths containing valid application manifests. */ function getRepoApps() { const files = traverseDirectory(MAINPATH); return files .filter((file) => { if (file.endsWith('manifest.json')) { const { type } = JSON.parse(readFileSync(file)); return type === 'WebApp' || type === 'RESTApp' || type === 'Widget'; } return false; }); } /** * Compares the versions of repository apps with the installed addons and categorizes them. * * @param {Array<Object>} repositoryApps - List of repository app objects. * @param {Array<Object>} installedAddons - List of installed addon objects. * @returns {Object} An object containing: * - {Array<Object>} notInstalled - Repository apps that are not installed. * - {Array<Object>} versionMismatches - Repository apps whose installed version does not match * the repository version. Each object includes `installedVersion`. * - {Array<Object>} excluded - Repository apps that are excluded from installation checks. */ function compareVersions(repositoryApps, installedAddons) { // Compare the versions of the repository apps with the installed addons // and collect them into the three lists of not installed, version mismatches, and excluded. return repositoryApps.reduce( ({ notInstalled, versionMismatches, excluded }, repoApp) => { const installedAddon = installedAddons.find((addon) => addon.appIdentifier === repoApp.id); // Add the app to the appropriate list based on its status if (installedAddon) { if (repoApp.version !== installedAddon.version) { versionMismatches.push({ ...repoApp, installedVersion: installedAddon.version }); } } else if (!installCheckExcludedApps || !installCheckExcludedApps.includes(repoApp.id)) { notInstalled.push(repoApp); } else { excluded.push(repoApp); } return { notInstalled, versionMismatches, excluded }; }, // The starting empty buckets { notInstalled: [], versionMismatches: [], excluded: [] }, ); } /** * Checks the repository for available apps, compares them with installed addons, * and logs the status of each app (installed, version mismatches, not installed, or excluded). * * - Lists the number of apps by type found in the repository. * - Compares repository apps with installed addon versions. * - Logs details about version mismatches, missing installations, and excluded apps. * * @returns {Promise<void>} Resolves when the check is complete and all results are logged. */ export default async function installCheck() { console.log('Checking for apps in repository...'); const apps = getRepoApps().map((filePath) => { const appInfo = JSON.parse(readFileSync(filePath, 'utf-8')); return { id: appInfo.id, version: appInfo.version, name: appInfo.name.sv || appInfo.name.en || appInfo.name, type: appInfo.type, }; }); // Get the count of each type of apps const appCounts = apps.reduce((acc, curr) => { acc[curr.type] = acc[curr.type] ? acc[curr.type] + 1 : 1; return acc; }, {}); Object.keys(appCounts).forEach((key) => { console.log(`${chalk.blue(`Found ${appCounts[key]} ${key}s in the repository.`)}`); }); console.log('\nChecking for installed apps...'); const addonVersions = await getAddonVersions(); const diff = compareVersions(apps, addonVersions); if (diff.versionMismatches.length === 0 && diff.notInstalled.length === 0) { console.log(chalk.green('All apps are installed and up to date as addons.')); } if (diff.versionMismatches.length > 0) { const logText = `${diff.versionMismatches.length} app${diff.versionMismatches.length > 1 ? 's' : ''} have version mismatches.`; console.log(`\n${chalk.redBright(logText)}`); console.log('-'.repeat(logText.length)); diff.versionMismatches.forEach((app) => { console.log(`${app.name} (${app.id})\n${chalk.redBright(`Available: ${app.version}, Installed: ${app.installedVersion}`)}`); }); } if (diff.notInstalled.length > 0) { const logText = `${diff.notInstalled.length} app${diff.notInstalled.length > 1 ? 's' : ''} are not installed as addons.`; console.log(`\n${chalk.yellow(logText)}`); console.log('-'.repeat(logText.length)); diff.notInstalled.forEach((app) => { console.log(`${app.name} (${app.id})`); }); } if (diff.excluded.length > 0) { const logText = `!Note that ${diff.excluded.length} app${diff.excluded.length > 1 ? 's' : ''} are excluded from the install check.`; console.log(`\n${chalk.blue(logText)}`); } }