@puls-atlas/cli
Version:
The Puls Atlas CLI tool for managing Atlas projects
151 lines • 4.22 kB
JavaScript
import chalk from 'chalk';
import inquirer from 'inquirer';
import { warnIfNotReleaseBranch } from '../../utils/git.js';
import { requireFirebaseJson, resolveFirestoreIndexesSourceLabel, selectProject } from '../../utils/firebase.js';
import { logger } from '../../utils/logger.js';
import { execSync } from '../../utils/index.js';
const FIRESTORE_INDEXES_DEPLOY_TARGET = 'firestore:indexes';
const outputDeploymentSummary = ({
indexesSourceLabel,
loggerImpl = logger,
projectId
}) => {
loggerImpl.summary('Deployment plan', [{
label: 'Consumer project',
value: projectId,
tone: 'warning'
}, {
label: 'Deploy target',
value: 'Firestore indexes',
tone: 'accent'
}, {
label: 'Source',
value: indexesSourceLabel,
tone: 'warning'
}], {
spacing: 'after'
});
};
const outputDeploymentOutcomeSummary = ({
indexesSourceLabel,
loggerImpl = logger,
projectId
}) => {
loggerImpl.summary('Deployment outcome', [{
label: 'Consumer project',
value: projectId,
tone: 'warning'
}, {
label: 'Deploy target',
value: 'Firestore indexes',
tone: 'accent'
}, {
label: 'Source',
value: indexesSourceLabel,
tone: 'warning'
}, {
label: 'Status',
value: 'deployed',
tone: 'success'
}], {
spacing: 'after'
});
};
const confirmIndexesDeployment = async ({
indexesSourceLabel,
projectId,
promptImpl = inquirer.prompt
}) => {
const {
isConfirmed
} = await promptImpl([{
type: 'confirm',
name: 'isConfirmed',
default: false,
message: `Deploy Firestore indexes from ${chalk.cyan(indexesSourceLabel)} ` + `to consumer project ${chalk.bold(projectId)}?`
}]);
return isConfirmed;
};
export const createDeployIndexesHandler = (dependencies = {}) => {
const {
execSyncImpl = execSync,
loggerImpl = logger,
promptImpl = inquirer.prompt,
requireFirebaseJsonImpl = requireFirebaseJson,
resolveFirestoreIndexesSourceLabelImpl = resolveFirestoreIndexesSourceLabel,
selectProjectImpl = selectProject,
warnIfNotReleaseBranchImpl = warnIfNotReleaseBranch
} = dependencies;
return async () => {
try {
warnIfNotReleaseBranchImpl({
loggerImpl
});
const {
projectId
} = await selectProjectImpl('.firebaserc', {
promptMessage: 'Select a Google Cloud consumer project to deploy indexes to:'
});
const firebaseJson = requireFirebaseJsonImpl();
const indexesSourceLabel = resolveFirestoreIndexesSourceLabelImpl(firebaseJson);
if (!indexesSourceLabel) {
loggerImpl.error('No Firestore indexes configuration found in firebase.json.', {
exit: true,
exitCode: 1
});
return false;
}
outputDeploymentSummary({
indexesSourceLabel,
loggerImpl,
projectId
});
const isConfirmed = await confirmIndexesDeployment({
indexesSourceLabel,
projectId,
promptImpl
});
if (!isConfirmed) {
loggerImpl.warning('Deployment cancelled by the user.');
return false;
}
const spinner = loggerImpl.spinner('Deploying Firestore indexes...');
try {
execSyncImpl('firebase deploy', {
only: FIRESTORE_INDEXES_DEPLOY_TARGET,
project: projectId,
stdio: 'inherit'
});
spinner.succeed('Firestore indexes deployed successfully.');
} catch (error) {
spinner.fail('Deployment failed. See the error above for details.');
loggerImpl.error(error, {
exit: true,
exitCode: 1
});
return false;
}
outputDeploymentOutcomeSummary({
indexesSourceLabel,
loggerImpl,
projectId
});
loggerImpl.success('Done!');
return true;
} catch (error) {
if (error instanceof Error && error.name === 'ExitPromptError') {
loggerImpl.error('Deployment cancelled by the user.', {
exit: true,
exitCode: 130
});
return false;
}
loggerImpl.error(error, {
exit: true,
exitCode: 1
});
return false;
}
};
};
export default createDeployIndexesHandler();