Skip to content

Commit

Permalink
#5064 Display detailed errors from CLI (#6921)
Browse files Browse the repository at this point in the history
* Display detailed errors from CLI

* feat(codegen): better Listr error handling at `executeCodegen()` level

* fix(codegen): remove useless comment

* fix(codegen): use AggregateError to keep references of original errors

* Create famous-bikes-punch.md

Co-authored-by: Charly POLY <cpoly55@gmail.com>
Co-authored-by: Charly POLY <1252066+charlypoly@users.noreply.github.com>
  • Loading branch information
3 people committed Feb 3, 2022
1 parent ca42a44 commit f13d355
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 33 deletions.
5 changes: 5 additions & 0 deletions .changeset/famous-bikes-punch.md
@@ -0,0 +1,5 @@
---
"@graphql-codegen/cli": patch
---

#5064 Display detailed errors from CLI
21 changes: 20 additions & 1 deletion packages/graphql-codegen-cli/src/codegen.ts
Expand Up @@ -6,9 +6,12 @@ import {
normalizeInstanceOrArray,
normalizeConfig,
getCachedDocumentNodeFromSchema,
isDetailedError,
} from '@graphql-codegen/plugin-helpers';
import { codegen } from '@graphql-codegen/core';

import { AggregateError } from '@graphql-tools/utils';

import { Renderer, ErrorRenderer } from './utils/listr-renderer';
import { GraphQLError, GraphQLSchema, DocumentNode } from 'graphql';
import { getPluginByName } from './plugins';
Expand All @@ -20,6 +23,7 @@ import path from 'path';
// eslint-disable-next-line
import { createRequire } from 'module';
import Listr from 'listr';
import { isListrError } from './utils/cli-error';

const makeDefaultLoader = (from: string) => {
if (fs.statSync(from).isDirectory()) {
Expand Down Expand Up @@ -384,7 +388,22 @@ export async function executeCodegen(input: CodegenContext | Types.Config): Prom
},
});

await listr.run();
try {
await listr.run();
} catch (err) {
if (isListrError(err)) {
const allErrs = err.errors.map(subErr =>
isDetailedError(subErr)
? `${subErr.message} for "${subErr.source}"${subErr.details}`
: subErr.message || subErr.toString()
);
const newErr = new AggregateError(err.errors, `${err.message} ${allErrs.join('\n\n')}`);
// Best-effort to all stack traces for debugging
newErr.stack = `${newErr.stack}\n\n${err.errors.map(subErr => subErr.stack).join('\n\n')}`;
throw newErr;
}
throw err;
}

return result;
}
7 changes: 7 additions & 0 deletions packages/graphql-codegen-cli/src/utils/cli-error.ts
@@ -1,5 +1,12 @@
import { DetailedError } from '@graphql-codegen/plugin-helpers';
import { isBrowser, isNode } from './is-browser';

type CompositeError = Error | DetailedError;
type ListrError = Error & { errors: CompositeError[] };
export function isListrError(err: Error & { name?: unknown; errors?: unknown }): err is ListrError {
return err.name === 'ListrError' && Array.isArray(err.errors) && err.errors.length > 0;
}

export function cliError(err: any, exitOnError = true) {
let msg: string;

Expand Down
70 changes: 38 additions & 32 deletions packages/graphql-codegen-cli/tests/codegen.spec.ts
Expand Up @@ -261,7 +261,7 @@ describe('Codegen Executor', () => {
throw SHOULD_NOT_THROW_STRING;
} catch (e) {
expect(e).not.toEqual(SHOULD_NOT_THROW_STRING);
expect(e.errors[0].message).toContain('Not all operations have an unique name: q');
expect(e.message).toContain('Not all operations have an unique name: q');
}
});

Expand Down Expand Up @@ -547,8 +547,7 @@ describe('Codegen Executor', () => {
throw new Error(SHOULD_NOT_THROW_STRING);
} catch (e) {
expect(e.message).not.toBe(SHOULD_NOT_THROW_STRING);
expect(e.errors[0].message).toContain('Invalid Custom Plugin');
expect(e.errors[0].details).toContain('does not export a valid JS object with');
expect(e.message).toContain('Invalid Custom Plugin');
}
});

