diff --git a/CHANGELOG.md b/CHANGELOG.md index 7761778648..4588ae9acf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## Upcoming - `apollo` - - + - Shorten `client:check` and `service:check` output in CI [#1404](https://github.com/apollographql/apollo-tooling/pull/1404) - `apollo-codegen-core` - - `apollo-codegen-flow` diff --git a/package-lock.json b/package-lock.json index 29237929fd..966b2adcfe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4686,6 +4686,15 @@ "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", "dev": true }, + "env-ci": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-4.1.1.tgz", + "integrity": "sha512-eTgpkALDeYRGNhYM2fO9LKsWDifoUgKL7hxpPZqFMP2IU7f+r89DtKqCmk3yQB/jxS8CmZTfKnWO5TiIDFs9Hw==", + "requires": { + "execa": "^1.0.0", + "java-properties": "^1.0.0" + } + }, "err-code": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", @@ -7464,6 +7473,11 @@ "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.2.2.tgz", "integrity": "sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA==" }, + "java-properties": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/java-properties/-/java-properties-1.0.2.tgz", + "integrity": "sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==" + }, "jest": { "version": "24.8.0", "resolved": "https://registry.npmjs.org/jest/-/jest-24.8.0.tgz", diff --git a/package.json b/package.json index 7da67b9b0c..583f55ce48 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "apollo-env": "file:packages/apollo-env", "apollo-graphql": "file:packages/apollo-graphql", "apollo-language-server": "file:packages/apollo-language-server", + "env-ci": "^4.1.1", "vscode-apollo": "file:packages/vscode-apollo" }, "devDependencies": { diff --git a/packages/apollo/src/commands/client/check.ts b/packages/apollo/src/commands/client/check.ts index 291f0598d3..b8e3cf018b 100644 --- a/packages/apollo/src/commands/client/check.ts +++ b/packages/apollo/src/commands/client/check.ts @@ -2,10 +2,12 @@ import { flags } from "@oclif/command"; import { print } from "graphql"; import { gitInfo } from "../../git"; import { ClientCommand } from "../../Command"; +import { CompactRenderer } from "../../utils"; import URI from "vscode-uri"; import { relative } from "path"; import { graphqlTypes } from "apollo-language-server"; import chalk from "chalk"; +import envCi from "env-ci"; const { ValidationErrorType } = graphqlTypes; type ValidationResult = graphqlTypes.ValidateOperations_service_validateOperations_validationResults; @@ -28,44 +30,51 @@ export default class ClientCheck extends ClientCommand { }; async run() { + const { isCi } = envCi(); + const { validationResults, operations } = await this.runTasks<{ operations: Operation[]; validationResults: ValidationResult[]; - }>(({ project, config }) => [ - { - title: "Checking client compatibility with service", - task: async ctx => { - if (!config.name) { - throw new Error( - "No service found to link to Engine. Engine is required for this command." - ); + }>( + ({ project, config }) => [ + { + title: "Checking client compatibility with service", + task: async ctx => { + if (!config.name) { + throw new Error( + "No service found to link to Engine. Engine is required for this command." + ); + } + ctx.gitContext = await gitInfo(this.log); + + ctx.operations = Object.entries( + this.project.mergedOperationsAndFragmentsForService + ).map(([name, doc]) => ({ + body: print(doc), + name, + relativePath: relative( + config.configURI ? config.configURI.fsPath : "", + URI.parse(doc.definitions[0].loc!.source.name).fsPath + ), + locationOffset: doc.definitions[0].loc!.source.locationOffset + })); + + ctx.validationResults = await project.engine.validateOperations({ + id: config.name, + tag: config.tag, + operations: ctx.operations.map(({ body, name }) => ({ + body, + name + })), + gitContext: ctx.gitContext + }); } - ctx.gitContext = await gitInfo(this.log); - - ctx.operations = Object.entries( - this.project.mergedOperationsAndFragmentsForService - ).map(([name, doc]) => ({ - body: print(doc), - name, - relativePath: relative( - config.configURI ? config.configURI.fsPath : "", - URI.parse(doc.definitions[0].loc!.source.name).fsPath - ), - locationOffset: doc.definitions[0].loc!.source.locationOffset - })); - - ctx.validationResults = await project.engine.validateOperations({ - id: config.name, - tag: config.tag, - operations: ctx.operations.map(({ body, name }) => ({ - body, - name - })), - gitContext: ctx.gitContext - }); } - } - ]); + ], + () => ({ + renderer: isCi ? CompactRenderer : "default" + }) + ); // Group the validation results by operation name const messagesByOperationName = this.getMessagesByOperationName( diff --git a/packages/apollo/src/commands/service/__tests__/__snapshots__/check.test.ts.snap b/packages/apollo/src/commands/service/__tests__/__snapshots__/check.test.ts.snap index 99bcce9cdd..d79773ed23 100644 --- a/packages/apollo/src/commands/service/__tests__/__snapshots__/check.test.ts.snap +++ b/packages/apollo/src/commands/service/__tests__/__snapshots__/check.test.ts.snap @@ -83,6 +83,18 @@ exports[`service:check integration federated should report composition errors co " `; +exports[`service:check integration federated should report composition errors correctly compacts output in CI 1`] = ` +"Loading Apollo Project +Found 3 graph composition errors for service accounts on graph engine + +Service Field Message +──────── ─────── ──────────────────────────────────────────────────────────────────────────────────────── +reviews User.id marked @external but it does not have a matching field on on the base service (accounts) +reviews User A @key selects id, but User.id could not be found +accounts User A @key selects id, but User.id could not be found +" +`; + exports[`service:check integration federated should report composition errors correctly vanilla 1`] = ` "Loading Apollo Project [started] Loading Apollo Project [completed] @@ -133,6 +145,19 @@ exports[`service:check integration federated should report composition success c " `; +exports[`service:check integration federated should report composition success correctly compacts output in CI 1`] = ` +"Loading Apollo Project +Found 0 graph composition errors for service accounts on graph engine +Validated composed schema against tag master on graph engine +Compared 1 schema change against 0 operations over the last 548 days +Found 0 breaking changes and 1 compatible change + +PASS ARG_CHANGED_TYPE \`Query.launches\` argument \`after\` has changed type from \`String\` to \`String!\` + +View full details at: https://engine-staging.apollographql.com/service/justin-fullstack-tutorial/check/3acd7765-61b2-4f1a-9227-8b288e42bfdc +" +`; + exports[`service:check integration federated should report composition success correctly vanilla 1`] = ` "Loading Apollo Project [started] Loading Apollo Project [completed] diff --git a/packages/apollo/src/commands/service/__tests__/check.test.ts b/packages/apollo/src/commands/service/__tests__/check.test.ts index 89d90fec08..b0027a624a 100644 --- a/packages/apollo/src/commands/service/__tests__/check.test.ts +++ b/packages/apollo/src/commands/service/__tests__/check.test.ts @@ -50,6 +50,9 @@ let mockedConsoleLogOriginal: Console["log"] | null = null; */ let mockedConsoleLogValues: string[] | null = null; +// Get original CI environment variables +const { CI, CIRCLECI, GITHUB_ACTION, BUILD_BUILDURI } = process.env; + // TODO: the following two functions are identical to the ones found in list.test.ts // we are choosing to duplicate them for now, because with a shared helper function, // jest overwrites console log output as the tests are run in parallel @@ -369,6 +372,11 @@ describe("service:check", () => { nock.disableNetConnect(); + delete process.env.CI; + delete process.env.CIRCLECI; + delete process.env.GITHUB_ACTION; + delete process.env.BUILD_BUILDURI; + // Set the jest timeout to be longer than the default 5000ms to compensate for slow CI. jest.setTimeout(25000); }); @@ -382,6 +390,11 @@ describe("service:check", () => { // Clean up all network mocks and restore original functionality nock.cleanAll(); nock.enableNetConnect(); + + process.env.CI = CI; + process.env.CIRCLECI = CIRCLECI; + process.env.GITHUB_ACTION = GITHUB_ACTION; + process.env.BUILD_BUILDURI = BUILD_BUILDURI; }); // These are integration tests and not e2e tests because these don't actually hit the remote server. @@ -406,6 +419,26 @@ describe("service:check", () => { expect(uncaptureApplicationOutput()).toMatchSnapshot(); }); + it("compacts output in CI", async () => { + captureApplicationOutput(); + mockCompositionFailure(); + + expect.assertions(2); + + process.env.CI = "true"; + + await expect( + ServiceCheck.run([ + ...cliKeyParameter, + "--serviceName=accounts", + `--endpoint=${localURL}/graphql` + ]) + ).rejects.toThrow(); + + // Inline snapshots don't work here due to https://github.com/facebook/jest/issues/6744. + expect(uncaptureApplicationOutput()).toMatchSnapshot(); + }); + it("--markdown", async () => { captureApplicationOutput(); mockCompositionFailure(); @@ -466,6 +499,26 @@ describe("service:check", () => { expect(uncaptureApplicationOutput()).toMatchSnapshot(); }); + it("compacts output in CI", async () => { + captureApplicationOutput(); + mockCompositionSuccess(); + + expect.assertions(2); + + process.env.CI = "true"; + + await expect( + ServiceCheck.run([ + ...cliKeyParameter, + "--serviceName=accounts", + `--endpoint=${localURL}/graphql` + ]) + ).resolves.not.toThrow(); + + // Inline snapshots don't work here due to https://github.com/facebook/jest/issues/6744. + expect(uncaptureApplicationOutput()).toMatchSnapshot(); + }); + it("--markdown", async () => { captureApplicationOutput(); mockCompositionSuccess(); diff --git a/packages/apollo/src/commands/service/check.ts b/packages/apollo/src/commands/service/check.ts index f11a919cd8..17fe1aa976 100644 --- a/packages/apollo/src/commands/service/check.ts +++ b/packages/apollo/src/commands/service/check.ts @@ -2,9 +2,14 @@ import { flags } from "@oclif/command"; import { table } from "heroku-cli-util"; import { introspectionFromSchema, printSchema, GraphQLSchema } from "graphql"; import chalk from "chalk"; +import envCi from "env-ci"; import { gitInfo } from "../../git"; import { ProjectCommand } from "../../Command"; -import { validateHistoricParams, pluralize } from "../../utils"; +import { + validateHistoricParams, + pluralize, + CompactRenderer +} from "../../utils"; import { CheckSchema_service_checkSchema, CheckSchema_service_checkSchema_diffToPrevious_changes as Change, @@ -303,6 +308,8 @@ export default class ServiceCheck extends ProjectCommand { const federatedServiceCompositionUnsuccessfulErrorMessage = "Federated service composition was unsuccessful. Please see the reasons below."; + const { isCi } = envCi(); + let schema: GraphQLSchema | undefined; try { await this.runTasks( @@ -568,8 +575,11 @@ export default class ServiceCheck extends ProjectCommand { // the `this.log` output to `stdout`. // // @see https://github.com/SamVerschueren/listr#renderer - renderer: - context.flags.markdown || context.flags.json ? "silent" : "default" + renderer: isCi + ? CompactRenderer + : context.flags.markdown || context.flags.json + ? "silent" + : "default" }) ); } catch (error) { diff --git a/packages/apollo/src/utils/CompactRenderer.ts b/packages/apollo/src/utils/CompactRenderer.ts new file mode 100644 index 0000000000..b210d64641 --- /dev/null +++ b/packages/apollo/src/utils/CompactRenderer.ts @@ -0,0 +1,36 @@ +import { + ListrRenderer, + ListrTaskObject, + ListrOptions, + ListrError +} from "listr"; + +export class CompactRenderer implements ListrRenderer { + _tasks: ReadonlyArray>; + + constructor( + tasks: ReadonlyArray>, + options: ListrOptions + ) { + this._tasks = tasks; + } + + static get nonTTY() { + return true; + } + + render() { + this._tasks.forEach(task => { + task.subscribe(event => { + if ( + event.type === "STATE" && + (task.state === "completed" || task.state === "failed") + ) { + console.log(task.title); + } + }); + }); + } + + end(err: ListrError) {} +} diff --git a/packages/apollo/src/utils/index.ts b/packages/apollo/src/utils/index.ts index 47c83b08ce..8125c4b1b5 100644 --- a/packages/apollo/src/utils/index.ts +++ b/packages/apollo/src/utils/index.ts @@ -1,3 +1,5 @@ export * from "./validateHistoricParams"; export * from "./pluralize"; + +export * from "./CompactRenderer";