UNPKG

@puls-atlas/cli

Version:

The Puls Atlas CLI tool for managing Atlas projects

159 lines 4.39 kB
import chalk from 'chalk'; import inquirer from 'inquirer'; import { warnIfNotReleaseBranch } from '../../utils/git.js'; import { requireFirebaseJson, resolveFirestoreRulesSourceLabel, selectProject } from '../../utils/firebase.js'; import { logger } from '../../utils/logger.js'; import { execSync } from '../../utils/index.js'; const FIRESTORE_RULES_DEPLOY_TARGET = 'firestore:rules'; const outputDeploymentSummary = ({ loggerImpl = logger, projectId, rulesSourceLabel }) => { loggerImpl.summary('Deployment plan', [{ label: 'Consumer project', value: projectId, tone: 'warning' }, { label: 'Deploy target', value: 'Firestore rules', tone: 'accent' }, { label: 'Source', value: rulesSourceLabel, tone: 'warning' }], { spacing: 'after' }); }; const outputDeploymentOutcomeSummary = ({ loggerImpl = logger, projectId, rulesSourceLabel }) => { loggerImpl.summary('Deployment outcome', [{ label: 'Consumer project', value: projectId, tone: 'warning' }, { label: 'Deploy target', value: 'Firestore rules', tone: 'accent' }, { label: 'Source', value: rulesSourceLabel, tone: 'warning' }, { label: 'Status', value: 'deployed', tone: 'success' }], { spacing: 'after' }); }; const confirmRulesDeployment = async ({ projectId, promptImpl = inquirer.prompt, rulesSourceLabel }) => { const { isConfirmed } = await promptImpl([{ type: 'confirm', name: 'isConfirmed', default: false, message: `Deploy Firestore rules from ${chalk.cyan(rulesSourceLabel)} ` + `to consumer project ${chalk.bold(projectId)}?` }]); return isConfirmed; }; export const createDeployRulesHandler = (dependencies = {}) => { const { execSyncImpl = execSync, loggerImpl = logger, promptImpl = inquirer.prompt, requireFirebaseJsonImpl = requireFirebaseJson, resolveFirestoreRulesSourceLabelImpl = resolveFirestoreRulesSourceLabel, selectProjectImpl = selectProject, warnIfNotReleaseBranchImpl = warnIfNotReleaseBranch } = dependencies; return async (options = {}) => { try { warnIfNotReleaseBranchImpl({ loggerImpl }); const { firestore, storage } = options; if (storage && !firestore) { loggerImpl.warning('Storage rules are not yet supported.'); return false; } const { projectId } = await selectProjectImpl('.firebaserc', { promptMessage: 'Select a Google Cloud consumer project to deploy Firestore rules to:' }); const firebaseJson = requireFirebaseJsonImpl(); const rulesSourceLabel = resolveFirestoreRulesSourceLabelImpl(firebaseJson); if (!rulesSourceLabel) { loggerImpl.error('No Firestore rules configuration found in firebase.json.', { exit: true, exitCode: 1 }); return false; } outputDeploymentSummary({ loggerImpl, projectId, rulesSourceLabel }); const isConfirmed = await confirmRulesDeployment({ projectId, promptImpl, rulesSourceLabel }); if (!isConfirmed) { loggerImpl.warning('Deployment cancelled by the user.'); return false; } const spinner = loggerImpl.spinner('Deploying Firestore rules...'); try { execSyncImpl('firebase deploy', { only: FIRESTORE_RULES_DEPLOY_TARGET, project: projectId, stdio: 'inherit' }); spinner.succeed('Firestore rules deployed successfully.'); } catch (error) { spinner.fail('Deployment failed. See the error above for details.'); loggerImpl.error(error, { exit: true, exitCode: 1 }); return false; } outputDeploymentOutcomeSummary({ loggerImpl, projectId, rulesSourceLabel }); 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 createDeployRulesHandler();