Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLI and Logging improvements #4353

Merged
merged 1 commit into from
Aug 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .changeset/friendly-bears-walk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
"@graphql-mesh/cli": minor
"@graphql-mesh/utils": minor
---

Now CLI reports critical errors with stack traces even if DEBUG isn't enabled, and error messages are no longer trimmed.

```diff
Schema couldn't be generated because of the following errors:
- - Foo bar is n...
+ - Foo bar is not valid
+ at /somepath/somejsfile.js:123:2
+ at /someotherpath/someotherjs.file:232:4
```
6 changes: 6 additions & 0 deletions .changeset/young-clouds-burn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@graphql-mesh/cli": minor
"@graphql-mesh/config": minor
---

New flag for `mesh build`. You can set `mesh build --throwOnInvalidConfig=true` to make the CLI throw an exception if the configuration file is invalid per Mesh's configuration schema
15 changes: 14 additions & 1 deletion packages/cli/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,31 @@ import { defaultImportFn, loadYaml, DefaultLogger } from '@graphql-mesh/utils';
import Ajv from 'ajv';
import { cosmiconfig, defaultLoaders } from 'cosmiconfig';
import { path, process } from '@graphql-mesh/cross-helpers';
import { AggregateError } from '@graphql-tools/utils';

export function validateConfig(
config: any,
filepath: string,
initialLoggerPrefix: string
initialLoggerPrefix: string,
throwOnInvalidConfig = false
): asserts config is YamlConfig.Config {
const ajv = new Ajv({
strict: false,
} as any);
jsonSchema.$schema = undefined;
const isValid = ajv.validate(jsonSchema, config);
if (!isValid) {
if (throwOnInvalidConfig) {
const aggregateError = new AggregateError(
ajv.errors.map(e => {
const error = new Error(e.message);
error.stack += `\n at ${filepath}:0:0`;
return error;
}),
'Configuration file is not valid'
);
throw aggregateError;
}
const logger = new DefaultLogger(initialLoggerPrefix).child('config');
logger.warn('Configuration file is not valid!');
logger.warn("This is just a warning! It doesn't have any effects on runtime.");
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/handleFatalError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Logger } from '@graphql-mesh/types';
import { process } from '@graphql-mesh/cross-helpers';

export function handleFatalError(e: Error, logger: Logger): any {
logger.error(e.stack || e.message);
logger.error(e);
if (process.env.JEST == null) {
process.exit(1);
}
Expand Down
7 changes: 6 additions & 1 deletion packages/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ export async function graphqlMesh(
}
}
)
.command<{ fileType: 'json' | 'ts' | 'js' }>(
.command<{ fileType: 'json' | 'ts' | 'js'; throwOnInvalidConfig: boolean }>(
cliParams.buildArtifactsCommand,
'Builds artifacts',
builder => {
Expand All @@ -318,6 +318,10 @@ export async function graphqlMesh(
choices: ['json', 'ts', 'js'],
default: 'ts',
});
builder.option('throwOnInvalidConfig', {
type: 'boolean',
default: false,
});
},
async args => {
try {
Expand Down Expand Up @@ -373,6 +377,7 @@ export async function graphqlMesh(
additionalPackagePrefixes: cliParams.additionalPackagePrefixes,
generateCode: true,
initialLoggerPrefix: cliParams.initialLoggerPrefix,
throwOnInvalidConfig: args.throwOnInvalidConfig,
});
logger = meshConfig.logger;

Expand Down
1 change: 1 addition & 0 deletions packages/config/src/process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export type ConfigProcessOptions = {
additionalPackagePrefixes?: string[];
generateCode?: boolean;
initialLoggerPrefix?: string;
throwOnInvalidConfig?: boolean;
};

type EnvelopPlugins = Parameters<typeof envelop>[0]['plugins'];
Expand Down
34 changes: 24 additions & 10 deletions packages/utils/src/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ export const titleBold: MessageTransformer = msg => ANSI_CODES.bold + msg + ANSI
export class DefaultLogger implements Logger {
constructor(public name?: string) {}

private getLoggerMessage(...args: any[]) {
private getLoggerMessage({ args = [], trim = this.isDebug }: { args: any[]; trim?: boolean }) {
return args
.flat(Infinity)
.map(arg => {
if (typeof arg === 'string') {
if (arg.length > 100 && !this.isDebug) {
return arg.slice(0, 100) + '...';
if (trim && arg.length > 100) {
return arg.slice(0, 100) + '...' + '<Error message is too long. Enable DEBUG=1 to see the full message.>';
}
return arg;
} else if (typeof arg === 'object' && arg?.stack != null) {
Expand All @@ -43,14 +43,17 @@ export class DefaultLogger implements Logger {
.join(` `);
}

private handleLazyMessage(...lazyArgs: LazyLoggerMessage[]) {
private handleLazyMessage({ lazyArgs, trim }: { lazyArgs: LazyLoggerMessage[]; trim?: boolean }) {
const flattenedArgs = lazyArgs.flat(Infinity).flatMap(arg => {
if (typeof arg === 'function') {
return arg();
}
return arg;
});
return this.getLoggerMessage(flattenedArgs);
return this.getLoggerMessage({
args: flattenedArgs,
trim,
});
}

private get isDebug() {
Expand All @@ -66,12 +69,16 @@ export class DefaultLogger implements Logger {
}

log(...args: any[]) {
const message = this.getLoggerMessage(...args);
const message = this.getLoggerMessage({
args,
});
return console.log(`${this.prefix} ${message}`);
}

warn(...args: any[]) {
const message = this.getLoggerMessage(...args);
const message = this.getLoggerMessage({
args,
});
const fullMessage = `⚠️ ${this.prefix} ${warnColor(message)}`;
if (console.warn) {
console.warn(fullMessage);
Expand All @@ -81,7 +88,9 @@ export class DefaultLogger implements Logger {
}

info(...args: any[]) {
const message = this.getLoggerMessage(...args);
const message = this.getLoggerMessage({
args,
});
const fullMessage = `💡 ${this.prefix} ${infoColor(message)}`;
if (console.info) {
console.info(fullMessage);
Expand All @@ -91,14 +100,19 @@ export class DefaultLogger implements Logger {
}

error(...args: any[]) {
const message = this.getLoggerMessage(...args);
const message = this.getLoggerMessage({
args,
trim: false,
});
const fullMessage = `💥 ${this.prefix} ${errorColor(message)}`;
console.log(fullMessage);
}

debug(...lazyArgs: LazyLoggerMessage[]) {
if (this.isDebug) {
const message = this.handleLazyMessage(lazyArgs);
const message = this.handleLazyMessage({
lazyArgs,
});
const fullMessage = `🐛 ${this.prefix} ${debugColor(message)}`;
if (console.debug) {
console.debug(fullMessage);
Expand Down