Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add fauna schema commit and abandon #357

Merged
merged 1 commit into from
Sep 17, 2024
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
96 changes: 96 additions & 0 deletions src/commands/schema/abandon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { confirm } from "@inquirer/prompts";
import SchemaCommand from "../../lib/schema-command";
import { Flags } from "@oclif/core";

export default class CommitSchemaCommand extends SchemaCommand {
static flags = {
...SchemaCommand.flags,
force: Flags.boolean({
description: "Push the change without a diff or schema version check",
default: false,
}),
};

static description = "Abandons the currently staged schema.";

static examples = ["$ fauna schema abandon"];

async run() {
try {
const { url, secret } = await this.fetchsetup();
if (this.flags?.force) {
const params = new URLSearchParams({
force: "true", // Just abandon, don't pass a schema version through.
});

const path = new URL(`/schema/1/staged/abandon?${params}`, url);
const res = await fetch(path, {
method: "POST",
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 ?? json.error);
}

this.log("Schema has been abandonded");
} else {
// Show status to confirm.
const { url, secret } = await this.fetchsetup();
const res = await fetch(
new URL("/schema/1/staged/status?diff=true", url),
{
method: "GET",
headers: { AUTHORIZATION: `Bearer ${secret}` },
// @ts-expect-error-next-line
duplex: "half",
}
);

const json = await res.json();
if (json.error) {
this.error(json.error.message);
}

if (json.status === "none") {
this.error("There is no staged schema to abandon");
}

this.log(json.diff);

const confirmed = await confirm({
message: "Abandon these changes?",
default: false,
});

if (confirmed) {
const params = new URLSearchParams({ version: json.version });

const path = new URL(`/schema/1/staged/abandon?${params}`, url);
const res = await fetch(path, {
method: "POST",
headers: { AUTHORIZATION: `Bearer ${secret}` },
// @ts-expect-error-next-line
duplex: "half",
});

const json0 = await res.json();
if (json0.error) {
this.error(json0.error.message);
}

this.log("Schema has been abandoned");
} else {
this.log("Abandon cancelled");
}
}
} catch (err) {
this.error(err);
}
}
}
100 changes: 100 additions & 0 deletions src/commands/schema/commit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { confirm } from "@inquirer/prompts";
import SchemaCommand from "../../lib/schema-command";
import { Flags } from "@oclif/core";

export default class CommitSchemaCommand extends SchemaCommand {
static flags = {
...SchemaCommand.flags,
force: Flags.boolean({
description: "Push the change without a diff or schema version check",
default: false,
}),
};

static description = "Commits the currently staged schema.";

static examples = ["$ fauna schema commit"];

async run() {
try {
const { url, secret } = await this.fetchsetup();
if (this.flags?.force) {
const params = new URLSearchParams({
force: "true", // Just commit, don't pass a schema version through.
});

const path = new URL(`/schema/1/staged/commit?${params}`, url);
const res = await fetch(path, {
method: "POST",
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 ?? json.error);
}

this.log("Schema has been committed");
} else {
// Show status to confirm.
const { url, secret } = await this.fetchsetup();
const res = await fetch(
new URL("/schema/1/staged/status?diff=true", url),
{
method: "GET",
headers: { AUTHORIZATION: `Bearer ${secret}` },
// @ts-expect-error-next-line
duplex: "half",
}
);

const json = await res.json();
if (json.error) {
this.error(json.error.message);
}

if (json.status === "none") {
this.error("There is no staged schema to commit");
}

this.log(json.diff);

if (json.status !== "ready") {
this.error("Schema is not ready to be committed");
}

const confirmed = await confirm({
message: "Accept and commit these changes?",
default: false,
});

if (confirmed) {
const params = new URLSearchParams({ version: json.version });

const path = new URL(`/schema/1/staged/commit?${params}`, url);
const res = await fetch(path, {
method: "POST",
headers: { AUTHORIZATION: `Bearer ${secret}` },
// @ts-expect-error-next-line
duplex: "half",
});

const json0 = await res.json();
if (json0.error) {
this.error(json0.error.message);
}

this.log("Schema has been committed");
} else {
this.log("Commit cancelled");
}
}
} catch (err) {
this.error(err);
}
}
}
95 changes: 95 additions & 0 deletions test/commands/schema.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,101 @@ describe("fauna schema push test", () => {
);
expect(stdout).to.contain(`${diff.diff}`);
});

it("runs schema commit", async () => {
nock(getEndpoint(), { allowUnmocked: false })
.persist()
.post("/", matchFqlReq(q.Now()))
.reply(200, new Date())
.get("/schema/1/staged/status?diff=true")
.reply(200, {
version: 3,
status: "ready",
diff: diff.diff,
})
.post("/schema/1/staged/commit?version=3")
.reply(200, { version: 0 });

// Stubbing the confirmation to always return true
const stubConfirm = sinon.stub(inquirer, "confirm").resolves(true);
const { stdout } = await runCommand(
withOpts(["schema commit", "--dir=test/testdata"])
);
expect(stdout).to.contain(`Schema has been committed`);
// Restore the stub after the test
stubConfirm.restore();
});

it("won't commit when schema isn't ready", async () => {
nock(getEndpoint(), { allowUnmocked: false })
.persist()
.post("/", matchFqlReq(q.Now()))
.reply(200, new Date())
.get("/schema/1/staged/status?diff=true")
.reply(200, {
version: 3,
status: "pending",
diff: diff.diff,
});

// Stubbing the confirmation to always return true
const stubConfirm = sinon.stub(inquirer, "confirm").resolves(true);
const { stdout, error } = await runCommand(
withOpts(["schema commit", "--dir=test/testdata"])
);
expect(stdout).to.contain(diff.diff);
expect(error.message).to.equal("Schema is not ready to be committed");
// Restore the stub after the test
stubConfirm.restore();
});

it("runs schema abandon", async () => {
nock(getEndpoint(), { allowUnmocked: false })
.persist()
.post("/", matchFqlReq(q.Now()))
.reply(200, new Date())
.get("/schema/1/staged/status?diff=true")
.reply(200, {
version: 3,
status: "ready",
diff: diff.diff,
})
.post("/schema/1/staged/abandon?version=3")
.reply(200, { version: 0 });

// Stubbing the confirmation to always return true
const stubConfirm = sinon.stub(inquirer, "confirm").resolves(true);
const { stdout } = await runCommand(
withOpts(["schema abandon", "--dir=test/testdata"])
);
expect(stdout).to.contain(`Schema has been abandoned`);
// Restore the stub after the test
stubConfirm.restore();
});

it("will abandon even when schema isn't ready", async () => {
nock(getEndpoint(), { allowUnmocked: false })
.persist()
.post("/", matchFqlReq(q.Now()))
.reply(200, new Date())
.get("/schema/1/staged/status?diff=true")
.reply(200, {
version: 3,
status: "pending",
diff: diff.diff,
})
.post("/schema/1/staged/abandon?version=3")
.reply(200, { version: 0 });

// Stubbing the confirmation to always return true
const stubConfirm = sinon.stub(inquirer, "confirm").resolves(true);
const { stdout } = await runCommand(
withOpts(["schema abandon", "--dir=test/testdata"])
);
expect(stdout).to.contain(`Schema has been abandoned`);
// Restore the stub after the test
stubConfirm.restore();
});
});

const testdir = "test/testdata";
Expand Down
7 changes: 5 additions & 2 deletions test/integ/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,11 @@ export const shellOk = async (
return res.stdout;
};

export const shellErr = async (cmd: string): Promise<string> => {
const res = await shell(cmd);
export const shellErr = async (
cmd: string,
secret?: string
): Promise<string> => {
const res = await shell(cmd, secret);
if (res.ok) {
fail(`Command should not have exitted succesfully:\n${res.stdout}`);
}
Expand Down
Loading