Skip to content

Commit

Permalink
feat: add project tags create/list/delete (#63)
Browse files Browse the repository at this point in the history
Depends on #57
  • Loading branch information
ps-kwang authored Apr 8, 2024
1 parent 2846fb2 commit 0137724
Show file tree
Hide file tree
Showing 5 changed files with 306 additions and 0 deletions.
6 changes: 6 additions & 0 deletions api/projects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,9 @@ export const projectSecrets = {
update: client("/projects/{id}/secrets/{name}").patch,
delete: client("/projects/{id}/secrets/{name}").delete,
};

export const projectTags = {
list: client("/projects/{id}/tags").get,
create: client("/projects/{id}/tags").post,
delete: client("/projects/{id}/tags").delete,
};
85 changes: 85 additions & 0 deletions commands/project/tags/create/mod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { command, flags } from "../../../../zcli.ts";
import { args, z } from "../../../../zcli.ts";
import { input } from "../../../../prompts/input.ts";
import { asserts } from "../../../../lib/asserts.ts";
import { loading } from "../../../../lib/loading.ts";
import { dataTable } from "../../../../lib/data-table.ts";
import { pickJson } from "../../../../lib/pick-json.ts";
import * as psFlags from "../../../../flags.ts";
import { defaultFields } from "../mod.ts";
import { projects, projectTags } from "../../../../api/projects.ts";
import { select } from "../../../../prompts/select.ts";

/**
* This variable is automatically generated by `zcli add`. Do not remove this
* or change its name unless you're no longer using `zcli add`.
*/
const subCommands: ReturnType<typeof command>[] = [];

export const create = command("create", {
short: "Create a new project tag",
long: `
Create a new project tag. This command will prompt you for a name if you don't
provide one.
`,
commands: subCommands,

args: args({ short: "Create a project tag with these properties." }).tuple([
z.string().describe("The project ID to create a tag for."),
z.string().describe("The name of the project tag to create."),
]).optional(),

flags: flags({
fields: psFlags.fields,
}),

// We use command metadata in the `persistentPreRun` function to check if a
// command requires an API key. If it does, we'll check to see if one is
// set. If not, we'll throw an error.
meta: {
requireApiKey: true,
},
}).run(async function* ({ args, flags }) {
let [projectId, name] = args;

if (!projectId) {
const existingProjects = await loading(projects.list({ limit: 50 }));
asserts(existingProjects.ok, existingProjects);

const selected = await select(
"Select a project:",
existingProjects.data.items,
{
filter(input, option) {
return option.name.toLowerCase().startsWith(input);
},
renderOption(option, isSelected) {
return `${isSelected ? ">" : " "} ${option.name}`;
},
},
);

asserts(selected, "No project selected.");
projectId = selected.id;
}

if (!name) {
name = await input("Tag name:");
asserts(name, "You must provide a name for the project tag.");
}

const result = await loading(projectTags.create({ id: projectId, name }), {
enabled: !flags.json,
});
asserts(result.ok, result);

if (!flags.json) {
for await (
const line of dataTable([result.data], flags.fields ?? defaultFields)
) {
yield line;
}
} else {
yield pickJson(result.data, flags.fields);
}
});
102 changes: 102 additions & 0 deletions commands/project/tags/delete/mod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { projects, projectTags } from "../../../../api/projects.ts";
import { asserts } from "../../../../lib/asserts.ts";
import { args, command, flag, flags, z } from "../../../../zcli.ts";
import { select } from "../../../../prompts/select.ts";
import { dataTable } from "../../../../lib/data-table.ts";
import { pickJson } from "../../../../lib/pick-json.ts";
import { loading } from "../../../../lib/loading.ts";
import { defaultFields } from "../mod.ts";

/**
* This variable is automatically generated by `zcli add`. Do not remove this
* or change its name unless you're no longer using `zcli add`.
*/
const subCommands: ReturnType<typeof command>[] = [];

export const delete_ = command("delete", {
short: "Delete a project tag.",
long: `
Delete a project tag by its name. If you don't provide a name, this command
will prompt you for one.
`,
commands: subCommands,
args: args().tuple([
z.string().describe("The project ID to delete from."),
z.string().describe("The project tag to delete."),
])
.optional(),
flags: flags({
fields: flag({
short: "The fields to include in the response.",
aliases: ["F"],
}).array(z.string()).optional(),
}),
// We use command metadata in the `persistentPreRun` function to check if a
// command requires an API key. If it does, we'll check to see if one is
// set. If not, we'll throw an error.
meta: {
requireApiKey: true,
},
}).run(async function* ({ args, flags }) {
let [projectId, name] = args;

if (!projectId) {
const existingProjects = await loading(projects.list({ limit: 50 }));
asserts(existingProjects.ok, existingProjects);

const selected = await select(
"Select a project:",
existingProjects.data.items,
{
filter(input, option) {
return option.name.toLowerCase().startsWith(input);
},
renderOption(option, isSelected) {
return `${isSelected ? ">" : " "} ${option.name}`;
},
},
);

asserts(selected, "No project selected.");
projectId = selected.id;
}

if (!name) {
const existingProjects = await loading(
projectTags.list({ id: projectId, limit: 50 }),
);
asserts(existingProjects.ok, existingProjects);

const selected = await select(
"Select a tag:",
existingProjects.data.items,
{
filter(input, option) {
return option.name.toLowerCase().startsWith(input);
},
renderOption(option, isSelected) {
return `${isSelected ? ">" : " "} ${option.name}`;
},
},
);

asserts(selected, "No tag selected.");
name = selected.name;
}

const result = await loading(projectTags.delete({ id: projectId, name }), {
enabled: !flags.json,
});

asserts(result.ok, result);

if (!flags.json) {
for await (
const line of dataTable([result.data], flags.fields ?? defaultFields)
) {
yield line;
}
} else {
yield pickJson(result.data, flags.fields);
}
});
85 changes: 85 additions & 0 deletions commands/project/tags/list/mod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { args, command } from "../../../../zcli.ts";
import { asserts } from "../../../../lib/asserts.ts";
import { dataTable } from "../../../../lib/data-table.ts";
import { loading } from "../../../../lib/loading.ts";
import * as psFlags from "../../../../flags.ts";
import { pickJson } from "../../../../lib/pick-json.ts";
import { defaultFields } from "../mod.ts";
import { projects } from "../../../../api/projects.ts";
import { projectTags } from "../../../../api/projects.ts";
import { select } from "../../../../prompts/select.ts";
import { z } from "../../../../zcli.ts";

/**
* This variable is automatically generated by `zcli add`. Do not remove this
* or change its name unless you're no longer using `zcli add`.
*/
const subCommands: ReturnType<typeof command>[] = [];

export const list = command("list", {
short: "List project tags.",
long: ({ root }) => `
List project tags in your team.
Pick a subset of fields to display:
\`\`\`
${root.name} project tags list -F id -F name -F dtCreated
\`\`\`
`,
commands: subCommands,
args: args().tuple([
z.string().describe("The project ID to list tags for."),
])
.optional(),
flags: psFlags.paginator,
// We use command metadata in the `persistentPreRun` function to check if a
// command requires an API key. If it does, we'll check to see if one is
// set. If not, we'll throw an error.
meta: {
requireApiKey: true,
},
}).run(async function* ({ args, flags }) {
let [projectId] = args;

if (!projectId) {
const existingProjects = await loading(projects.list({ limit: 50 }));
asserts(existingProjects.ok, existingProjects);

const selected = await select(
"Select a project:",
existingProjects.data.items,
{
filter(input, option) {
return option.name.toLowerCase().startsWith(input);
},
renderOption(option, isSelected) {
return `${isSelected ? ">" : " "} ${option.name}`;
},
},
);

asserts(selected, "No project selected.");
projectId = selected.id;
}

const result = await loading(
projectTags.list({
id: projectId,
...flags,
order: flags.asc ? "asc" : undefined,
}),
{ enabled: !flags.json },
);

asserts(result.ok, result);

if (!flags.json) {
for await (
const line of dataTable(result.data.items, flags.fields ?? defaultFields)
) {
yield line;
}
} else {
yield pickJson(result.data, flags.fields);
}
});
28 changes: 28 additions & 0 deletions commands/project/tags/mod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { command } from "../../../zcli.ts";
import { create } from "./create/mod.ts";
import { list } from "./list/mod.ts";
import { delete_ } from "./delete/mod.ts";

export const defaultFields = [
"id",
"name",
];

/**
* This variable is automatically generated by `zcli add`. Do not remove this
* or change its name unless you're no longer using `zcli add`.
*/
const subCommands: ReturnType<typeof command>[] = [
list,
create,
delete_,
];

export const tag = command("tag", {
short: "Manage your Paperspace project tags.",
commands: subCommands,
}).run(function* ({ ctx }) {
for (const line of tag.help(ctx)) {
yield line;
}
});

0 comments on commit 0137724

Please sign in to comment.