@redocly/cli
Version:
[@Redocly](https://redocly.com) CLI is your all-in-one API documentation utility. It builds, manages, improves, and quality-checks your API descriptions, all of which comes in handy for various phases of the API Lifecycle. Create your own rulesets to make
199 lines • 8.56 kB
JavaScript
import * as colors from 'colorette';
import { logger } from '@redocly/openapi-core';
import { printExecutionTime, capitalize } from '../../utils/miscellaneous.js';
import { Spinner } from '../../utils/spinner.js';
import { DeploymentError } from '../utils.js';
import { ReuniteApi, getApiKeys, getDomain } from '../api/index.js';
import { handleReuniteError, retryUntilConditionMet } from './utils.js';
const RETRY_INTERVAL_MS = 5000; // 5 sec
export async function handlePushStatus({ argv, }) {
const startedAt = performance.now();
const spinner = new Spinner();
const { organization, project: projectId, pushId, wait } = argv;
const domain = argv.domain || getDomain();
const maxExecutionTime = argv['max-execution-time'] || 1200; // 20 min
const retryIntervalMs = argv['retry-interval']
? argv['retry-interval'] * 1000
: RETRY_INTERVAL_MS;
const startTime = argv['start-time'] || Date.now();
const retryTimeoutMs = maxExecutionTime * 1000;
const continueOnDeployFailures = argv['continue-on-deploy-failures'] || false;
try {
const apiKey = getApiKeys();
const client = new ReuniteApi({ domain, apiKey, command: 'push-status' });
let pushResponse;
pushResponse = await retryUntilConditionMet({
operation: () => client.remotes.getPush({
organizationId: organization,
projectId,
pushId,
}),
condition: wait
? // Keep retrying if status is "pending" or "running" (returning false, so the operation will be retried)
(result) => !['pending', 'running'].includes(result.status['preview'].deploy.status)
: null,
onConditionNotMet: (lastResult) => {
displayDeploymentAndBuildStatus({
status: lastResult.status['preview'].deploy.status,
url: lastResult.status['preview'].deploy.url,
spinner,
buildType: 'preview',
continueOnDeployFailures,
wait,
});
},
onRetry: (lastResult) => {
if (argv.onRetry) {
argv.onRetry({
preview: lastResult.status.preview,
production: lastResult.isMainBranch ? lastResult.status.production : null,
commit: lastResult.commit,
});
}
},
startTime,
retryTimeoutMs,
retryIntervalMs,
});
printPushStatus({
buildType: 'preview',
spinner,
wait,
push: pushResponse,
continueOnDeployFailures,
});
printScorecard(pushResponse.status.preview.scorecard);
const shouldWaitForProdDeployment = pushResponse.isMainBranch &&
(wait ? pushResponse.status.preview.deploy.status === 'success' : true);
if (shouldWaitForProdDeployment) {
pushResponse = await retryUntilConditionMet({
operation: () => client.remotes.getPush({
organizationId: organization,
projectId,
pushId,
}),
condition: wait
? // Keep retrying if status is "pending" or "running" (returning false, so the operation will be retried)
(result) => !['pending', 'running'].includes(result.status['production'].deploy.status)
: null,
onConditionNotMet: (lastResult) => {
displayDeploymentAndBuildStatus({
status: lastResult.status['production'].deploy.status,
url: lastResult.status['production'].deploy.url,
spinner,
buildType: 'production',
continueOnDeployFailures,
wait,
});
},
onRetry: (lastResult) => {
if (argv.onRetry) {
argv.onRetry({
preview: lastResult.status.preview,
production: lastResult.isMainBranch ? lastResult.status.production : null,
commit: lastResult.commit,
});
}
},
startTime,
retryTimeoutMs,
retryIntervalMs,
});
}
if (pushResponse.isMainBranch) {
printPushStatus({
buildType: 'production',
spinner,
wait,
push: pushResponse,
continueOnDeployFailures,
});
printScorecard(pushResponse.status.production.scorecard);
}
printPushStatusInfo({ organization, projectId, pushId, startedAt });
client.reportSunsetWarnings();
const summary = {
preview: pushResponse.status.preview,
production: pushResponse.isMainBranch ? pushResponse.status.production : null,
commit: pushResponse.commit,
};
return summary;
}
catch (err) {
spinner.stop(); // Spinner can block process exit, so we need to stop it explicitly.
handleReuniteError('✗ Failed to get push status.', err);
}
finally {
spinner.stop(); // Spinner can block process exit, so we need to stop it explicitly.
}
}
function printPushStatusInfo({ organization, projectId, pushId, startedAt, }) {
logger.info(`\nProcessed push-status for ${colors.yellow(organization)}, ${colors.yellow(projectId)} and pushID ${colors.yellow(pushId)}.\n`);
printExecutionTime('push-status', startedAt, 'Finished');
}
function printPushStatus({ buildType, spinner, push, continueOnDeployFailures, }) {
if (!push) {
return;
}
if (push.isOutdated || !push.hasChanges) {
logger.warn(`Files not added to your project. Reason: ${push.isOutdated ? 'outdated' : 'no changes'}.\n`);
}
else {
displayDeploymentAndBuildStatus({
status: push.status[buildType].deploy.status,
url: push.status[buildType].deploy.url,
buildType,
spinner,
continueOnDeployFailures,
});
}
}
function printScorecard(scorecard) {
if (!scorecard || scorecard.length === 0) {
return;
}
logger.output(`\n${colors.magenta('Scorecard')}:`);
for (const scorecardItem of scorecard) {
logger.output(`
${colors.magenta('Name')}: ${scorecardItem.name}
${colors.magenta('Status')}: ${scorecardItem.status}
${colors.magenta('URL')}: ${colors.cyan(scorecardItem.url)}
${colors.magenta('Description')}: ${scorecardItem.description}\n`);
}
logger.output(`\n`);
}
function displayDeploymentAndBuildStatus({ status, url, spinner, buildType, continueOnDeployFailures, wait, }) {
const message = getMessage({ status, url, buildType, wait });
if (status === 'failed' && !continueOnDeployFailures) {
spinner.stop();
throw new DeploymentError(message);
}
if (wait && (status === 'pending' || status === 'running')) {
return spinner.start(message);
}
spinner.stop();
return logger.output(message);
}
function getMessage({ status, url, buildType, wait, }) {
switch (status) {
case 'skipped':
return `${colors.yellow(`Skipped ${buildType}`)}\n`;
case 'pending': {
const message = `${colors.yellow(`Pending ${buildType}`)}`;
return wait ? message : `Status: ${message}\n`;
}
case 'running': {
const message = `${colors.yellow(`Running ${buildType}`)}`;
return wait ? message : `Status: ${message}\n`;
}
case 'success':
return `${colors.green(`🚀 ${capitalize(buildType)} deploy success.`)}\n${colors.magenta(`${capitalize(buildType)} URL`)}: ${colors.cyan(url || 'No URL yet.')}\n`;
case 'failed':
return `${colors.red(`❌ ${capitalize(buildType)} deploy fail.`)}\n${colors.magenta(`${capitalize(buildType)} URL`)}: ${colors.cyan(url || 'No URL yet.')}`;
default: {
const message = `${colors.yellow(`No status yet for ${buildType} deploy`)}`;
return wait ? message : `Status: ${message}\n`;
}
}
}
//# sourceMappingURL=push-status.js.map