Skip to content

Commit

Permalink
Merge branch 'master' into fix-flags-overriding-config
Browse files Browse the repository at this point in the history
  • Loading branch information
klujanrosas committed Jul 25, 2018
2 parents fba0a23 + 143b540 commit 9e93b78
Show file tree
Hide file tree
Showing 15 changed files with 280 additions and 110 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ install:
script:
- npm test
- npm run packageExtension
- cd packages/apollo-cli && ./bin/run queries:check --queries="./src/operations/*" --key=$STAGING_API_KEY --engine=https://engine-staging-graphql.apollographql.com/api/graphql
- test $STAGING_API_KEY && cd packages/apollo-cli && ./bin/run queries:check --queries="./src/operations/*" --key=$STAGING_API_KEY --engine=https://engine-staging-graphql.apollographql.com/api/graphql
118 changes: 104 additions & 14 deletions packages/apollo-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@
Apollo CLI brings together your GraphQL clients and servers with tools for validating your schema, linting your operations for compatibility with your server, and generating static types for improved client-side type safety.

<!-- toc -->
* [Apollo CLI](#apollo-cli)
* [Usage](#usage)
* [Commands](#commands)
* [Code Generation](#code-generation)
* [Contributing](#contributing)
<!-- tocstop -->

- [Apollo CLI](#apollo-cli)
- [Usage](#usage)
- [Commands](#commands)
- [Configuration](#configuration)
- [Code Generation](#code-generation)
- [Contributing](#contributing)
<!-- tocstop -->

# Usage

<!-- usage -->

```sh-session
$ npm install -g apollo
$ apollo COMMAND
Expand All @@ -26,17 +29,19 @@ USAGE
$ apollo COMMAND
...
```

<!-- usagestop -->

# Commands

<!-- commands -->
* [`apollo codegen:generate [OUTPUT]`](#apollo-codegengenerate-output)
* [`apollo help [COMMAND]`](#apollo-help-command)
* [`apollo queries:check`](#apollo-queriescheck)
* [`apollo schema:check`](#apollo-schemacheck)
* [`apollo schema:download OUTPUT`](#apollo-schemadownload-output)
* [`apollo schema:publish`](#apollo-schemapublish)

- [`apollo codegen:generate [OUTPUT]`](#apollo-codegengenerate-output)
- [`apollo help [COMMAND]`](#apollo-help-command)
- [`apollo queries:check`](#apollo-queriescheck)
- [`apollo schema:check`](#apollo-schemacheck)
- [`apollo schema:download OUTPUT`](#apollo-schemadownload-output)
- [`apollo schema:publish`](#apollo-schemapublish)

## `apollo codegen:generate [OUTPUT]`

Expand All @@ -50,11 +55,11 @@ ARGUMENTS
OUTPUT
Directory to which generated files will be written.
- For TypeScript/Flow generators, this specifies a directory relative to each source file by default.
- For TypeScript/Flow generators with the "outputFlat" flag is set, and for the Swift generator, this specifies a
- For TypeScript/Flow generators with the "outputFlat" flag is set, and for the Swift generator, this specifies a
file or directory (absolute or relative to the current working directory) to which:
- a file will be written for each query (if "output" is a directory)
- all generated types will be written
- For all other types, this defines a file (absolute or relative to the current working directory) to which all
- For all other types, this defines a file (absolute or relative to the current working directory) to which all
generated types are written.
OPTIONS
Expand Down Expand Up @@ -204,8 +209,93 @@ OPTIONS
```

_See code: [src/commands/schema/publish.ts](https://github.com/apollographql/apollo-cli/blob/v1.5.0/src/commands/schema/publish.ts)_

<!-- commandsstop -->

# Configuration

The Apollo CLI and VS Code extension can be configured with an Apollo Config file. Apollo configuration is stored as a plain object and can be either specified under the `apollo` key in your `package.json` or as a separate `apollo.config.js` which exports the config data.

The core of any configuration is specifying schemas and queries. Schemas specify information about your backend such as where to get the schema, what endpoint to make requests against, and the Apollo Engine API key to get schema updates and stats from. Queries define which documents Apollo tooling should analyze and tie them to the schema they are targeting.

Let's take a look at a basic configuration file (`package.json` style):

```js
{
...
"apollo": {
"schemas": {
"myPrimaryBackend": {
"schema": "downloadedSchema.json", // if not defined the an introspection query will be run
"endpoint": "http://example.com/graphql", // if not defined the schema will be downloaded from Apollo Engine
"engineKey": "my-engine-key" // use this key when connecting to Apollo Engine
}
},
"queries": [
{
"schema": "myPrimaryBackend", // reference the previously defined schema
"includes": [ "**/*.tsx" ], // load queries from .tsx files
"excludes": [ "node_modules/**" ] // don't include any matching files from node_modules
}
]
}
}
```

Or in `apollo.config.js` style:

```js
...

module.exports = {
schemas: {
myPrimaryBackend: {
schema: "downloadedSchema.json", // if not defined the an introspection query will be run
endpoint: "http://example.com/graphql", // if not defined the schema will be downloaded from Apollo Engine
engineKey: "my-engine-key" // use this key when connecting to Apollo Engine
}
},
queries: [
{
schema: "myPrimaryBackend", // reference the previously defined schema
includes: [ "**/*.tsx" ], // load queries from .tsx files
excludes: [ "node_modules/**" ] // don't include any matching files from node_modules
}
]
}
```

## Endpoint Configuration

When configuring a schema's endpoint, you can either pass in a string or an object, which allows for specifying advanced options like headers and subscription endpoints.

```js
endpoint: {
url: "http://example.com/graphql",
subscriptions: "ws://example.com/graphql",
headers: {
cookie: "myCookie=myCookieValue"
}
}
```

## Schema Dependencies

Schemas can also declare dependencies on eachother, which can be useful in situations like having a client-side schema for `apollo-link-state`. To declare a dependency, use the `extends` key. When working with a client-side schema, make sure to also specify the `clientSide` key to enable code-generation support.

```js
schemas: {
myServerSideSchema: {
...
},
myClientSideSchema: {
extends: "myServerSideSchema",
clientSide: true
...
}
}
```

# Code Generation

## Accompanying Libraries
Expand Down
92 changes: 53 additions & 39 deletions packages/apollo-cli/src/commands/schema/__tests__/check.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
jest.mock("apollo-codegen-core/lib/localfs", () => {
return require("../../../__mocks__/localfs");
});

// this is because of herkou-cli-utils hacky mocking system on their console logger
import { stdout, mockConsole } from "heroku-cli-util";
import * as path from "path";
Expand All @@ -8,27 +12,29 @@ import gql from "graphql-tag";
import { ENGINE_URI } from "../../../engine";
import { VALIDATE_SCHEMA } from "../../../operations/validateSchema";

import { vol, fs as mockFS } from "apollo-codegen-core/lib/localfs";

const test = setup.do(() => mockConsole());
const ENGINE_API_KEY = "service:test:1234";
const hash = "12345";
const localSchema = { __schema: { fakeSchema: true } };
const fullSchema = execute(
buildSchema(
fs.readFileSync(path.resolve(__dirname, "./fixtures/schema.graphql"), {
encoding: "utf-8",
})
),
gql(introspectionQuery)
).data;
const schemaContents = fs.readFileSync(
path.resolve(__dirname, "./fixtures/schema.graphql"),
{
encoding: "utf-8"
}
);

const fullSchema = execute(buildSchema(schemaContents), gql(introspectionQuery))
.data;

const localSuccess = nock => {
nock
.post("/graphql", {
query: print(gql(introspectionQuery)),
operationName: "IntrospectionQuery",
variables: {},
variables: {}
})
.reply(200, { data: localSchema });
.reply(200, { data: fullSchema });
};

const engineSuccess = ({ schema, tag, results } = {}) => nock => {
Expand All @@ -38,15 +44,15 @@ const engineSuccess = ({ schema, tag, results } = {}) => nock => {
operationName: "CheckSchema",
variables: {
id: "test",
schema: schema || localSchema.__schema,
schema: schema || fullSchema.__schema,
tag: tag || "current",
gitContext: {
commit: /.+/i,
remoteUrl: /apollo-cli/i,
committer: /@/i,
},
committer: /@/i
}
},
query: print(VALIDATE_SCHEMA),
query: print(VALIDATE_SCHEMA)
})
.reply(200, {
data: {
Expand All @@ -57,33 +63,40 @@ const engineSuccess = ({ schema, tag, results } = {}) => nock => {
{
type: "NOTICE",
code: "DEPRECATION_ADDED",
description: "Field `User.lastName` was deprecated",
description: "Field `User.lastName` was deprecated"
},
{
type: "WARNING",
code: "FIELD_REMOVED",
description: "Field `User.firstName` removed",
description: "Field `User.firstName` removed"
},
{
type: "FAILURE",
code: "ARG_CHANGE_TYPE",
description: "Argument id on `Query.user` changed to ID!",
description: "Argument id on `Query.user` changed to ID!"
},
{
type: "NOTICE",
code: "FIELD_ADDED",
description: "Field `User.fullName` was added",
},
],
},
},
},
},
description: "Field `User.fullName` was added"
}
]
}
}
}
}
});
};

jest.setTimeout(25000);

beforeEach(() => {
vol.reset();
vol.fromJSON({
__blankFileSoDirectoryExists: ""
});
});

describe("successful checks", () => {
test
.nock("http://localhost:4000", localSuccess)
Expand Down Expand Up @@ -161,17 +174,17 @@ describe("successful checks", () => {
.post("/graphql", {
query: print(gql(introspectionQuery)),
operationName: "IntrospectionQuery",
variables: {},
variables: {}
})
.reply(200, { data: localSchema });
.reply(200, { data: fullSchema });
})
.nock(ENGINE_URI, engineSuccess())
.env({ ENGINE_API_KEY })
.command([
"schema:check",
"--endpoint=https://staging.example.com/graphql",
"--header=Authorization: 1234",
"--header=Hello: World",
"--header=Hello: World"
])
.exit(1)
.it(
Expand All @@ -184,16 +197,15 @@ describe("successful checks", () => {
);

test
.do(() =>
vol.fromJSON({
"introspection-result.json": JSON.stringify({ data: fullSchema })
})
)
.stdout()
.nock(ENGINE_URI, engineSuccess())
.env({ ENGINE_API_KEY })
.command([
"schema:check",
`--endpoint=${path.resolve(
__dirname,
"./fixtures/introspection-result.json"
)}`,
])
.command(["schema:check", "--endpoint=introspection-result.json"])
.exit(1)
.it(
"calls engine with a schema from an introspection result on the filesystem",
Expand All @@ -205,13 +217,15 @@ describe("successful checks", () => {
);

test
.do(() =>
vol.fromJSON({
"schema.graphql": schemaContents
})
)
.stdout()
.nock(ENGINE_URI, engineSuccess({ schema: fullSchema.__schema }))
.env({ ENGINE_API_KEY })
.command([
"schema:check",
`--endpoint=${path.resolve(__dirname, "./fixtures/schema.graphql")}`,
])
.command(["schema:check", "--endpoint=schema.graphql"])
.exit(1)
.it(
"calls engine with a schema from a schema file on the filesystem",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { fs as mockFS, vol } from "apollo-codegen-core/lib/localfs";
const test = setup.do(() => mockConsole());
const ENGINE_API_KEY = "service:test:1234";
const hash = "12345";
const localSchema = { __schema: { fakeSchema: true } };
const schemaSource = fs.readFileSync(
path.resolve(__dirname, "./fixtures/schema.graphql"),
{
Expand All @@ -28,9 +27,7 @@ const schemaSource = fs.readFileSync(
const fullSchema = execute(buildSchema(schemaSource), gql(introspectionQuery))
.data;

const introspectionResult = fs.readFileSync(
path.resolve(__dirname, "./fixtures/introspection-result.json")
);
const introspectionResult = JSON.stringify({ data: fullSchema });

const localSuccess = nock => {
nock
Expand All @@ -39,7 +36,7 @@ const localSuccess = nock => {
operationName: "IntrospectionQuery",
variables: {}
})
.reply(200, { data: localSchema });
.reply(200, { data: fullSchema });
};

const engineSuccess = ({ schema, tag, result } = {}) => nock => {
Expand All @@ -48,7 +45,7 @@ const engineSuccess = ({ schema, tag, result } = {}) => nock => {
.post("/", {
operationName: "UploadSchema",
variables: {
schema: schema || localSchema.__schema,
schema: schema || fullSchema.__schema,
id: "test",
tag: tag || "current",
gitContext: {
Expand Down Expand Up @@ -166,7 +163,7 @@ describe("successful uploads", () => {
operationName: "IntrospectionQuery",
variables: {}
})
.reply(200, { data: localSchema });
.reply(200, { data: fullSchema });
})
.nock(ENGINE_URI, engineSuccess())
.env({ ENGINE_API_KEY })
Expand Down
Loading

0 comments on commit 9e93b78

Please sign in to comment.