Skip to content
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
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## Upcoming

- `apollo`
- <First `apollo` related entry goes here>
- Shorten `client:check` and `service:check` output in CI [#1404](https://github.com/apollographql/apollo-tooling/pull/1404)
- `apollo-codegen-core`
- <First `apollo-codegen-core` related entry goes here>
- `apollo-codegen-flow`
Expand Down
14 changes: 14 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
75 changes: 42 additions & 33 deletions packages/apollo/src/commands/client/check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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]
Expand Down
53 changes: 53 additions & 0 deletions packages/apollo/src/commands/service/__tests__/check.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -369,6 +372,11 @@ describe("service:check", () => {

nock.disableNetConnect();

delete process.env.CI;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

re these lines, I think this is a fine solution. Not sure there's a more effective way to simulate this environment

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);
});
Expand All @@ -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.
Expand All @@ -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();
Expand Down Expand Up @@ -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();
Expand Down
16 changes: 13 additions & 3 deletions packages/apollo/src/commands/service/check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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<TasksOutput>(
Expand Down Expand Up @@ -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) {
Expand Down
36 changes: 36 additions & 0 deletions packages/apollo/src/utils/CompactRenderer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {
ListrRenderer,
ListrTaskObject,
ListrOptions,
ListrError
} from "listr";

export class CompactRenderer<Ctx> implements ListrRenderer {
_tasks: ReadonlyArray<ListrTaskObject<Ctx>>;

constructor(
tasks: ReadonlyArray<ListrTaskObject<Ctx>>,
options: ListrOptions<Ctx>
) {
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<Ctx>) {}
}
2 changes: 2 additions & 0 deletions packages/apollo/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export * from "./validateHistoricParams";

export * from "./pluralize";

export * from "./CompactRenderer";