UNPKG

@puls-atlas/cli

Version:

The Puls Atlas CLI tool for managing Atlas projects

153 lines 6.66 kB
import * as features from '../../utils/feature.js'; import { resolveSyncReleaseTarget } from './release.js'; import { getAtlasGeneratedFeatureConfigPath, loadAtlasFeatureCache, logger, readJsonFile } from '../../utils/index.js'; import { createSyncReadAliasEntryRows, createSyncReadAliasSummaryRows, createSyncSchemaPlanSummaryRows } from './schemaPlan.js'; const formatReleaseValue = value => value ? value : 'not set'; const formatBooleanValue = value => { if (value === true) { return 'yes'; } if (value === false) { return 'no'; } return 'not set'; }; const formatRoutingTargetValue = routingTarget => { if (!routingTarget) { return 'not set'; } if (routingTarget.dataset && routingTarget.table) { return `${routingTarget.target ?? 'unknown'} (${routingTarget.dataset}.${routingTarget.table})`; } if (routingTarget.schema && routingTarget.table) { return `${routingTarget.target ?? 'unknown'} (${routingTarget.schema}.${routingTarget.table})`; } return routingTarget.target ?? 'not set'; }; const createPipelineRoutingEntries = runtimeConfig => { if (!Array.isArray(runtimeConfig?.pipelines) || runtimeConfig.pipelines.length === 0) { return []; } return runtimeConfig.pipelines.map(pipeline => { const routing = pipeline?.destination?.routing ?? {}; const writeTargets = Array.isArray(routing.writeTargets) ? routing.writeTargets.map(formatRoutingTargetValue).join(', ') : ''; return `${pipeline.workloadKey}: read=${formatRoutingTargetValue(routing.read)}, write=${formatRoutingTargetValue(routing.write)}, writeTargets=${writeTargets || 'not set'}, backfill=${formatRoutingTargetValue(routing.backfill)}`; }); }; export const showSyncPromoteStatus = async (options = {}, dependencies = {}, cwd = process.cwd()) => { const getAtlasGeneratedFeatureConfigPathImpl = dependencies.getAtlasGeneratedFeatureConfigPath ?? getAtlasGeneratedFeatureConfigPath; const loadFeatureContextImpl = dependencies.loadFeatureContext ?? features.loadFeatureContext; const loadFeatureCacheImpl = dependencies.loadFeatureCache ?? loadAtlasFeatureCache; const loggerImpl = dependencies.logger ?? logger; const readJsonFileImpl = dependencies.readJsonFile ?? readJsonFile; const exit = dependencies.exit ?? (code => process.exit(code)); let spinner; try { spinner = loggerImpl.spinner('Loading Atlas sync promotion status...'); const context = await loadFeatureContextImpl('sync', options, { cwd }); const cacheArtifact = loadFeatureCacheImpl('sync', context.projectId, cwd); const runtimeConfigPath = getAtlasGeneratedFeatureConfigPathImpl('sync', context.projectId, cwd); const runtimeConfig = readJsonFileImpl(runtimeConfigPath, { allowMissing: true }); const release = cacheArtifact.cache?.release ?? runtimeConfig?.release ?? null; const releaseTarget = cacheArtifact.cache?.releaseTarget ?? runtimeConfig?.releaseTarget ?? resolveSyncReleaseTarget(release); const rollout = cacheArtifact.cache?.rollout ?? runtimeConfig?.rollout ?? null; const readAliasPlan = cacheArtifact.cache?.readAliasPlan ?? runtimeConfig?.readAliasPlan ?? null; const schemaPlan = cacheArtifact.cache?.schemaPlan ?? runtimeConfig?.schemaPlan ?? null; spinner.succeed('Atlas sync promotion status loaded.'); loggerImpl.summary('Promotion status', [{ label: 'Project', value: context.projectId }, context.environment ? { label: 'Environment', value: context.environment } : null, { label: 'Config', value: context.configPath }, { label: 'Local cache', value: cacheArtifact.cache ? cacheArtifact.filePath : 'missing' }, { label: 'Runtime config', value: runtimeConfig ? runtimeConfigPath : 'not generated' }, { label: 'Release strategy', value: releaseTarget.strategy }, { label: 'Active release', value: formatReleaseValue(releaseTarget.active) }, { label: 'Candidate release', value: formatReleaseValue(releaseTarget.candidate) }, { label: 'Promotion target', value: releaseTarget.target }, { label: 'Target release id', value: formatReleaseValue(releaseTarget.releaseId) }, { label: 'Rollout mode', value: rollout?.mode ?? 'not set' }, { label: 'Read target', value: rollout?.readTarget ?? 'not set' }, { label: 'Write target', value: rollout?.writeTarget ?? 'not set' }, { label: 'Backfill target', value: rollout?.backfillTarget ?? 'not required' }, { label: 'Requires cutover', value: formatBooleanValue(rollout?.requiresCutover) }, { label: 'Config fingerprint', value: formatReleaseValue(rollout?.configFingerprint) }, { label: 'Active fingerprint', value: formatReleaseValue(rollout?.activeConfigFingerprint) }, { label: 'Candidate fingerprint', value: formatReleaseValue(rollout?.candidateConfigFingerprint) }, runtimeConfig?.pipelines ? { label: 'Enabled workloads', value: runtimeConfig.pipelines.length } : null, ...createSyncReadAliasSummaryRows(readAliasPlan), ...createSyncSchemaPlanSummaryRows(schemaPlan)]); const pipelineRoutingEntries = createPipelineRoutingEntries(runtimeConfig); if (pipelineRoutingEntries.length > 0) { loggerImpl.section('Pipeline routing', pipelineRoutingEntries); } if (readAliasPlan?.entries?.length > 0) { loggerImpl.summary('BigQuery read aliases', createSyncReadAliasEntryRows(readAliasPlan)); } if (!cacheArtifact.cache) { loggerImpl.warning('Atlas sync promotion status is missing the local rollout cache. Run "atlas sync apply" to materialize or refresh the local release state.'); } if (!runtimeConfig) { loggerImpl.warning('Atlas sync promotion status could not find a generated runtime config. Run "atlas sync apply" before inspecting pipeline routing.'); } if (rollout?.requiresCutover === true) { loggerImpl.warning('Atlas sync candidate release still requires cutover. Promote it with "atlas sync promote" after the candidate backfill has completed successfully.'); } return { cacheArtifact, configPath: context.configPath, releaseTarget, rollout, readAliasPlan, runtimeConfig, schemaPlan, status: 'loaded' }; } catch (error) { if (spinner) { spinner.fail('Failed to load Atlas sync promotion status.'); } loggerImpl.error(error.message, false); return exit(1); } }; export default async options => showSyncPromoteStatus(options);