UNPKG

@puls-atlas/cli

Version:

The Puls Atlas CLI tool for managing Atlas projects

135 lines 5.13 kB
import fs from 'fs'; import path from 'path'; import inquirer from 'inquirer'; import { rimraf } from 'rimraf'; import { execSync } from './shell.js'; import { logger } from './logger.js'; import { normalizeOptionalString } from './value.js'; const getNodeModulesPath = cwd => path.join(cwd, 'node_modules'); const GOOGLE_ARTIFACT_REGISTRY_AUTH_PACKAGE = 'google-artifactregistry-auth'; const GOOGLE_ARTIFACT_REGISTRY_AUTH_COMMAND = `npx ${GOOGLE_ARTIFACT_REGISTRY_AUTH_PACKAGE}`; const GOOGLE_ARTIFACT_REGISTRY_INSTALL_COMMAND = `npm install -g ${GOOGLE_ARTIFACT_REGISTRY_AUTH_PACKAGE}`; const MISSING_COMMAND_ERROR_MESSAGES = ['command not found', 'is not recognized as the name of a cmdlet', 'not recognized as an internal or external command']; const createRemovalSpinner = (loggerImpl = logger) => loggerImpl.spinner('Removing node_modules directory...'); const createArtifactRegistryAuthSpinner = (loggerImpl = logger) => loggerImpl.spinner('Authenticating with Google Artifact Registry...'); const createArtifactRegistryInstallSpinner = (loggerImpl = logger) => loggerImpl.spinner(`Installing ${GOOGLE_ARTIFACT_REGISTRY_AUTH_PACKAGE}...`); const runArtifactRegistryAuthentication = execSyncImpl => execSyncImpl(GOOGLE_ARTIFACT_REGISTRY_AUTH_COMMAND, { stdio: 'pipe' }); const installArtifactRegistryAuthenticationDependency = execSyncImpl => execSyncImpl(GOOGLE_ARTIFACT_REGISTRY_INSTALL_COMMAND, { stdio: 'pipe' }); const isMissingArtifactRegistryAuthDependency = error => { if (error?.code === 'ENOENT') { return true; } const normalizedMessage = normalizeOptionalString(error?.message)?.toLowerCase(); if (!normalizedMessage) { return false; } return MISSING_COMMAND_ERROR_MESSAGES.some(message => normalizedMessage.includes(message)); }; export const authenticateWithGoogleArtifactRegistry = (options = {}, dependencies = {}) => { const { onAuthenticated } = options; const { execSyncImpl = execSync, loggerImpl = logger } = dependencies; const initialSpinner = createArtifactRegistryAuthSpinner(loggerImpl); try { runArtifactRegistryAuthentication(execSyncImpl); initialSpinner.succeed('Authenticated with Google Artifact Registry.'); if (typeof onAuthenticated === 'function') { onAuthenticated(); } return { didInstallDependency: false }; } catch (error) { if (!isMissingArtifactRegistryAuthDependency(error)) { initialSpinner.fail('Authentication with Google Artifact Registry failed.'); throw error; } } initialSpinner.stop(); loggerImpl.warning(`${GOOGLE_ARTIFACT_REGISTRY_AUTH_PACKAGE} is not installed. Installing now...`); const installSpinner = createArtifactRegistryInstallSpinner(loggerImpl); try { installArtifactRegistryAuthenticationDependency(execSyncImpl); installSpinner.succeed(`${GOOGLE_ARTIFACT_REGISTRY_AUTH_PACKAGE} installed successfully.`); } catch (error) { installSpinner.fail(`Failed to install ${GOOGLE_ARTIFACT_REGISTRY_AUTH_PACKAGE}.`); throw error; } const retrySpinner = createArtifactRegistryAuthSpinner(loggerImpl); try { runArtifactRegistryAuthentication(execSyncImpl); retrySpinner.succeed('Authenticated with Google Artifact Registry.'); if (typeof onAuthenticated === 'function') { onAuthenticated(); } return { didInstallDependency: true }; } catch (error) { retrySpinner.fail('Authentication with Google Artifact Registry failed.'); throw error; } }; export const installNodeDependencies = async (cwd, options = {}, dependencies = {}) => { const { execSyncImpl = execSync, existsSyncImpl = fs.existsSync, loggerImpl = logger, promptImpl = inquirer.prompt, rimrafSyncImpl = rimraf.sync } = dependencies; const nodeModulesPath = getNodeModulesPath(cwd); const hasNodeModules = existsSyncImpl(nodeModulesPath); const { allYes = false } = options; const { removeNodeModules = false } = hasNodeModules ? allYes ? { removeNodeModules: false } : await promptImpl([{ type: 'confirm', name: 'removeNodeModules', default: false, message: 'Do you want to perform an install with a fresh node_modules directory?' }]) : {}; if (removeNodeModules) { const removingNodeModules = createRemovalSpinner(loggerImpl); try { rimrafSyncImpl(nodeModulesPath); removingNodeModules.succeed('Removed node_modules directory.'); } catch (error) { removingNodeModules.fail('Failed to remove node_modules directory.'); throw new Error(`Failed to remove node_modules directory in ${cwd}. ${error.message}`); } } try { return execSyncImpl('npm i', { ...options, cwd }); } catch (error) { throw new Error(`npm install failed in ${cwd}. ${error.message}`); } }; export const cleanInstallNodeDependencies = async (cwd, options = {}, dependencies = {}) => { const { execSyncImpl = execSync } = dependencies; try { return execSyncImpl('npm ci', { ...options, cwd }); } catch (error) { throw new Error(`npm ci failed in ${cwd}. ${error.message}`); } };