diff --git a/src/commands/schema/diff.ts b/src/commands/schema/diff.ts index 0d5e3881..761467d9 100644 --- a/src/commands/schema/diff.ts +++ b/src/commands/schema/diff.ts @@ -1,12 +1,19 @@ import SchemaCommand from "../../lib/schema-command"; -import { colorParam, hasColor } from "../../lib/color"; +import { bold, colorParam, hasColor, reset } from "../../lib/color"; +import { Flags } from "@oclif/core"; export default class DiffSchemaCommand extends SchemaCommand { static flags = { ...SchemaCommand.flags, + active: Flags.boolean({ + description: + "Compare the local schema to the active schema instead of the staged schema.", + default: false, + }), }; - static description = "Print the diff between local and remote schema."; + static description = + "Print the diff between local schema and staged remote schema."; static examples = [ "$ fauna schema diff", "$ fauna schema diff --dir schemas/myschema", @@ -15,18 +22,48 @@ export default class DiffSchemaCommand extends SchemaCommand { async run() { const fps = this.gatherRelativeFSLFilePaths(); const files = this.read(fps); + const { url, secret } = await this.fetchsetup(); + + let version: string | undefined = undefined; + let status: string = ""; + + try { + const res = await fetch(new URL(`/schema/1/staged/status`, url), { + method: "GET", + headers: { AUTHORIZATION: `Bearer ${secret}` }, + // https://github.com/nodejs/node/issues/46221 + // https://github.com/microsoft/TypeScript-DOM-lib-generator/issues/1483 + // @ts-expect-error-next-line + duplex: "half", + }); + + const json = await res.json(); + if (json.error) { + this.error(json.error.message); + } + + version = json.version; + status = json.status; + + if (json.status === "none" && this.flags?.active) { + this.error( + "There is no staged schema, so passing `--active` does nothing" + ); + } + } catch (err) { + this.error(err); + } + try { - const { url, secret } = await this.fetchsetup(); const params = new URLSearchParams({ ...(hasColor() ? { color: colorParam() } : {}), - force: "true", + staged: this.flags?.active ? "false" : "true", + ...(version !== undefined ? { version } : { force: "true" }), }); const res = await fetch(new URL(`/schema/1/validate?${params}`, url), { method: "POST", headers: { AUTHORIZATION: `Bearer ${secret}` }, body: this.body(files), - // https://github.com/nodejs/node/issues/46221 - // https://github.com/microsoft/TypeScript-DOM-lib-generator/issues/1483 // @ts-expect-error-next-line duplex: "half", }); @@ -34,6 +71,22 @@ export default class DiffSchemaCommand extends SchemaCommand { if (json.error) { this.error(json.error.message); } + + if (status !== "none") { + if (this.flags?.active) { + this.log( + `Differences between the ${bold()}local${reset()} schema and the ${bold()}remote, active${reset()} schema:` + ); + } else { + this.log( + `Differences between the ${bold()}local${reset()} schema and the ${bold()}remote, staged${reset()} schema:` + ); + } + } else { + this.log( + `Differences between the ${bold()}local${reset()} schema and the ${bold()}remote${reset()} schema:` + ); + } this.log(json.diff ? json.diff : "No schema differences"); } catch (err) { this.error(err); diff --git a/src/lib/color.ts b/src/lib/color.ts index 941570ad..bd82c290 100644 --- a/src/lib/color.ts +++ b/src/lib/color.ts @@ -26,3 +26,14 @@ export const colorParam = (): string => { export const hasColor = (): boolean => { return colorEnabled ?? false; }; + +export const reset = (): string => esc(`\u001b[0m`); +export const bold = (): string => esc(`\u001b[1m`); + +const esc = (str: string): string => { + if (hasColor()) { + return str; + } else { + return ""; + } +}; diff --git a/test/commands/schema.test.ts b/test/commands/schema.test.ts index ed1ecb35..dadd0013 100644 --- a/test/commands/schema.test.ts +++ b/test/commands/schema.test.ts @@ -50,13 +50,76 @@ describe("fauna schema diff test", () => { .persist() .post("/", matchFqlReq(query.Now())) .reply(200, new Date()) - .post("/schema/1/validate?force=true") + .get("/schema/1/staged/status") + .reply(200, { status: "none", version: 0 }) + .post("/schema/1/validate?staged=true&version=0") .reply(200, diff); const { stdout } = await runCommand( withOpts(["schema diff", "--dir=test/testdata"]) ); + expect(stdout).to.contain( + `Differences between the local schema and the remote schema:` + ); + expect(stdout).to.contain(`${diff.diff}`); + }); + + it("runs schema diff when there's a staged schema", async () => { + nock(getEndpoint(), { allowUnmocked: false }) + .persist() + .post("/", matchFqlReq(query.Now())) + .reply(200, new Date()) + .get("/schema/1/staged/status") + .reply(200, { status: "ready", version: 0 }) + .post("/schema/1/validate?staged=true&version=0") + .reply(200, diff); + + const { stdout } = await runCommand( + withOpts(["schema diff", "--dir=test/testdata"]) + ); + + expect(stdout).to.contain( + `Differences between the local schema and the remote, staged schema:` + ); + expect(stdout).to.contain(`${diff.diff}`); + }); + + it("runs schema diff --active with no staged schema", async () => { + nock(getEndpoint(), { allowUnmocked: false }) + .persist() + .post("/", matchFqlReq(query.Now())) + .reply(200, new Date()) + .get("/schema/1/staged/status") + .reply(200, { status: "none", version: 0 }) + .post("/schema/1/validate?staged=true&version=0") + .reply(200, diff); + + const { error } = await runCommand( + withOpts(["schema diff", "--dir=test/testdata", "--active"]) + ); + expect(error?.message).to.equal( + "There is no staged schema, so passing `--active` does nothing" + ); + }); + + it("runs schema diff --active", async () => { + nock(getEndpoint(), { allowUnmocked: false }) + .persist() + .post("/", matchFqlReq(query.Now())) + .reply(200, new Date()) + .get("/schema/1/staged/status") + .reply(200, { status: "ready", version: 0 }) + .post("/schema/1/validate?staged=false&version=0") + .reply(200, diff); + + const { stdout } = await runCommand( + withOpts(["schema diff", "--dir=test/testdata", "--active"]) + ); + + expect(stdout).to.contain( + `Differences between the local schema and the remote, active schema:` + ); expect(stdout).to.contain(`${diff.diff}`); }); });