Expand All @@ -565,8 +564,7 @@ describe('Codegen Executor', () => {
throw new Error(SHOULD_NOT_THROW_STRING);
} catch (e) {
expect(e.message).not.toBe(SHOULD_NOT_THROW_STRING);
expect(e.errors[0].message).toContain('validation failed');
expect(e.errors[0].details).toContain('Invalid!');
expect(e.message).toContain('validation failed');
}
});

Expand Down Expand Up @@ -757,9 +755,8 @@ describe('Codegen Executor', () => {
});

throw new Error(SHOULD_NOT_THROW_STRING);
} catch (listrError) {
const e = listrError.errors[0];
expect(e.message).toContain('Failed to load schema');
} catch (error) {
expect(error.message).toContain('Failed to load schema');
}
});

Expand All @@ -781,9 +778,8 @@ describe('Codegen Executor', () => {
});

throw new Error(SHOULD_NOT_THROW_STRING);
} catch (listrError) {
const e = listrError.errors[0];
expect(e.details).toContain('Failed to load custom loader');
} catch (error) {
expect(error.message).toContain('Failed to load custom loader');
}
});

Expand All @@ -805,10 +801,9 @@ describe('Codegen Executor', () => {
});

throw new Error(SHOULD_NOT_THROW_STRING);
} catch (listrError) {
const e = listrError.errors[0];
expect(e.message).toContain('Failed to load schema');
expect(e.details).toContain('Failed to load custom loader');
} catch (error) {
expect(error.message).toContain('Failed to load schema');
expect(error.message).toContain('Failed to load custom loader');
}
});
});
Expand Down Expand Up @@ -873,9 +868,8 @@ describe('Codegen Executor', () => {
});

throw new Error(SHOULD_NOT_THROW_STRING);
} catch (listrError) {
const e = listrError.errors[0];
expect(e.message).toContain('Unable to find any GraphQL type definitions for the following pointers');
} catch (error) {
expect(error.message).toContain('Unable to find any GraphQL type definitions for the following pointers');
}
});

Expand All @@ -898,9 +892,8 @@ describe('Codegen Executor', () => {
});

throw new Error(SHOULD_NOT_THROW_STRING);
} catch (listrError) {
const e = listrError.errors[0];
expect(e.message).toContain('Failed to load custom loader');
} catch (error) {
expect(error.message).toContain('Failed to load custom loader');
}
});

Expand All @@ -923,9 +916,8 @@ describe('Codegen Executor', () => {
});

throw new Error(SHOULD_NOT_THROW_STRING);
} catch (listrError) {
const e = listrError.errors[0];
expect(e.message).toContain('Failed to load custom loader');
} catch (error) {
expect(error.message).toContain('Failed to load custom loader');
}
});
});
Expand All @@ -943,13 +935,7 @@ describe('Codegen Executor', () => {
},
});
} catch (error) {
const isExpectedError = error.errors && error.errors.some(e => e.message.includes('Failed to load schema'));

if (!isExpectedError) {
// eslint-disable-next-line no-console
console.error(error);
throw error;
}
expect(error.message).toContain('Failed to load schema from http://www.dummyschema.com/graphql');
}
expect((global as any).CUSTOM_FETCH_FN_CALLED).toBeTruthy();
});
Expand Down Expand Up @@ -988,7 +974,7 @@ describe('Codegen Executor', () => {
});
expect(output.length).toBe(1);
} catch (e) {
expect(e.errors[0].message).not.toBe('Query root type must be provided.');
expect(e.message).not.toBe('Query root type must be provided.');
}
});

Expand Down Expand Up @@ -1061,4 +1047,24 @@ describe('Codegen Executor', () => {
}
`);
});

it('Handles weird errors due to invalid schema', async () => {
const schema = /* GraphQL */ `
type Query {
brrrt:1
}
`;
try {
await executeCodegen({
schema: [schema],
generates: {
'out1.graphql': {
plugins: ['schema-ast'],
},
},
});
} catch (error) {
expect(error.message).toContain('Failed to load schema for "out1.graphql"');
}
});
});

1 comment on commit f13d355

@vercel
Copy link

@vercel vercel bot commented on f13d355 Feb 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.