mirror of
https://github.com/graphql-hive/console
synced 2026-04-21 14:37:17 +00:00
feat(cli): separate dangerous changes from warnings in CLI schema check command (#3862)
Co-authored-by: Patrick Deniso <patrick.deniso@wealthsimple.com> Co-authored-by: Laurin Quast <laurinquast@googlemail.com>
This commit is contained in:
parent
a356107746
commit
02f5274850
9 changed files with 102 additions and 3 deletions
5
.changeset/two-rings-give.md
Normal file
5
.changeset/two-rings-give.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"@graphql-hive/cli": patch
|
||||
---
|
||||
|
||||
Separated schema check changes in CLI output
|
||||
16
integration-tests/fixtures/breaking-schema-detailed.graphql
Normal file
16
integration-tests/fixtures/breaking-schema-detailed.graphql
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
type Query {
|
||||
users: [User!]
|
||||
}
|
||||
|
||||
enum UserRole {
|
||||
ADMIN
|
||||
EDITOR
|
||||
VIEWER
|
||||
}
|
||||
|
||||
type User {
|
||||
id: ID!
|
||||
name: String!
|
||||
address: String
|
||||
role: UserRole!
|
||||
}
|
||||
15
integration-tests/fixtures/init-schema-detailed.graphql
Normal file
15
integration-tests/fixtures/init-schema-detailed.graphql
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
type Query {
|
||||
users: [User!]
|
||||
}
|
||||
|
||||
enum UserRole {
|
||||
ADMIN
|
||||
EDITOR
|
||||
}
|
||||
|
||||
type User {
|
||||
id: ID!
|
||||
name: String!
|
||||
email: String!
|
||||
role: UserRole
|
||||
}
|
||||
|
|
@ -78,6 +78,7 @@ describe('Schema policy checks', () => {
|
|||
expect(message.split('\n')).toEqual([
|
||||
'ℹ Detected 1 change',
|
||||
'',
|
||||
' Safe changes:',
|
||||
' - Field field was added to object type Query',
|
||||
'',
|
||||
'',
|
||||
|
|
@ -153,6 +154,7 @@ describe('Schema policy checks', () => {
|
|||
'',
|
||||
'ℹ Detected 1 change',
|
||||
'',
|
||||
' Safe changes:',
|
||||
' - Field field was added to object type Query',
|
||||
'',
|
||||
'View full report:',
|
||||
|
|
@ -199,6 +201,7 @@ describe('Schema policy checks', () => {
|
|||
expect(message.split('\n')).toEqual([
|
||||
'ℹ Detected 2 changes',
|
||||
'',
|
||||
' Safe changes:',
|
||||
' - Type User was added',
|
||||
' - Field user was added to object type Query',
|
||||
'',
|
||||
|
|
@ -251,6 +254,7 @@ describe('Schema policy checks', () => {
|
|||
'',
|
||||
'ℹ Detected 2 changes',
|
||||
'',
|
||||
' Safe changes:',
|
||||
' - Type User was added',
|
||||
' - Field user was added to object type Query',
|
||||
'',
|
||||
|
|
@ -321,6 +325,7 @@ describe('Schema policy checks', () => {
|
|||
'',
|
||||
'ℹ Detected 3 changes',
|
||||
'',
|
||||
' Safe changes:',
|
||||
' - Type User was added',
|
||||
' - Field user was added to object type Query',
|
||||
' - Field Query.foo is deprecated',
|
||||
|
|
|
|||
|
|
@ -19,6 +19,36 @@ describe.each`
|
|||
const serviceName = projectType === ProjectType.Single ? undefined : 'test';
|
||||
const serviceUrl = projectType === ProjectType.Single ? undefined : 'http://localhost:4000';
|
||||
|
||||
test.concurrent('can publish a schema with breaking, warning and safe changes', async () => {
|
||||
const { createOrg } = await initSeed().createOwner();
|
||||
const { inviteAndJoinMember, createProject } = await createOrg();
|
||||
await inviteAndJoinMember();
|
||||
const { createToken } = await createProject(projectType, {
|
||||
useLegacyRegistryModels: model === 'legacy',
|
||||
});
|
||||
const { secret } = await createToken({});
|
||||
|
||||
await schemaPublish([
|
||||
'--registry.accessToken',
|
||||
secret,
|
||||
'--author',
|
||||
'Kamil',
|
||||
'--commit',
|
||||
'abc123',
|
||||
...serviceNameArgs,
|
||||
...serviceUrlArgs,
|
||||
'fixtures/init-schema-detailed.graphql',
|
||||
]);
|
||||
await expect(
|
||||
schemaCheck([
|
||||
...serviceNameArgs,
|
||||
'--registry.accessToken',
|
||||
secret,
|
||||
'fixtures/breaking-schema-detailed.graphql',
|
||||
]),
|
||||
).rejects.toThrowError(/breaking changes:|dangerous changes:|safe changes/i);
|
||||
});
|
||||
|
||||
test.concurrent('can publish and check a schema with target:registry:read access', async () => {
|
||||
const { createOrg } = await initSeed().createOwner();
|
||||
const { inviteAndJoinMember, createProject } = await createOrg();
|
||||
|
|
|
|||
|
|
@ -305,6 +305,7 @@ describe('publish', () => {
|
|||
}),
|
||||
).resolves.toMatchInlineSnapshot(`
|
||||
i Detected 1 change
|
||||
Safe changes:
|
||||
- Field price was added to object type Product
|
||||
v Schema published
|
||||
i Available at http://localhost:8080/$organization/$project/production/history/$version
|
||||
|
|
|
|||
|
|
@ -169,6 +169,7 @@ describe('publish', () => {
|
|||
}),
|
||||
).resolves.toMatchInlineSnapshot(`
|
||||
i Detected 1 change
|
||||
Safe changes:
|
||||
- Field price was added to object type Product
|
||||
v Schema published
|
||||
i Available at http://localhost:8080/$organization/$project/production/history/$version
|
||||
|
|
|
|||
|
|
@ -274,6 +274,7 @@ describe('publish', () => {
|
|||
}),
|
||||
).resolves.toMatchInlineSnapshot(`
|
||||
i Detected 1 change
|
||||
Safe changes:
|
||||
- Field price was added to object type Product
|
||||
v Schema published
|
||||
i Available at http://localhost:8080/$organization/$project/production/history/$version
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { UrlLoader } from '@graphql-tools/url-loader';
|
|||
import baseCommand from '../base-command';
|
||||
import {
|
||||
CriticalityLevel,
|
||||
SchemaChange,
|
||||
SchemaChangeConnection,
|
||||
SchemaErrorConnection,
|
||||
SchemaWarningConnection,
|
||||
|
|
@ -31,12 +32,36 @@ export function renderErrors(this: baseCommand, errors: SchemaErrorConnection) {
|
|||
}
|
||||
|
||||
export function renderChanges(this: baseCommand, changes: SchemaChangeConnection) {
|
||||
const filterChangesByLevel = (level: CriticalityLevel) => {
|
||||
return (change: SchemaChange) => change.criticality === level;
|
||||
};
|
||||
const writeChanges = (changes: SchemaChange[]) => {
|
||||
changes.forEach(change => {
|
||||
this.log(String(indent), criticalityMap[change.criticality], this.bolderize(change.message));
|
||||
});
|
||||
};
|
||||
|
||||
this.info(`Detected ${changes.total} change${changes.total > 1 ? 's' : ''}`);
|
||||
this.log('');
|
||||
|
||||
changes.nodes.forEach(change => {
|
||||
this.log(indent, criticalityMap[change.criticality], this.bolderize(change.message));
|
||||
});
|
||||
const breakingChanges = changes.nodes.filter(filterChangesByLevel(CriticalityLevel.Breaking));
|
||||
const dangerousChanges = changes.nodes.filter(filterChangesByLevel(CriticalityLevel.Dangerous));
|
||||
const safeChanges = changes.nodes.filter(filterChangesByLevel(CriticalityLevel.Safe));
|
||||
|
||||
if (breakingChanges.length) {
|
||||
this.log(String(indent), `Breaking changes:`);
|
||||
writeChanges(breakingChanges);
|
||||
}
|
||||
|
||||
if (dangerousChanges.length) {
|
||||
this.log(String(indent), `Dangerous changes:`);
|
||||
writeChanges(dangerousChanges);
|
||||
}
|
||||
|
||||
if (safeChanges.length) {
|
||||
this.log(String(indent), `Safe changes:`);
|
||||
writeChanges(safeChanges);
|
||||
}
|
||||
}
|
||||
|
||||
export function renderWarnings(this: baseCommand, warnings: SchemaWarningConnection) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue