@puls-atlas/cli
Version:
The Puls Atlas CLI tool for managing Atlas projects
135 lines • 5.13 kB
JavaScript
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}`);
}
};