wgc
Version:
The official CLI tool to manage the GraphQL Federation Platform Cosmo
231 lines • 10.8 kB
JavaScript
import { EnumStatusCode } from '@wundergraph/cosmo-connect/dist/common/common_pb';
import Table from 'cli-table3';
import logSymbols from 'log-symbols';
import pc from 'picocolors';
/**
* Shared handler for proposal command responses (both create and update).
* Displays schema changes, composition errors, and other issues.
*/
export const handleProposalResult = (resp, proposalName, isCreate = false) => {
var _a, _b, _c, _d, _e, _f;
const changesTable = new Table({
head: [
pc.bold(pc.white('SUBGRAPH_NAME')),
pc.bold(pc.white('CHANGE')),
pc.bold(pc.white('TYPE')),
pc.bold(pc.white('DESCRIPTION')),
],
wordWrap: true,
});
const compositionErrorsTable = new Table({
head: [pc.bold(pc.white('ERROR_MESSAGE'))],
colWidths: [120],
wordWrap: true,
});
const compositionWarningsTable = new Table({
head: [pc.bold(pc.white('WARNING_MESSAGE'))],
colWidths: [120],
wordWrap: true,
});
const lintIssuesTable = new Table({
head: [
pc.bold(pc.white('SUBGRAPH_NAME')),
pc.bold(pc.white('LINT_RULE')),
pc.bold(pc.white('ERROR_MESSAGE')),
pc.bold(pc.white('LINE NUMBER')),
],
colAligns: ['left', 'left', 'center'],
wordWrap: true,
});
const graphPruningIssuesTable = new Table({
head: [
pc.bold(pc.white('SUBGRAPH_NAME')),
pc.bold(pc.white('RULE')),
pc.bold(pc.white('FIELD_PATH')),
pc.bold(pc.white('MESSAGE')),
pc.bold(pc.white('LINE NUMBER')),
],
colAligns: ['left', 'left', 'left', 'center'],
wordWrap: true,
});
let success = false;
let finalStatement = '';
let successMessage = '';
let studioCheckUrl = '';
if (resp.checkUrl) {
studioCheckUrl = `${pc.bold('Open in studio')}: ${resp.checkUrl}`;
}
if (((_a = resp.response) === null || _a === void 0 ? void 0 : _a.code) === EnumStatusCode.OK) {
successMessage = isCreate
? pc.green(`Proposal '${proposalName}' was created successfully.`)
: pc.green(`Proposal '${proposalName}' was updated successfully.`);
}
else {
return {
success: false,
message: ((_b = resp.response) === null || _b === void 0 ? void 0 : _b.details)
? pc.red(pc.bold(resp.response.details))
: pc.red(`Failed to ${isCreate ? 'create' : 'update'} proposal.`),
};
}
// Handle successful response
if (resp.nonBreakingChanges.length === 0 &&
resp.breakingChanges.length === 0 &&
resp.compositionErrors.length === 0 &&
resp.lintErrors.length === 0 &&
resp.lintWarnings.length === 0 &&
resp.graphPruneErrors.length === 0 &&
resp.graphPruneWarnings.length === 0) {
console.log(`\nDetected no changes.\nDetected no lint issues.\nDetected no graph pruning issues.\n\n${studioCheckUrl}\n`);
success = true;
return { success: true, message: successMessage };
}
console.log(`\nChecking the proposed schema`);
// No operations usage stats mean the check was not performed against any live traffic
if (resp.operationUsageStats) {
if (resp.operationUsageStats.totalOperations === 0) {
// Composition errors are still considered failures, otherwise we can consider this a success
// because no operations were affected by the change
success =
resp.compositionErrors.length === 0 && resp.lintErrors.length === 0 && resp.graphPruneErrors.length === 0;
console.log(`No operations were affected by this schema change.`);
finalStatement = `This schema change didn't affect any operations from existing client traffic.`;
}
else if (resp.operationUsageStats.totalOperations === resp.operationUsageStats.safeOperations) {
// This is also a success because changes to these operations were marked as safe
success =
resp.compositionErrors.length === 0 && resp.lintErrors.length === 0 && resp.graphPruneErrors.length === 0;
console.log(`${resp.operationUsageStats.totalOperations} operations were considered safe due to overrides.`);
finalStatement = `This schema change affected operations with safe overrides.`;
}
else {
// Composition and breaking errors are considered failures because operations were affected by the change
success =
resp.breakingChanges.length === 0 &&
resp.compositionErrors.length === 0 &&
resp.lintErrors.length === 0 &&
resp.graphPruneErrors.length === 0;
const { breakingChanges, operationUsageStats } = resp;
const { totalOperations, safeOperations, firstSeenAt, lastSeenAt } = operationUsageStats;
if (breakingChanges.length > 0) {
const warningMessage = [logSymbols.warning, ` Found ${pc.bold(breakingChanges.length)} breaking changes.`];
if (totalOperations > 0) {
warningMessage.push(`${pc.bold(totalOperations - safeOperations)} operations impacted.`);
}
if (safeOperations > 0) {
warningMessage.push(`In addition, ${safeOperations} operations marked safe due to overrides.`);
}
console.log(warningMessage.join(''));
finalStatement = `This check has encountered ${pc.bold(`${breakingChanges.length}`)} breaking changes that would break operations from existing client traffic.`;
}
}
}
if (resp.nonBreakingChanges.length > 0 || resp.breakingChanges.length > 0) {
console.log('\nDetected the following changes:');
if (resp.breakingChanges.length > 0) {
for (const breakingChange of resp.breakingChanges) {
changesTable.push([
breakingChange.subgraphName || '-',
`${logSymbols.error} ${pc.red('BREAKING')}`,
breakingChange.changeType,
breakingChange.message,
]);
}
}
if (resp.nonBreakingChanges.length > 0) {
for (const nonBreakingChange of resp.nonBreakingChanges) {
changesTable.push([
nonBreakingChange.subgraphName || '-',
`${logSymbols.success} NON-BREAKING`,
nonBreakingChange.changeType,
nonBreakingChange.message,
]);
}
}
console.log(changesTable.toString());
}
if (resp.compositionErrors.length > 0) {
console.log(pc.red('\nDetected composition errors:'));
for (const compositionError of resp.compositionErrors) {
compositionErrorsTable.push([compositionError.message]);
}
console.log(compositionErrorsTable.toString());
}
if (resp.compositionWarnings.length > 0) {
console.log(pc.yellow(`\nDetected composition warnings:`));
for (const compositionWarning of resp.compositionWarnings) {
compositionWarningsTable.push([compositionWarning.message]);
}
console.log(compositionWarningsTable.toString());
}
if (resp.lintErrors.length > 0 || resp.lintWarnings.length > 0) {
console.log('\nDetected lint issues:');
for (const error of resp.lintErrors) {
lintIssuesTable.push([
error.subgraphName || '-',
`${logSymbols.error} ${pc.red(error.lintRuleType)}`,
error.message,
(_c = error.issueLocation) === null || _c === void 0 ? void 0 : _c.line,
]);
}
for (const warning of resp.lintWarnings) {
lintIssuesTable.push([
warning.subgraphName || '-',
`${logSymbols.warning} ${pc.yellow(warning.lintRuleType)}`,
warning.message,
(_d = warning.issueLocation) === null || _d === void 0 ? void 0 : _d.line,
]);
}
console.log(lintIssuesTable.toString());
}
if (resp.graphPruneErrors.length > 0 || resp.graphPruneWarnings.length > 0) {
console.log('\nDetected graph pruning issues:');
for (const error of resp.graphPruneErrors) {
graphPruningIssuesTable.push([
error.subgraphName || '-',
`${logSymbols.error} ${pc.red(error.graphPruningRuleType)}`,
error.fieldPath,
error.message,
((_e = error.issueLocation) === null || _e === void 0 ? void 0 : _e.line) || '-',
]);
}
for (const warning of resp.graphPruneWarnings) {
graphPruningIssuesTable.push([
warning.subgraphName || '-',
`${logSymbols.warning} ${pc.yellow(warning.graphPruningRuleType)}`,
warning.fieldPath,
warning.message,
((_f = warning.issueLocation) === null || _f === void 0 ? void 0 : _f.line) || '-',
]);
}
console.log(graphPruningIssuesTable.toString());
}
if (resp.isLinkedTrafficCheckFailed || resp.isLinkedPruningCheckFailed) {
finalStatement += success
? `\n\n But this schema change has been linked to a target subgraph and the target subgraph check has failed.`
: `\n\n This schema change has been linked to a target subgraph and the target subgraph check has failed.`;
if (resp.isLinkedTrafficCheckFailed) {
finalStatement += `\n\n The target subgraph check has failed because of client traffic issues.`;
}
if (resp.isLinkedPruningCheckFailed) {
finalStatement += `\n\n The target subgraph check has failed because of graph pruning issues.`;
}
success = false;
}
if (success) {
console.log('\n' +
logSymbols.success +
pc.green(` Schema check with the proposed schemas passed. ${finalStatement}`) +
'\n\n' +
studioCheckUrl +
'\n');
return { success: true, message: successMessage };
}
else {
console.error('\n' +
logSymbols.error +
pc.red(` Schema check with the proposed schemas failed. ${finalStatement}\nSee https://cosmo-docs.wundergraph.com/studio/schema-checks for more information on resolving schema check errors.\n${studioCheckUrl}\n`));
return { success: true, message: successMessage };
}
};
//# sourceMappingURL=handle-proposal-result.js.map