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
65 changes: 59 additions & 6 deletions src/commands/schema/diff.ts
Original file line number Diff line number Diff line change
@@ -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",
Expand All @@ -15,25 +22,71 @@ 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",
});
const json = await res.json();
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);
Expand Down
11 changes: 11 additions & 0 deletions src/lib/color.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 "";
}
};
65 changes: 64 additions & 1 deletion test/commands/schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}`);
});
});
Expand Down