From 6f5f43a8b5d8d060ec66923bade8f5329d3dd90d Mon Sep 17 00:00:00 2001 From: Adam Zionts Date: Fri, 27 Mar 2020 11:27:31 -0700 Subject: [PATCH] Support APOLLO_KEY, deprecate ENGINE_API_KEY This supports a more modern name for the API key and adds deprecation messages for the (now legacy) ENGINE_API_KEY. Much in the same spirit as https://github.com/apollographql/apollo-tooling/pull/1849, the goal is to modernize our documentation to no longer use the out-of-date name "engine". This also modifies tests to support the new version and adds a test that ensures an error is thrown when a user sets _both_ keys. --- .../src/config/__tests__/loadConfig.ts | 30 ++++++++++++++----- .../src/config/loadConfig.ts | 17 +++++++++-- .../src/project/base.ts | 4 +-- .../src/providers/schema/engine.ts | 6 ++-- packages/apollo/src/Command.ts | 2 +- .../commands/client/__tests__/check.test.ts | 20 ++++++------- .../commands/service/__tests__/check.test.ts | 22 +++++++------- .../service/__tests__/publish.test.ts | 22 +++++++------- 8 files changed, 76 insertions(+), 47 deletions(-) diff --git a/packages/apollo-language-server/src/config/__tests__/loadConfig.ts b/packages/apollo-language-server/src/config/__tests__/loadConfig.ts index 3760e79796..bba4c44f84 100644 --- a/packages/apollo-language-server/src/config/__tests__/loadConfig.ts +++ b/packages/apollo-language-server/src/config/__tests__/loadConfig.ts @@ -279,7 +279,7 @@ describe("loadConfig", () => { it("finds .env in config path & parses for key", async () => { writeFilesToDir(dir, { "my.config.js": `module.exports = { client: { name: 'hello' } }`, - ".env": `ENGINE_API_KEY=service:harambe:54378950jn` + ".env": `APOLLO_KEY=service:harambe:54378950jn` }); const config = await loadConfig({ @@ -293,7 +293,7 @@ describe("loadConfig", () => { it("finds .env.local in config path & parses for key", async () => { writeFilesToDir(dir, { "my.config.js": `module.exports = { client: { name: 'hello' } }`, - ".env.local": `ENGINE_API_KEY=service:harambe:54378950jn` + ".env.local": `APOLLO_KEY=service:harambe:54378950jn` }); const config = await loadConfig({ @@ -307,8 +307,8 @@ describe("loadConfig", () => { it("finds .env and .env.local in config path & parses for key, preferring .env.local", async () => { writeFilesToDir(dir, { "my.config.js": `module.exports = { client: { name: 'hello' } }`, - ".env": `ENGINE_API_KEY=service:hamato:54378950jn`, - ".env.local": `ENGINE_API_KEY=service:yoshi:65489061ko` + ".env": `APOLLO_KEY=service:hamato:54378950jn`, + ".env.local": `APOLLO_KEY=service:yoshi:65489061ko` }); const config = await loadConfig({ @@ -319,11 +319,25 @@ describe("loadConfig", () => { expect(config.client.service).toEqual("yoshi"); }); + it("Throws when .env defined legacy and new key", async () => { + writeFilesToDir(dir, { + "my.config.js": `module.exports = { client: { name: 'hello' } }`, + ".env.local": `ENGINE_API_KEY=service:yoshi:65489061ko\nAPOLLO_KEY=service:yoshi:65489061ko` + }); + + const loadConfigPromise = loadConfig({ + configPath: dirPath, + configFileName: "my.config.js" + }); + + await expect(loadConfigPromise).rejects.toThrow(/Cannot set both/); + }); + // this doesn't work right now :) xit("finds .env in cwd & parses for key", async () => { writeFilesToDir(dir, { "dir/my.config.js": `module.exports = { client: { name: 'hello' } }`, - ".env": `ENGINE_API_KEY=service:harambe:54378950jn` + ".env": `APOLLO_KEY=service:harambe:54378950jn` }); process.chdir(dir); const config = await loadConfig({ @@ -382,7 +396,7 @@ describe("loadConfig", () => { it("lets config service name take precedence for client project", async () => { writeFilesToDir(dir, { "my.config.js": `module.exports = { client: { service: 'hello' } }`, - ".env": `ENGINE_API_KEY=service:harambe:54378950jn` + ".env": `APOLLO_KEY=service:harambe:54378950jn` }); const config = await loadConfig({ @@ -397,7 +411,7 @@ describe("loadConfig", () => { it("lets name passed in take precedence over env var", async () => { writeFilesToDir(dir, { "my.config.js": `module.exports = { client: { } }`, - ".env": `ENGINE_API_KEY=service:harambe:54378950jn` + ".env": `APOLLO_KEY=service:harambe:54378950jn` }); const config = await loadConfig({ @@ -412,7 +426,7 @@ describe("loadConfig", () => { it("uses env var to determine service name when no other options", async () => { writeFilesToDir(dir, { "my.config.js": `module.exports = { client: { } }`, - ".env": `ENGINE_API_KEY=service:harambe:54378950jn` + ".env": `APOLLO_KEY=service:harambe:54378950jn` }); const config = await loadConfig({ diff --git a/packages/apollo-language-server/src/config/loadConfig.ts b/packages/apollo-language-server/src/config/loadConfig.ts index 430b006676..dbca1e0c3b 100644 --- a/packages/apollo-language-server/src/config/loadConfig.ts +++ b/packages/apollo-language-server/src/config/loadConfig.ts @@ -34,6 +34,9 @@ const loaders = { } }; +export const legacyKeyEnvVar = "ENGINE_API_KEY"; +export const keyEnvVar = "APOLLO_KEY"; + export interface LoadConfigSettings { // the current working directory to start looking for the config // config loading only works on node so we default to @@ -123,9 +126,19 @@ export async function loadConfig({ const env: { [key: string]: string } = require("dotenv").parse( readFileSync(dotEnvPath) ); - if (env["ENGINE_API_KEY"]) { - apiKey = env["ENGINE_API_KEY"]; + const legacyKey = env[legacyKeyEnvVar]; + const key = env[keyEnvVar]; + if (legacyKey && key) { + throw new Error( + `Cannot set both ${legacyKeyEnvVar} and ${keyEnvVar}. Please only set ${keyEnvVar}` + ); + } + if (legacyKey) { + Debug.warning( + `[Deprecation warning] Setting the key via ${legacyKeyEnvVar} is deprecated and will not be supported in future versions.` + ); } + apiKey = key || legacyKey; } }); diff --git a/packages/apollo-language-server/src/project/base.ts b/packages/apollo-language-server/src/project/base.ts index 0605c25340..7768a521ed 100644 --- a/packages/apollo-language-server/src/project/base.ts +++ b/packages/apollo-language-server/src/project/base.ts @@ -23,7 +23,7 @@ import { GraphQLDocument, extractGraphQLDocuments } from "../document"; import { LoadingHandler } from "../loadingHandler"; import { FileSet } from "../fileSet"; -import { ApolloConfig } from "../config"; +import { ApolloConfig, keyEnvVar } from "../config"; import { schemaProviderFromConfig, GraphQLSchemaProvider, @@ -136,7 +136,7 @@ export abstract class GraphQLProject implements GraphQLSchemaProvider { // handle error states for missing engine config // all in the same place :tada: if (!this.engineClient) { - throw new Error("Unable to find ENGINE_API_KEY"); + throw new Error(`Unable to find ${keyEnvVar}`); } return this.engineClient!; } diff --git a/packages/apollo-language-server/src/providers/schema/engine.ts b/packages/apollo-language-server/src/providers/schema/engine.ts index 08110616db..00f98ac669 100644 --- a/packages/apollo-language-server/src/providers/schema/engine.ts +++ b/packages/apollo-language-server/src/providers/schema/engine.ts @@ -3,7 +3,7 @@ import { NotificationHandler } from "vscode-languageserver"; import gql from "graphql-tag"; import { GraphQLSchema, buildClientSchema } from "graphql"; import { ApolloEngineClient, ClientIdentity } from "../../engine"; -import { ClientConfig, parseServiceSpecifier } from "../../config"; +import { ClientConfig, keyEnvVar, parseServiceSpecifier } from "../../config"; import { getServiceFromKey, isServiceKey } from "../../config"; import { GraphQLSchemaProvider, @@ -36,7 +36,9 @@ export class EngineSchemaProvider implements GraphQLSchemaProvider { // create engine client if (!this.client) { if (!engine.apiKey) { - throw new Error("ENGINE_API_KEY not found"); + throw new Error( + `No API key found. Please set ${keyEnvVar} or use --key` + ); } this.client = new ApolloEngineClient( engine.apiKey, diff --git a/packages/apollo/src/Command.ts b/packages/apollo/src/Command.ts index 6794aab82a..7d4e782bc7 100644 --- a/packages/apollo/src/Command.ts +++ b/packages/apollo/src/Command.ts @@ -83,7 +83,7 @@ export abstract class ProjectCommand extends Command { key: flags.string({ description: "The API key to use for authentication to Apollo Graph Manager", - default: () => process.env.ENGINE_API_KEY + default: () => process.env.APOLLO_KEY || process.env.ENGINE_API_KEY }), engine: flags.string({ description: "URL for a custom Apollo Graph Manager deployment", diff --git a/packages/apollo/src/commands/client/__tests__/check.test.ts b/packages/apollo/src/commands/client/__tests__/check.test.ts index fb28ea6f7f..347b41972c 100644 --- a/packages/apollo/src/commands/client/__tests__/check.test.ts +++ b/packages/apollo/src/commands/client/__tests__/check.test.ts @@ -13,7 +13,7 @@ it("is turned on after summit", () => {}); // import { fs as mockFS, vol } from "apollo-codegen-core/lib/localfs"; // const test = setup.do(() => mockConsole()); -// const ENGINE_API_KEY = "service:test:1234"; +// const APOLLO_KEY = "service:test:1234"; // const hash = "12345"; // const dummyOperations = [ @@ -26,7 +26,7 @@ it("is turned on after summit", () => {}); // const engineSuccess = ({ operations, tag, results } = {}) => nock => { // nock -// .matchHeader("x-api-key", ENGINE_API_KEY) +// .matchHeader("x-api-key", APOLLO_KEY) // .post("/", { // operationName: "CheckOperations", // variables: { @@ -85,7 +85,7 @@ it("is turned on after summit", () => {}); // test // .do(() => vol.fromJSON(files)) // .nock(ENGINE_URI, engineSuccess()) -// .env({ ENGINE_API_KEY }) +// .env({ APOLLO_KEY }) // .stdout() // .command(["queries:check"]) // .exit(1) @@ -103,7 +103,7 @@ it("is turned on after summit", () => {}); // "apollo": { // "schemas": { // "default": { -// "engineKey": "${ENGINE_API_KEY}" +// "engineKey": "${APOLLO_KEY}" // } // } // } @@ -132,7 +132,7 @@ it("is turned on after summit", () => {}); // "apollo": { // "schemas": { // "default": { -// "engineKey": "${ENGINE_API_KEY}" +// "engineKey": "${APOLLO_KEY}" // } // } // } @@ -156,7 +156,7 @@ it("is turned on after summit", () => {}); // .do(() => vol.fromJSON(files)) // .nock(ENGINE_URI, engineSuccess()) // .stdout() -// .command(["queries:check", `--key=${ENGINE_API_KEY}`]) +// .command(["queries:check", `--key=${APOLLO_KEY}`]) // .exit(1) // .it("allows custom api key", () => { // expect(stdout).toContain("FAILURE"); @@ -166,7 +166,7 @@ it("is turned on after summit", () => {}); // test // .do(() => vol.fromJSON(files)) // .nock(ENGINE_URI, engineSuccess({ results: [] })) -// .env({ ENGINE_API_KEY }) +// .env({ APOLLO_KEY }) // .stdout() // .command(["queries:check"]) // .it( @@ -187,7 +187,7 @@ it("is turned on after summit", () => {}); // vol.fromJSON(nested); // }) // .nock(ENGINE_URI, engineSuccess()) -// .env({ ENGINE_API_KEY }) +// .env({ APOLLO_KEY }) // .stdout() // .command(["queries:check", "--queries=./client/*.graphql"]) // .exit(1) @@ -203,7 +203,7 @@ it("is turned on after summit", () => {}); // "https://engine.example.com", // engineSuccess({ engine: "https://engine.example.com" }) // ) -// .env({ ENGINE_API_KEY }) +// .env({ APOLLO_KEY }) // .command(["queries:check", "--engine=https://engine.example.com"]) // .exit(1) // .it("compares against a schema from a custom registry", std => { @@ -214,7 +214,7 @@ it("is turned on after summit", () => {}); // test // .do(() => vol.fromJSON(files)) // .nock(ENGINE_URI, engineSuccess()) -// .env({ ENGINE_API_KEY }) +// .env({ APOLLO_KEY }) // .stdout() // .command(["queries:check", "--json"]) // .exit(1) diff --git a/packages/apollo/src/commands/service/__tests__/check.test.ts b/packages/apollo/src/commands/service/__tests__/check.test.ts index d27435549f..967dceb748 100644 --- a/packages/apollo/src/commands/service/__tests__/check.test.ts +++ b/packages/apollo/src/commands/service/__tests__/check.test.ts @@ -850,7 +850,7 @@ describe("service:check", () => { // import { vol, fs as mockFS } from "apollo-codegen-core/lib/localfs"; // const test = setup.do(() => captureApplicationOutput()); -// const ENGINE_API_KEY = "service:test:1234"; +// const APOLLO_KEY = "service:test:1234"; // const hash = "12345"; // const schemaContents = fs.readFileSync( // path.resolve(__dirname, "./fixtures/schema.graphql"), @@ -874,7 +874,7 @@ describe("service:check", () => { // const engineSuccess = ({ schema, tag, results } = {}) => nock => { // nock -// .matchHeader("x-api-key", ENGINE_API_KEY) +// .matchHeader("x-api-key", APOLLO_KEY) // .post("/", { // operationName: "CheckSchema", // variables: { @@ -936,7 +936,7 @@ describe("service:check", () => { // test // .nock("http://localhost:4000", localSuccess) // .nock(ENGINE_URI, engineSuccess()) -// .env({ ENGINE_API_KEY }) +// .env({ APOLLO_KEY }) // .stdout() // .command(["schema:check"]) // .exit(1) @@ -950,7 +950,7 @@ describe("service:check", () => { // .nock("http://localhost:4000", localSuccess) // .nock(ENGINE_URI, engineSuccess()) // .stdout() -// .command(["schema:check", `--key=${ENGINE_API_KEY}`]) +// .command(["schema:check", `--key=${APOLLO_KEY}`]) // .exit(1) // .it("allows custom api key", () => { // expect(stdout).toContain("FAILURE"); @@ -961,7 +961,7 @@ describe("service:check", () => { // test // .nock("http://localhost:4000", localSuccess) // .nock(ENGINE_URI, engineSuccess({ results: [] })) -// .env({ ENGINE_API_KEY }) +// .env({ APOLLO_KEY }) // .stdout() // .command(["schema:check"]) // .it( @@ -975,7 +975,7 @@ describe("service:check", () => { // .stdout() // .nock("https://staging.example.com", localSuccess) // .nock(ENGINE_URI, engineSuccess()) -// .env({ ENGINE_API_KEY }) +// .env({ APOLLO_KEY }) // .command(["schema:check", "--endpoint=https://staging.example.com/graphql"]) // .exit(1) // .it("compares against a schema from a custom remote", () => { @@ -991,7 +991,7 @@ describe("service:check", () => { // "https://engine.example.com", // engineSuccess({ engine: "https://engine.example.com" }) // ) -// .env({ ENGINE_API_KEY }) +// .env({ APOLLO_KEY }) // .command(["schema:check", "--engine=https://engine.example.com"]) // .exit(1) // .it("compares against a schema from a custom registry", std => { @@ -1014,7 +1014,7 @@ describe("service:check", () => { // .reply(200, { data: fullSchema }); // }) // .nock(ENGINE_URI, engineSuccess()) -// .env({ ENGINE_API_KEY }) +// .env({ APOLLO_KEY }) // .command([ // "schema:check", // "--endpoint=https://staging.example.com/graphql", @@ -1039,7 +1039,7 @@ describe("service:check", () => { // ) // .stdout() // .nock(ENGINE_URI, engineSuccess()) -// .env({ ENGINE_API_KEY }) +// .env({ APOLLO_KEY }) // .command(["schema:check", "--endpoint=introspection-result.json"]) // .exit(1) // .it( @@ -1059,7 +1059,7 @@ describe("service:check", () => { // ) // .stdout() // .nock(ENGINE_URI, engineSuccess({ schema: fullSchema.__schema })) -// .env({ ENGINE_API_KEY }) +// .env({ APOLLO_KEY }) // .command(["schema:check", "--endpoint=schema.graphql"]) // .exit(1) // .it( @@ -1074,7 +1074,7 @@ describe("service:check", () => { // test // .nock("http://localhost:4000", localSuccess) // .nock(ENGINE_URI, engineSuccess()) -// .env({ ENGINE_API_KEY }) +// .env({ APOLLO_KEY }) // .stdout() // .command(["schema:check", "--json"]) // .exit(1) diff --git a/packages/apollo/src/commands/service/__tests__/publish.test.ts b/packages/apollo/src/commands/service/__tests__/publish.test.ts index 43d15d26e0..8520c02eb6 100644 --- a/packages/apollo/src/commands/service/__tests__/publish.test.ts +++ b/packages/apollo/src/commands/service/__tests__/publish.test.ts @@ -12,7 +12,7 @@ it("is turned on after summit", () => {}); // export const vol = Volume.fromJSON({}); // const ENGINE_URI = "https://engine-graphql.apollographql.com/api/graphql"; // const test = setup.do(() => mockConsole()); -// const ENGINE_API_KEY = "service:test:1234"; +// const APOLLO_KEY = "service:test:1234"; // const hash = "12345"; // const schemaSource = fs.readFileSync( // path.resolve(__dirname, "./fixtures/schema.graphql"), @@ -38,7 +38,7 @@ it("is turned on after summit", () => {}); // const engineSuccess = ({ schema, tag, result } = {}) => nock => { // nock -// .matchHeader("x-api-key", ENGINE_API_KEY) +// .matchHeader("x-api-key", APOLLO_KEY) // .post("/", { // operationName: "UploadSchema", // variables: { @@ -83,7 +83,7 @@ it("is turned on after summit", () => {}); // .only() // .nock("http://localhost:4000", localSuccess) // .nock(ENGINE_URI, engineSuccess()) -// .env({ ENGINE_API_KEY }) +// .env({ APOLLO_KEY }) // .stdout() // .command(["service:push"]) // .it("calls engine with a schema from the default remote", () => { @@ -94,7 +94,7 @@ it("is turned on after summit", () => {}); // .nock("http://localhost:4000", localSuccess) // .nock(ENGINE_URI, engineSuccess()) // .stdout() -// .command(["service:push", `--key=${ENGINE_API_KEY}`]) +// .command(["service:push", `--key=${APOLLO_KEY}`]) // .it("allows a custom api key", () => { // expect(uiLog).toContain("12345"); // }); @@ -103,7 +103,7 @@ it("is turned on after summit", () => {}); // .stdout() // .nock("https://staging.example.com", localSuccess) // .nock(ENGINE_URI, engineSuccess()) -// .env({ ENGINE_API_KEY }) +// .env({ APOLLO_KEY }) // .command(["service:push", "--endpoint=https://staging.example.com/graphql"]) // .it("calls engine with a schema from a custom remote", ({ stdout }) => { // expect(uiLog).toContain("12345"); @@ -118,7 +118,7 @@ it("is turned on after summit", () => {}); // "schemas": { // "customEndpoint": { // "endpoint": "https://staging.example.com/graphql", -// "engineKey": "${ENGINE_API_KEY}" +// "engineKey": "${APOLLO_KEY}" // } // } // } @@ -140,7 +140,7 @@ it("is turned on after summit", () => {}); // test // .nock("http://localhost:4000", localSuccess) // .nock("https://engine.example.com", engineSuccess()) -// .env({ ENGINE_API_KEY }) +// .env({ APOLLO_KEY }) // .stdout() // .command(["service:push", "--engine=https://engine.example.com"]) // .it("calls engine with a schema from a custom registry", () => { @@ -161,7 +161,7 @@ it("is turned on after summit", () => {}); // .reply(200, { data: fullSchema }); // }) // .nock(ENGINE_URI, engineSuccess()) -// .env({ ENGINE_API_KEY }) +// .env({ APOLLO_KEY }) // .command([ // "service:push", // "--endpoint=https://staging.example.com/graphql", @@ -183,7 +183,7 @@ it("is turned on after summit", () => {}); // ) // .stdout() // .nock(ENGINE_URI, engineSuccess()) -// .env({ ENGINE_API_KEY }) +// .env({ APOLLO_KEY }) // .command(["service:push", "--endpoint=introspection-result.json"]) // .it( // "calls engine with a schema from an introspection result on the filesystem", @@ -200,7 +200,7 @@ it("is turned on after summit", () => {}); // ) // .stdout() // .nock(ENGINE_URI, engineSuccess({ schema: fullSchema.__schema })) -// .env({ ENGINE_API_KEY }) +// .env({ APOLLO_KEY }) // .command(["service:push", "--endpoint=schema.graphql"]) // .it( // "calls engine with a schema from a schema file on the filesystem", @@ -234,7 +234,7 @@ it("is turned on after summit", () => {}); // } // }) // ) -// .env({ ENGINE_API_KEY }) +// .env({ APOLLO_KEY }) // .stdout() // .command(["service:push"]) // .it(