@cipherly/plane-cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +65 -0
  3. package/dist/cycles/create.cycles.js +44 -0
  4. package/dist/cycles/delete.cycles.js +30 -0
  5. package/dist/cycles/index.js +21 -0
  6. package/dist/cycles/list.cycles.js +42 -0
  7. package/dist/cycles/update.cycles.js +46 -0
  8. package/dist/cycles/work-items/index.js +17 -0
  9. package/dist/cycles/work-items/list.cycles.work-items.js +43 -0
  10. package/dist/labels/create.labels.js +34 -0
  11. package/dist/labels/delete.labels.js +30 -0
  12. package/dist/labels/index.js +20 -0
  13. package/dist/labels/list.labels.js +36 -0
  14. package/dist/labels/update.labels.js +36 -0
  15. package/dist/plane.js +60 -0
  16. package/dist/projects/create.projects.js +38 -0
  17. package/dist/projects/delete.projects.js +28 -0
  18. package/dist/projects/index.js +20 -0
  19. package/dist/projects/list.projects.js +35 -0
  20. package/dist/projects/update.projects.js +39 -0
  21. package/dist/states/create.states.js +37 -0
  22. package/dist/states/delete.states.js +30 -0
  23. package/dist/states/index.js +20 -0
  24. package/dist/states/list.states.js +36 -0
  25. package/dist/states/update.states.js +36 -0
  26. package/dist/users/index.js +17 -0
  27. package/dist/users/me.users.js +36 -0
  28. package/dist/utils.js +63 -0
  29. package/dist/work-items/create.work-items.js +51 -0
  30. package/dist/work-items/delete.work-items.js +30 -0
  31. package/dist/work-items/index.js +21 -0
  32. package/dist/work-items/list.work-items.js +44 -0
  33. package/dist/work-items/types/index.js +17 -0
  34. package/dist/work-items/types/list.types.work-items.js +40 -0
  35. package/dist/work-items/update.work-items.js +41 -0
  36. package/package.json +29 -0
  37. package/src/cycles/create.cycles.ts +39 -0
  38. package/src/cycles/delete.cycles.ts +25 -0
  39. package/src/cycles/index.ts +5 -0
  40. package/src/cycles/list.cycles.ts +37 -0
  41. package/src/cycles/update.cycles.ts +41 -0
  42. package/src/cycles/work-items/index.ts +1 -0
  43. package/src/cycles/work-items/list.cycles.work-items.ts +40 -0
  44. package/src/labels/create.labels.ts +29 -0
  45. package/src/labels/delete.labels.ts +25 -0
  46. package/src/labels/index.ts +5 -0
  47. package/src/labels/list.labels.ts +31 -0
  48. package/src/labels/update.labels.ts +31 -0
  49. package/src/plane.ts +97 -0
  50. package/src/projects/create.projects.ts +33 -0
  51. package/src/projects/delete.projects.ts +23 -0
  52. package/src/projects/index.ts +5 -0
  53. package/src/projects/list.projects.ts +30 -0
  54. package/src/projects/update.projects.ts +32 -0
  55. package/src/states/create.states.ts +32 -0
  56. package/src/states/delete.states.ts +25 -0
  57. package/src/states/index.ts +5 -0
  58. package/src/states/list.states.ts +31 -0
  59. package/src/states/update.states.ts +31 -0
  60. package/src/users/index.ts +1 -0
  61. package/src/users/me.users.ts +30 -0
  62. package/src/utils.ts +81 -0
  63. package/src/work-items/create.work-items.ts +85 -0
  64. package/src/work-items/delete.work-items.ts +25 -0
  65. package/src/work-items/index.ts +5 -0
  66. package/src/work-items/list.work-items.ts +43 -0
  67. package/src/work-items/types/index.ts +1 -0
  68. package/src/work-items/types/list.types.work-items.ts +36 -0
  69. package/src/work-items/update.work-items.ts +79 -0
  70. package/tsconfig.json +14 -0
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderWorkItem = exports.listWorkItems = void 0;
4
+ const commander_1 = require("commander");
5
+ const utils_1 = require("../utils");
6
+ exports.listWorkItems = new commander_1.Command("list")
7
+ .description("List work items")
8
+ .requiredOption("-p, --project-id <projectId>", "Project's ID")
9
+ .action(async (__, cmd) => {
10
+ if (cmd.parent == null)
11
+ return;
12
+ const { apiKey, apiBase, workspaceSlug, json } = (0, utils_1.checkRequiredOptionsAndReturn)(cmd);
13
+ const projectId = cmd.getOptionValue("projectId");
14
+ const { result, status } = await (0, utils_1.requestPlaneAPI)({
15
+ apiBase,
16
+ apiKey,
17
+ endpoint: `workspaces/${workspaceSlug}/projects/${projectId}/work-items/`,
18
+ method: "GET",
19
+ params: {
20
+ expand: "state,labels,assignees",
21
+ },
22
+ });
23
+ if (json)
24
+ console.log(JSON.stringify(result));
25
+ else {
26
+ if (status !== 200)
27
+ console.table(result);
28
+ else
29
+ console.table(result.results.map(exports.renderWorkItem));
30
+ }
31
+ });
32
+ const renderWorkItem = (workItem) => {
33
+ return {
34
+ id: workItem.id,
35
+ name: workItem.name,
36
+ state: (workItem.state && workItem.state.name) || null,
37
+ labels: (workItem.labels && workItem.labels.map((label) => label.name)) ||
38
+ [],
39
+ assignees: (workItem.assignees &&
40
+ workItem.assignees.map((user) => `${user.first_name} ${user.last_name}`.trim())) ||
41
+ [],
42
+ };
43
+ };
44
+ exports.renderWorkItem = renderWorkItem;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./list.types.work-items"), exports);
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderWorkItemType = exports.listWorkItemTypes = void 0;
4
+ const commander_1 = require("commander");
5
+ const utils_1 = require("../../utils");
6
+ exports.listWorkItemTypes = new commander_1.Command("list")
7
+ .description("List work item types")
8
+ .requiredOption("-p, --project-id <projectId>", "Project's ID")
9
+ .action(async (__, cmd) => {
10
+ if (cmd.parent == null)
11
+ return;
12
+ const { apiKey, apiBase, workspaceSlug, json } = (0, utils_1.checkRequiredOptionsAndReturn)(cmd);
13
+ const projectId = cmd.getOptionValue("projectId");
14
+ const { result, status } = await (0, utils_1.requestPlaneAPI)({
15
+ apiBase,
16
+ apiKey,
17
+ endpoint: `workspaces/${workspaceSlug}/projects/${projectId}/work-item-types/`,
18
+ method: "GET",
19
+ });
20
+ if (json)
21
+ console.log(JSON.stringify(result));
22
+ else {
23
+ if (status !== 200)
24
+ console.table(result);
25
+ else
26
+ console.table(result.results.map(exports.renderWorkItemType));
27
+ }
28
+ });
29
+ const renderWorkItemType = (workItemType) => {
30
+ return {
31
+ id: workItemType.id,
32
+ name: workItemType.name,
33
+ description: workItemType.description,
34
+ is_epic: workItemType.is_epic,
35
+ is_default: workItemType.is_default,
36
+ is_active: workItemType.is_active,
37
+ level: workItemType.level,
38
+ };
39
+ };
40
+ exports.renderWorkItemType = renderWorkItemType;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.updateWorkItem = void 0;
4
+ const commander_1 = require("commander");
5
+ const utils_1 = require("../utils");
6
+ const list_work_items_1 = require("./list.work-items");
7
+ exports.updateWorkItem = new commander_1.Command("update")
8
+ .description("Update a work-item")
9
+ .requiredOption("-p, --project-id <projectId>", "Project's ID")
10
+ .requiredOption("-w, --work-item-id <workItemId>", "Work item's ID")
11
+ .option("-n, --name [name]", "Work item's name")
12
+ .option("-d, --description [description]", "Work item's description in HTML")
13
+ .action(async (__, cmd) => {
14
+ if (cmd.parent == null)
15
+ return;
16
+ const { apiKey, apiBase, workspaceSlug, json } = (0, utils_1.checkRequiredOptionsAndReturn)(cmd);
17
+ const projectId = cmd.getOptionValue("projectId");
18
+ const workItemId = cmd.getOptionValue("workItemId");
19
+ const name = cmd.getOptionValue("name");
20
+ const description = cmd.getOptionValue("description");
21
+ const body = {};
22
+ if (name !== undefined)
23
+ body.name = name;
24
+ if (description !== undefined)
25
+ body.description = description;
26
+ const { result, status } = await (0, utils_1.requestPlaneAPI)({
27
+ apiBase,
28
+ apiKey,
29
+ endpoint: `workspaces/${workspaceSlug}/projects/${projectId}/work-items/${workItemId}/`,
30
+ method: "PATCH",
31
+ body,
32
+ });
33
+ if (json)
34
+ console.log(JSON.stringify(result));
35
+ else {
36
+ if (status !== 200)
37
+ console.table(result);
38
+ else
39
+ console.table((0, list_work_items_1.renderWorkItem)(result));
40
+ }
41
+ });
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@cipherly/plane-cli",
3
+ "version": "1.0.0",
4
+ "description": "CLI for api.plane.so",
5
+ "packageManager": "pnpm@8.8.0",
6
+ "bin": {
7
+ "plane": "dist/plane.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc -p tsconfig.json",
11
+ "dev": "ts-node src/plane.ts"
12
+ },
13
+ "engines": {
14
+ "node": ">=18"
15
+ },
16
+ "dependencies": {
17
+ "commander": "^11.1.0"
18
+ },
19
+ "devDependencies": {
20
+ "@types/node": "^20.8.1",
21
+ "ts-node": "^10.9.1",
22
+ "typescript": "^5.2.2"
23
+ },
24
+ "keywords": [
25
+ "plane",
26
+ "cli"
27
+ ],
28
+ "license": "Apache-2.0"
29
+ }
@@ -0,0 +1,39 @@
1
+ import { Command } from "commander";
2
+ import { checkRequiredOptionsAndReturn, requestPlaneAPI } from "../utils";
3
+ import { renderCycle } from "./list.cycles";
4
+
5
+ export const createCycle = new Command("create")
6
+ .description("Create a new cycle")
7
+ .requiredOption("-p, --project-id <projectId>", "Project's ID")
8
+ .requiredOption("-n, --name <name>", "Cycle's name")
9
+ .option("-d, --description [description]", "Cycle's description")
10
+ .option("-sd, --start-date [startDate]", "Cycle's start date")
11
+ .option("-ed, --end-date [endDate]", "Cycle's end date")
12
+ .action(async (__, cmd: Command) => {
13
+ if (cmd.parent == null) return;
14
+ const { apiKey, apiBase, workspaceSlug, json } =
15
+ checkRequiredOptionsAndReturn(cmd);
16
+ const projectId = cmd.getOptionValue("projectId");
17
+ const name = cmd.getOptionValue("name");
18
+ const description = cmd.getOptionValue("description");
19
+ const startDate = cmd.getOptionValue("startDate");
20
+ const endDate = cmd.getOptionValue("endDate");
21
+ const { result, status } = await requestPlaneAPI({
22
+ apiBase,
23
+ apiKey,
24
+ endpoint: `workspaces/${workspaceSlug}/projects/${projectId}/cycles/`,
25
+ method: "POST",
26
+ body: {
27
+ name,
28
+ description,
29
+ project_id: projectId,
30
+ start_date: startDate,
31
+ end_date: endDate,
32
+ },
33
+ });
34
+ if (json) console.log(JSON.stringify(result));
35
+ else {
36
+ if (status !== 201) console.table(result);
37
+ else console.table(renderCycle(result));
38
+ }
39
+ });
@@ -0,0 +1,25 @@
1
+ import { Command } from "commander";
2
+ import { checkRequiredOptionsAndReturn, requestPlaneAPI } from "../utils";
3
+
4
+ export const deleteCycle = new Command("delete")
5
+ .description("Delete a cycle")
6
+ .requiredOption("-p, --project-id <projectId>", "Project's ID")
7
+ .requiredOption("-c, --cycle-id <cycleId>", "Cycle's ID")
8
+ .action(async (__, cmd: Command) => {
9
+ if (cmd.parent == null) return;
10
+ const { apiKey, apiBase, workspaceSlug, json } =
11
+ checkRequiredOptionsAndReturn(cmd);
12
+ const projectId = cmd.getOptionValue("projectId");
13
+ const cycleId = cmd.getOptionValue("cycleId");
14
+ const { result, status } = await requestPlaneAPI({
15
+ apiBase,
16
+ apiKey,
17
+ endpoint: `workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/`,
18
+ method: "DELETE",
19
+ });
20
+ if (json) console.log(JSON.stringify(result));
21
+ else {
22
+ if (status !== 204) console.table(result);
23
+ else console.table(result);
24
+ }
25
+ });
@@ -0,0 +1,5 @@
1
+ export * from "./list.cycles";
2
+ export * from "./work-items";
3
+ export * from "./create.cycles";
4
+ export * from "./update.cycles";
5
+ export * from "./delete.cycles";
@@ -0,0 +1,37 @@
1
+ import { Command } from "commander";
2
+ import { checkRequiredOptionsAndReturn, requestPlaneAPI } from "../utils";
3
+
4
+ export const listCycles = new Command("list")
5
+ .description("List cycles")
6
+ .requiredOption("-p, --project-id <projectId>", "Project's ID")
7
+ .action(async (__, cmd: Command) => {
8
+ if (cmd.parent == null) return;
9
+ const { apiKey, apiBase, workspaceSlug, json } =
10
+ checkRequiredOptionsAndReturn(cmd);
11
+ const projectId = cmd.getOptionValue("projectId");
12
+ const { result, status } = await requestPlaneAPI({
13
+ apiBase,
14
+ apiKey,
15
+ endpoint: `workspaces/${workspaceSlug}/projects/${projectId}/cycles/`,
16
+ method: "GET",
17
+ });
18
+ if (json) console.log(JSON.stringify(result));
19
+ else {
20
+ if (status !== 200) console.table(result);
21
+ else console.table(result.results.map(renderCycle));
22
+ }
23
+ });
24
+
25
+ export const renderCycle = (cycle: any) => {
26
+ return {
27
+ id: cycle.id,
28
+ name: cycle.name,
29
+ description: cycle.description,
30
+ total_issues: cycle.total_issues,
31
+ cancelled_issues: cycle.cancelled_issues,
32
+ completed_issues: cycle.completed_issues,
33
+ started_issues: cycle.started_issues,
34
+ unstarted_issues: cycle.unstarted_issues,
35
+ backlog_issues: cycle.backlog_issues,
36
+ };
37
+ };
@@ -0,0 +1,41 @@
1
+ import { Command } from "commander";
2
+ import { checkRequiredOptionsAndReturn, requestPlaneAPI } from "../utils";
3
+ import { renderCycle } from "./list.cycles";
4
+
5
+ export const updateCycle = new Command("update")
6
+ .description("Update a cycle")
7
+ .requiredOption("-p, --project-id <projectId>", "Project's ID")
8
+ .requiredOption("-c, --cycle-id <cycleId>", "Cycle's ID")
9
+ .option("-n, --name [name]", "Cycle's name")
10
+ .option("-d, --description [description]", "Cycle's description")
11
+ .option("-sd, --start-date [startDate]", "Cycle's start date")
12
+ .option("-ed, --end-date [endDate]", "Cycle's end date")
13
+ .action(async (__, cmd: Command) => {
14
+ if (cmd.parent == null) return;
15
+ const { apiKey, apiBase, workspaceSlug, json } =
16
+ checkRequiredOptionsAndReturn(cmd);
17
+ const projectId = cmd.getOptionValue("projectId");
18
+ const cycleId = cmd.getOptionValue("cycleId");
19
+ const name = cmd.getOptionValue("name");
20
+ const description = cmd.getOptionValue("description");
21
+ const startDate = cmd.getOptionValue("startDate");
22
+ const endDate = cmd.getOptionValue("endDate");
23
+ const { result, status } = await requestPlaneAPI({
24
+ apiBase,
25
+ apiKey,
26
+ endpoint: `workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/`,
27
+ method: "PATCH",
28
+ body: {
29
+ name,
30
+ description,
31
+ project_id: projectId,
32
+ start_date: startDate,
33
+ end_date: endDate,
34
+ },
35
+ });
36
+ if (json) console.log(JSON.stringify(result));
37
+ else {
38
+ if (status !== 200) console.table(result);
39
+ else console.table(renderCycle(result));
40
+ }
41
+ });
@@ -0,0 +1 @@
1
+ export * from "./list.cycles.work-items";
@@ -0,0 +1,40 @@
1
+ import { Command } from "commander";
2
+ import { checkRequiredOptionsAndReturn, requestPlaneAPI } from "../../utils";
3
+
4
+ export const listCyclesWorkItems = new Command("list-work-items")
5
+ .description("List cycle work items")
6
+ .requiredOption("-p, --project-id <projectId>", "Project's ID")
7
+ .requiredOption("-c, --cycle-id <cycleId>", "Cycle's ID")
8
+ .action(async (__, cmd: Command) => {
9
+ if (cmd.parent == null) return;
10
+ const { apiKey, apiBase, workspaceSlug, json } =
11
+ checkRequiredOptionsAndReturn(cmd);
12
+ const projectId = cmd.getOptionValue("projectId");
13
+ const cycleId = cmd.getOptionValue("cycleId");
14
+ const { result, status } = await requestPlaneAPI({
15
+ apiBase,
16
+ apiKey,
17
+ endpoint: `workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/cycle-issues/`,
18
+ method: "GET",
19
+ params: {
20
+ expand: "state,labels,assignees",
21
+ },
22
+ });
23
+ if (json) console.log(JSON.stringify(result));
24
+ else {
25
+ if (status !== 200) console.table(result);
26
+ else console.table(result.results.map(renderCycleWorkItem));
27
+ }
28
+ });
29
+
30
+ export const renderCycleWorkItem = (workItem: any) => {
31
+ return {
32
+ id: workItem.id,
33
+ name: workItem.name,
34
+ state: workItem.state.name,
35
+ labels: workItem.labels.map((label: any) => label.name),
36
+ assignees: workItem.assignees.map((user: any) =>
37
+ `${user.first_name} ${user.last_name}`.trim(),
38
+ ),
39
+ };
40
+ };
@@ -0,0 +1,29 @@
1
+ import { Command } from "commander";
2
+ import { checkRequiredOptionsAndReturn, requestPlaneAPI } from "../utils";
3
+ import { renderLabel } from "./list.labels";
4
+
5
+ export const createLabel = new Command("create")
6
+ .description("Create a new label")
7
+ .requiredOption("-p, --project-id <projectId>", "Project's ID")
8
+ .requiredOption("-n, --name <name>", "Label's name")
9
+ .action(async (__, cmd: Command) => {
10
+ if (cmd.parent == null) return;
11
+ const { apiKey, apiBase, workspaceSlug, json } =
12
+ checkRequiredOptionsAndReturn(cmd);
13
+ const projectId = cmd.getOptionValue("projectId");
14
+ const name = cmd.getOptionValue("name");
15
+ const { result, status } = await requestPlaneAPI({
16
+ apiBase,
17
+ apiKey,
18
+ endpoint: `workspaces/${workspaceSlug}/projects/${projectId}/labels/`,
19
+ method: "POST",
20
+ body: {
21
+ name,
22
+ },
23
+ });
24
+ if (json) console.log(JSON.stringify(result));
25
+ else {
26
+ if (status !== 201) console.table(result);
27
+ else console.table(renderLabel(result));
28
+ }
29
+ });
@@ -0,0 +1,25 @@
1
+ import { Command } from "commander";
2
+ import { checkRequiredOptionsAndReturn, requestPlaneAPI } from "../utils";
3
+
4
+ export const deleteLabel = new Command("delete")
5
+ .description("Delete a label")
6
+ .requiredOption("-p, --project-id <projectId>", "Project's ID")
7
+ .requiredOption("-l, --label-id <labelId>", "Label's ID")
8
+ .action(async (__, cmd: Command) => {
9
+ if (cmd.parent == null) return;
10
+ const { apiKey, apiBase, workspaceSlug, json } =
11
+ checkRequiredOptionsAndReturn(cmd);
12
+ const projectId = cmd.getOptionValue("projectId");
13
+ const labelId = cmd.getOptionValue("labelId");
14
+ const { result, status } = await requestPlaneAPI({
15
+ apiBase,
16
+ apiKey,
17
+ endpoint: `workspaces/${workspaceSlug}/projects/${projectId}/labels/${labelId}/`,
18
+ method: "DELETE",
19
+ });
20
+ if (json) console.log(JSON.stringify(result));
21
+ else {
22
+ if (status !== 204) console.table(result);
23
+ else console.table(result);
24
+ }
25
+ });
@@ -0,0 +1,5 @@
1
+ export * from "./list.labels";
2
+ export * from "./create.labels";
3
+ export * from "./update.labels";
4
+ export * from "./delete.labels";
5
+
@@ -0,0 +1,31 @@
1
+ import { Command } from "commander";
2
+ import { checkRequiredOptionsAndReturn, requestPlaneAPI } from "../utils";
3
+
4
+ export const listLabels = new Command("list")
5
+ .description("List labels")
6
+ .requiredOption("-p, --project-id <projectId>", "Project's ID")
7
+ .action(async (__, cmd: Command) => {
8
+ if (cmd.parent == null) return;
9
+ const { apiKey, apiBase, workspaceSlug, json } =
10
+ checkRequiredOptionsAndReturn(cmd);
11
+ const projectId = cmd.getOptionValue("projectId");
12
+ const { result, status } = await requestPlaneAPI({
13
+ apiBase,
14
+ apiKey,
15
+ endpoint: `workspaces/${workspaceSlug}/projects/${projectId}/labels/`,
16
+ method: "GET",
17
+ });
18
+ if (json) console.log(JSON.stringify(result));
19
+ else {
20
+ if (status !== 200) console.table(result);
21
+ else console.table(result.results.map(renderLabel));
22
+ }
23
+ });
24
+
25
+ export const renderLabel = (label: any) => {
26
+ return {
27
+ id: label.id,
28
+ name: label.name,
29
+ description: label.description,
30
+ };
31
+ };
@@ -0,0 +1,31 @@
1
+ import { Command } from "commander";
2
+ import { checkRequiredOptionsAndReturn, requestPlaneAPI } from "../utils";
3
+ import { renderLabel } from "./list.labels";
4
+
5
+ export const updateLabel = new Command("update")
6
+ .description("Update a label")
7
+ .requiredOption("-p, --project-id <projectId>", "Project's ID")
8
+ .requiredOption("-l, --label-id <labelId>", "Label's ID")
9
+ .requiredOption("-n, --name <name>", "Label's name")
10
+ .action(async (__, cmd: Command) => {
11
+ if (cmd.parent == null) return;
12
+ const { apiKey, apiBase, workspaceSlug, json } =
13
+ checkRequiredOptionsAndReturn(cmd);
14
+ const projectId = cmd.getOptionValue("projectId");
15
+ const labelId = cmd.getOptionValue("labelId");
16
+ const name = cmd.getOptionValue("name");
17
+ const { result, status } = await requestPlaneAPI({
18
+ apiBase,
19
+ apiKey,
20
+ endpoint: `workspaces/${workspaceSlug}/projects/${projectId}/labels/${labelId}/`,
21
+ method: "PATCH",
22
+ body: {
23
+ name,
24
+ },
25
+ });
26
+ if (json) console.log(JSON.stringify(result));
27
+ else {
28
+ if (status !== 200) console.table(result);
29
+ else console.table(renderLabel(result));
30
+ }
31
+ });
package/src/plane.ts ADDED
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import {
4
+ createProject,
5
+ deleteProject,
6
+ listProjects,
7
+ updateProject,
8
+ } from "./projects";
9
+ import {
10
+ createWorkItem,
11
+ deleteWorkItem,
12
+ listWorkItems,
13
+ listWorkItemTypes,
14
+ updateWorkItem,
15
+ } from "./work-items";
16
+ import { createState, deleteState, listStates, updateState } from "./states";
17
+ import { createLabel, deleteLabel, listLabels, updateLabel } from "./labels";
18
+ import {
19
+ createCycle,
20
+ deleteCycle,
21
+ listCycles,
22
+ listCyclesWorkItems,
23
+ updateCycle,
24
+ } from "./cycles";
25
+ import { getCurrentUser } from "./users";
26
+
27
+ const program = new Command();
28
+ program.name("plane").description("CLI for api.plane.so").version("1.0.0");
29
+
30
+ program
31
+ .command("projects")
32
+ .description("Manage projects")
33
+ .addCommand(listProjects)
34
+ .addCommand(createProject)
35
+ .addCommand(updateProject)
36
+ .addCommand(deleteProject);
37
+
38
+ program
39
+ .command("work-items")
40
+ .description("Manage work items")
41
+ .addCommand(listWorkItems)
42
+ .addCommand(createWorkItem)
43
+ .addCommand(updateWorkItem)
44
+ .addCommand(deleteWorkItem);
45
+
46
+ program
47
+ .command("work-item-types")
48
+ .description("Manage work item types")
49
+ .addCommand(listWorkItemTypes);
50
+
51
+ program
52
+ .command("states")
53
+ .description("Manage states")
54
+ .addCommand(listStates)
55
+ .addCommand(createState)
56
+ .addCommand(updateState)
57
+ .addCommand(deleteState);
58
+
59
+ program
60
+ .command("labels")
61
+ .description("Manage labels")
62
+ .addCommand(listLabels)
63
+ .addCommand(createLabel)
64
+ .addCommand(updateLabel)
65
+ .addCommand(deleteLabel);
66
+
67
+ program
68
+ .command("cycles")
69
+ .description("Manage cycles")
70
+ .addCommand(listCycles)
71
+ .addCommand(listCyclesWorkItems)
72
+ .addCommand(createCycle)
73
+ .addCommand(updateCycle)
74
+ .addCommand(deleteCycle);
75
+
76
+ program.command("users").description("Manage users").addCommand(getCurrentUser);
77
+
78
+ program.commands.forEach((cmd) => {
79
+ cmd.requiredOption(
80
+ "--api-key <key>",
81
+ "Plane API key",
82
+ process.env.PLANE_API_KEY,
83
+ );
84
+ cmd.requiredOption(
85
+ "--api-base <url>",
86
+ "Plane API base",
87
+ process.env.PLANE_API_BASE || "api.plane.so",
88
+ );
89
+ cmd.requiredOption(
90
+ "--workspace-slug <slug>",
91
+ "Workspace slug",
92
+ process.env.PLANE_WORKSPACE_SLUG,
93
+ );
94
+ cmd.option("-j, --json", "Print in JSON format");
95
+ });
96
+
97
+ program.parse();
@@ -0,0 +1,33 @@
1
+ import { Command } from "commander";
2
+ import { checkRequiredOptionsAndReturn, requestPlaneAPI } from "../utils";
3
+ import { renderProject } from "./list.projects";
4
+
5
+ export const createProject = new Command("create")
6
+ .description("Create a new project")
7
+ .requiredOption("-n, --name <name>", "Project's name")
8
+ .requiredOption("-i, --identifier <identifier>", "Project' identifier")
9
+ .option("-d, --description [description]", "Project's description")
10
+ .action(async (__, cmd: Command) => {
11
+ if (cmd.parent == null) return;
12
+ const { apiKey, apiBase, workspaceSlug, json } =
13
+ checkRequiredOptionsAndReturn(cmd);
14
+ const name = cmd.getOptionValue("name");
15
+ const identifier = cmd.getOptionValue("identifier");
16
+ const description = cmd.getOptionValue("description");
17
+ const { result, status } = await requestPlaneAPI({
18
+ apiBase,
19
+ apiKey,
20
+ endpoint: `workspaces/${workspaceSlug}/projects/`,
21
+ method: "POST",
22
+ body: {
23
+ name,
24
+ identifier,
25
+ description,
26
+ },
27
+ });
28
+ if (json) console.log(JSON.stringify(result));
29
+ else {
30
+ if (status !== 201) console.table(result);
31
+ else console.table(renderProject(result));
32
+ }
33
+ });
@@ -0,0 +1,23 @@
1
+ import { Command } from "commander";
2
+ import { checkRequiredOptionsAndReturn, requestPlaneAPI } from "../utils";
3
+
4
+ export const deleteProject = new Command("delete")
5
+ .description("Delete a project")
6
+ .requiredOption("-p, --project-id <projectId>", "Project's ID")
7
+ .action(async (__, cmd: Command) => {
8
+ if (cmd.parent == null) return;
9
+ const { apiKey, apiBase, workspaceSlug, json } =
10
+ checkRequiredOptionsAndReturn(cmd);
11
+ const projectId = cmd.getOptionValue("projectId");
12
+ const { result, status } = await requestPlaneAPI({
13
+ apiBase,
14
+ apiKey,
15
+ endpoint: `workspaces/${workspaceSlug}/projects/${projectId}/`,
16
+ method: "DELETE",
17
+ });
18
+ if (json) console.log(JSON.stringify(result));
19
+ else {
20
+ if (status !== 204) console.table(result);
21
+ else console.table(result);
22
+ }
23
+ });
@@ -0,0 +1,5 @@
1
+ export * from "./list.projects";
2
+ export * from "./create.projects";
3
+ export * from "./update.projects";
4
+ export * from "./delete.projects";
5
+