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:
Mina Kong 2024-02-21 06:36:18 -08:00 committed by GitHub
parent a356107746
commit 02f5274850
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 102 additions and 3 deletions

View file

@ -0,0 +1,5 @@
---
"@graphql-hive/cli": patch
---
Separated schema check changes in CLI output

View file

@ -0,0 +1,16 @@
type Query {
users: [User!]
}
enum UserRole {
ADMIN
EDITOR
VIEWER
}
type User {
id: ID!
name: String!
address: String
role: UserRole!
}

View file

@ -0,0 +1,15 @@
type Query {
users: [User!]
}
enum UserRole {
ADMIN
EDITOR
}
type User {
id: ID!
name: String!
email: String!
role: UserRole
}

View file

@ -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',

View file

@ -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();

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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) {