@ysicing/plane-cli 1.0.0 → 1.0.2
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.
- package/README.md +112 -121
- package/package.json +1 -1
- package/src/commands/auth.js +2 -2
- package/src/commands/config.js +27 -4
- package/src/commands/issue.js +200 -7
- package/src/commands/me.js +1 -1
- package/src/commands/project.js +86 -3
- package/src/commands/workspace.js +2 -2
- package/src/core/config.js +3 -0
package/README.md
CHANGED
|
@@ -1,28 +1,15 @@
|
|
|
1
1
|
# plane-cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`plane-cli` 是一个基于 Plane 外部 API(`/api/v1`)的命令行工具,用于在终端中管理 workspace、project 和 work item(issue)。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## 特性
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
## 当前状态
|
|
14
|
-
|
|
15
|
-
这套 CLI 已经在真实 Plane 实例上做过 smoke 验证,当前重点覆盖:
|
|
16
|
-
|
|
17
|
-
- 认证与 workspace 选择
|
|
18
|
-
- `project` 的查询、创建、更新、成员管理、features 开关
|
|
19
|
-
- `issue/work-item` 的查询、创建、更新
|
|
20
|
-
- `issue` 的 labels、comments、activities、links、relations、attachments
|
|
21
|
-
|
|
22
|
-
适合:
|
|
23
|
-
|
|
24
|
-
- 人类直接在终端里操作
|
|
25
|
-
- Agent / 脚本通过 `--json` 消费结果
|
|
7
|
+
- 支持 API Key 配置与账号密码登录
|
|
8
|
+
- 支持多 workspace 选择与切换
|
|
9
|
+
- 支持人类可读输出与结构化 JSON 输出
|
|
10
|
+
- 支持 `project` 查询、创建、更新、成员管理、features 开关
|
|
11
|
+
- 支持 `issue` 查询、创建、更新、labels、comments、activities、links、relations、attachments
|
|
12
|
+
- 支持 `GAEA-25` 这类 issue key 自动解析
|
|
26
13
|
|
|
27
14
|
## 安装
|
|
28
15
|
|
|
@@ -30,104 +17,97 @@ plane issue get --project <project-id> <issue-id> --json
|
|
|
30
17
|
npm install -g @ysicing/plane-cli
|
|
31
18
|
```
|
|
32
19
|
|
|
33
|
-
|
|
20
|
+
安装完成后可执行命令为:
|
|
34
21
|
|
|
35
22
|
```bash
|
|
36
|
-
|
|
23
|
+
plane
|
|
37
24
|
```
|
|
38
25
|
|
|
39
|
-
##
|
|
26
|
+
## 环境要求
|
|
40
27
|
|
|
41
|
-
-
|
|
42
|
-
- 默认面向 `project` 与 `work-item`
|
|
43
|
-
- 暂不提供危险删除命令
|
|
28
|
+
- Node.js 22 或更高版本
|
|
44
29
|
|
|
45
|
-
##
|
|
30
|
+
## 输出格式
|
|
46
31
|
|
|
47
|
-
|
|
32
|
+
默认输出为人类可读格式。
|
|
48
33
|
|
|
49
|
-
|
|
34
|
+
如需供脚本、Agent 或流水线消费,可使用:
|
|
50
35
|
|
|
51
36
|
```bash
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
--api-key your-api-key \
|
|
55
|
-
--workspace your-workspace-slug
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
也支持环境变量覆盖:
|
|
59
|
-
|
|
60
|
-
```bash
|
|
61
|
-
export PLANE_BASE_URL=https://plane.example.com
|
|
62
|
-
export PLANE_API_KEY=your-api-key
|
|
63
|
-
export PLANE_WORKSPACE=your-workspace-slug
|
|
37
|
+
plane project ls --json
|
|
38
|
+
plane issue get GAEA-25 --format json
|
|
64
39
|
```
|
|
65
40
|
|
|
66
|
-
##
|
|
41
|
+
## 认证
|
|
67
42
|
|
|
68
|
-
|
|
43
|
+
### 方式一:直接配置 API Key
|
|
69
44
|
|
|
70
45
|
```bash
|
|
71
46
|
plane config set \
|
|
72
47
|
--base-url https://plane.example.com \
|
|
73
48
|
--api-key your-api-key \
|
|
74
49
|
--workspace your-workspace-slug
|
|
75
|
-
|
|
76
|
-
plane me
|
|
77
|
-
plane project ls
|
|
78
50
|
```
|
|
79
51
|
|
|
80
|
-
|
|
52
|
+
也可通过环境变量提供:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
export PLANE_BASE_URL=https://plane.example.com
|
|
56
|
+
export PLANE_API_KEY=your-api-key
|
|
57
|
+
export PLANE_WORKSPACE=your-workspace-slug
|
|
58
|
+
```
|
|
81
59
|
|
|
82
|
-
|
|
60
|
+
### 方式二:账号密码登录
|
|
83
61
|
|
|
84
62
|
```bash
|
|
85
|
-
|
|
63
|
+
plane auth login \
|
|
86
64
|
--base-url https://plane.example.com \
|
|
87
65
|
--username you@example.com \
|
|
88
66
|
--password 'your-password'
|
|
89
67
|
```
|
|
90
68
|
|
|
91
|
-
LDAP
|
|
69
|
+
### 方式三:LDAP 登录
|
|
92
70
|
|
|
93
71
|
```bash
|
|
94
|
-
|
|
72
|
+
plane auth login \
|
|
95
73
|
--base-url https://plane.example.com \
|
|
96
74
|
--ldap \
|
|
97
|
-
--username your-ldap-
|
|
75
|
+
--username your-ldap-user \
|
|
98
76
|
--password 'your-password'
|
|
99
77
|
```
|
|
100
78
|
|
|
101
|
-
|
|
79
|
+
如需避免在命令行中直接暴露密码:
|
|
102
80
|
|
|
103
81
|
```bash
|
|
104
|
-
printf '%s' 'your-password' |
|
|
82
|
+
printf '%s' 'your-password' | plane auth login \
|
|
105
83
|
--base-url https://plane.example.com \
|
|
106
84
|
--ldap \
|
|
107
|
-
--username your-ldap-
|
|
85
|
+
--username your-ldap-user \
|
|
108
86
|
--password-stdin
|
|
109
87
|
```
|
|
110
88
|
|
|
111
|
-
|
|
89
|
+
## Workspace 管理
|
|
90
|
+
|
|
91
|
+
如账号下存在多个 workspace,建议先查看并选择默认 workspace:
|
|
112
92
|
|
|
113
93
|
```bash
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
94
|
+
plane workspace current
|
|
95
|
+
plane workspace ls
|
|
96
|
+
plane workspace use <slug>
|
|
117
97
|
```
|
|
118
98
|
|
|
119
|
-
##
|
|
99
|
+
## 命令概览
|
|
120
100
|
|
|
121
|
-
###
|
|
101
|
+
### 基础命令
|
|
122
102
|
|
|
123
103
|
```bash
|
|
104
|
+
plane --help
|
|
124
105
|
plane me
|
|
106
|
+
plane config list
|
|
125
107
|
plane workspace current
|
|
126
|
-
plane workspace ls
|
|
127
|
-
plane workspace use <slug>
|
|
128
108
|
```
|
|
129
109
|
|
|
130
|
-
### Project
|
|
110
|
+
### Project 命令
|
|
131
111
|
|
|
132
112
|
```bash
|
|
133
113
|
plane project ls
|
|
@@ -143,111 +123,122 @@ plane project members ls --project <project-id>
|
|
|
143
123
|
plane project members add --project <project-id> --member <user-id> --role member
|
|
144
124
|
|
|
145
125
|
plane project features get <project-id>
|
|
146
|
-
plane project features enable-all <project-id>
|
|
147
126
|
plane project features set <project-id> --epics on --milestones on --auto-transition on
|
|
127
|
+
plane project features enable-all <project-id>
|
|
148
128
|
```
|
|
149
129
|
|
|
150
|
-
### Issue / Work Item
|
|
130
|
+
### Issue / Work Item 命令
|
|
131
|
+
|
|
132
|
+
`work-item` 是 `issue` 的别名。
|
|
151
133
|
|
|
152
134
|
```bash
|
|
153
135
|
plane issue ls --project <project-id>
|
|
154
136
|
plane issue get --project <project-id> <issue-id>
|
|
155
|
-
plane issue
|
|
156
|
-
plane issue
|
|
137
|
+
plane issue get GAEA-25
|
|
138
|
+
plane issue key GAEA-25
|
|
157
139
|
plane issue search --query login --workspace-search
|
|
158
140
|
|
|
159
141
|
plane issue create --project <project-id> --name "First work item"
|
|
160
142
|
plane issue update --project <project-id> <issue-id> --priority high
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Issue Labels
|
|
161
146
|
|
|
147
|
+
```bash
|
|
162
148
|
plane issue labels ls --project <project-id>
|
|
163
149
|
plane issue labels create --project <project-id> --name backend --color '#ff6600'
|
|
150
|
+
```
|
|
164
151
|
|
|
165
|
-
|
|
166
|
-
plane issue comments ls DEMO-123
|
|
167
|
-
plane issue comments add --project <project-id> <issue-id> --html '<p>Need follow-up</p>'
|
|
168
|
-
plane issue comments add DEMO-123 --html '<p>Need follow-up</p>'
|
|
169
|
-
plane issue comments update --project <project-id> <issue-id> <comment-id> --html '<p>Updated</p>'
|
|
170
|
-
|
|
171
|
-
plane issue activities ls --project <project-id> <issue-id>
|
|
172
|
-
plane issue activities ls DEMO-123
|
|
152
|
+
### Issue Comments
|
|
173
153
|
|
|
174
|
-
|
|
175
|
-
plane issue
|
|
176
|
-
plane issue
|
|
177
|
-
plane issue
|
|
154
|
+
```bash
|
|
155
|
+
plane issue comments ls GAEA-25
|
|
156
|
+
plane issue comments add GAEA-25 --html '<p>Need follow-up</p>'
|
|
157
|
+
plane issue comments update GAEA-25 <comment-id> --html '<p>Updated</p>'
|
|
158
|
+
```
|
|
178
159
|
|
|
179
|
-
|
|
180
|
-
plane issue relations ls DEMO-123
|
|
181
|
-
plane issue relations add --project <project-id> <issue-id> --relation-type blocking --issues '<other-issue-id>'
|
|
160
|
+
### Issue Activities
|
|
182
161
|
|
|
183
|
-
|
|
184
|
-
plane issue
|
|
185
|
-
plane issue attachments upload --project <project-id> <issue-id> --file ./spec.pdf
|
|
162
|
+
```bash
|
|
163
|
+
plane issue activities ls GAEA-25
|
|
186
164
|
```
|
|
187
165
|
|
|
188
|
-
|
|
166
|
+
### Issue Links
|
|
189
167
|
|
|
190
168
|
```bash
|
|
191
|
-
|
|
169
|
+
plane issue links ls GAEA-25
|
|
170
|
+
plane issue links add GAEA-25 --url 'https://example.com/doc'
|
|
171
|
+
plane issue links update GAEA-25 <link-id> --url 'https://example.com/doc-v2'
|
|
192
172
|
```
|
|
193
173
|
|
|
194
|
-
|
|
174
|
+
### Issue Relations
|
|
195
175
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
-
|
|
176
|
+
```bash
|
|
177
|
+
plane issue relations ls GAEA-25
|
|
178
|
+
plane issue relations add GAEA-25 --relation-type blocking --issues '<other-issue-id>'
|
|
179
|
+
```
|
|
199
180
|
|
|
200
|
-
|
|
181
|
+
### Issue Attachments
|
|
201
182
|
|
|
202
183
|
```bash
|
|
203
|
-
plane issue
|
|
204
|
-
plane
|
|
184
|
+
plane issue attachments ls GAEA-25
|
|
185
|
+
plane issue attachments upload GAEA-25 --file ./spec.pdf
|
|
205
186
|
```
|
|
206
187
|
|
|
207
|
-
##
|
|
208
|
-
|
|
209
|
-
- 多 workspace 登录后,如果没有显式传 `--workspace`,CLI 不会自动替你选择默认 workspace。先执行 `plane workspace ls`,再执行 `plane workspace use <slug>`。
|
|
210
|
-
- `issue create/update --assignees` 支持传用户 ID、邮箱、或精确全名。CLI 会先读取 workspace 成员再解析成后端需要的 member ID。
|
|
211
|
-
- `project create` 带 `--project-lead` 和 `--default-assignee` 时,CLI 会自动采用“两段式创建”:先建项目,再补一次 update。这是为了兼容部分 Plane 实例的后端校验差异。
|
|
212
|
-
- `project features set`、`issue attachments upload` 这类命令在真实实例上可能会遇到几秒钟的读副本延迟。写入成功后如果立刻回读不到,稍后再查一次通常即可。
|
|
213
|
-
- 当前不提供危险删除命令,也不主动清理服务端 token。
|
|
188
|
+
## 交互与参数约定
|
|
214
189
|
|
|
215
|
-
|
|
190
|
+
### Issue Key 自动解析
|
|
216
191
|
|
|
217
|
-
|
|
192
|
+
对于以下命令,若目标是已存在的 issue,可直接使用 `GAEA-25` 这类 key,而无需显式提供 `--project` 与 issue UUID:
|
|
218
193
|
|
|
219
|
-
- `
|
|
220
|
-
- `workspace current/ls/use`
|
|
221
|
-
- `project ls/get/summary/create/update`
|
|
222
|
-
- `project members workspace/ls/add`
|
|
223
|
-
- `project features get/set/enable-all`
|
|
224
|
-
- `issue ls/get/key/search/create/update`
|
|
225
|
-
- `issue labels ls/create`
|
|
194
|
+
- `issue get`
|
|
226
195
|
- `issue comments ls/add/update`
|
|
227
196
|
- `issue activities ls`
|
|
228
197
|
- `issue links ls/add/update`
|
|
229
198
|
- `issue relations ls/add`
|
|
230
199
|
- `issue attachments ls/upload`
|
|
231
200
|
|
|
232
|
-
|
|
201
|
+
### 指定 Assignee
|
|
202
|
+
|
|
203
|
+
`issue create` 与 `issue update` 的 `--assignees` 支持以下输入形式:
|
|
204
|
+
|
|
205
|
+
- 用户 ID
|
|
206
|
+
- 邮箱
|
|
207
|
+
- 精确全名
|
|
208
|
+
|
|
209
|
+
CLI 会自动根据 workspace 成员列表解析为后端所需的 member ID。
|
|
233
210
|
|
|
234
|
-
|
|
211
|
+
## Help 体系
|
|
235
212
|
|
|
236
|
-
|
|
213
|
+
支持以下层级的帮助信息:
|
|
237
214
|
|
|
238
215
|
```bash
|
|
239
|
-
|
|
240
|
-
|
|
216
|
+
plane -h
|
|
217
|
+
plane project -h
|
|
218
|
+
plane project features set --help
|
|
219
|
+
plane issue comments add --help
|
|
220
|
+
plane issue attachments upload --help
|
|
241
221
|
```
|
|
242
222
|
|
|
243
|
-
|
|
223
|
+
## 限制说明
|
|
224
|
+
|
|
225
|
+
- 当前不提供危险删除命令
|
|
226
|
+
- 当前不自动回收服务端 API Token
|
|
227
|
+
- `project members ls` 受限于 Plane `api/v1` 返回结构,仅返回用户资料,不包含完整的 `ProjectMember` 记录字段
|
|
228
|
+
- `project create` 在部分 Plane 实例上对 `project_lead/default_assignee` 的校验较严格,CLI 已采用“两段式创建”兼容该行为
|
|
229
|
+
- `project features set`、`issue attachments upload` 在启用读副本的实例上,可能存在短暂回读延迟
|
|
230
|
+
|
|
231
|
+
## 发布
|
|
232
|
+
|
|
233
|
+
当前包名为 `@ysicing/plane-cli`。发布前建议执行:
|
|
244
234
|
|
|
245
235
|
```bash
|
|
246
|
-
npm
|
|
236
|
+
npm test
|
|
237
|
+
npm run pack:check
|
|
247
238
|
```
|
|
248
239
|
|
|
249
|
-
|
|
240
|
+
发布:
|
|
250
241
|
|
|
251
242
|
```bash
|
|
252
|
-
npm
|
|
243
|
+
npm publish
|
|
253
244
|
```
|
package/package.json
CHANGED
package/src/commands/auth.js
CHANGED
|
@@ -49,7 +49,7 @@ function resolveWorkspaceToSave({ explicitWorkspace, existingWorkspace, userWork
|
|
|
49
49
|
export async function runAuthCommand(args, context) {
|
|
50
50
|
const [subcommand, ...rest] = args;
|
|
51
51
|
|
|
52
|
-
if (!subcommand || subcommand === "--help" || subcommand === "help") {
|
|
52
|
+
if (!subcommand || subcommand === "--help" || subcommand === "-h" || subcommand === "help") {
|
|
53
53
|
printHelp();
|
|
54
54
|
return;
|
|
55
55
|
}
|
|
@@ -58,7 +58,7 @@ export async function runAuthCommand(args, context) {
|
|
|
58
58
|
throw new CliError(`Unknown auth subcommand: ${subcommand}`);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
if (rest.includes("--help") || rest.includes("help")) {
|
|
61
|
+
if (rest.includes("--help") || rest.includes("-h") || rest.includes("help")) {
|
|
62
62
|
printHelp();
|
|
63
63
|
return;
|
|
64
64
|
}
|
package/src/commands/config.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { loadConfig, maskApiKey, resolveConfigPath, saveConfig } from "../core/config.js";
|
|
2
2
|
import { CliError } from "../core/errors.js";
|
|
3
|
-
import { parseCommandArgs } from "../core/options.js";
|
|
3
|
+
import { parseCommandArgs, pickDefined } from "../core/options.js";
|
|
4
4
|
import { printData } from "../core/output.js";
|
|
5
5
|
|
|
6
6
|
function configSnapshot(config, path) {
|
|
@@ -21,11 +21,24 @@ function printHelp() {
|
|
|
21
21
|
`);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
function printGetHelp() {
|
|
25
|
+
console.log(`Usage:
|
|
26
|
+
plane config get
|
|
27
|
+
plane config get <baseUrl|apiKey|workspace|knownWorkspaces>
|
|
28
|
+
`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function printSetHelp() {
|
|
32
|
+
console.log(`Usage:
|
|
33
|
+
plane config set [--base-url <url>] [--api-key <key>] [--workspace <slug>]
|
|
34
|
+
`);
|
|
35
|
+
}
|
|
36
|
+
|
|
24
37
|
export async function runConfigCommand(args, context) {
|
|
25
38
|
const [subcommand = "list", ...rest] = args;
|
|
26
39
|
const path = resolveConfigPath();
|
|
27
40
|
|
|
28
|
-
if (subcommand === "--help" || subcommand === "help") {
|
|
41
|
+
if (subcommand === "--help" || subcommand === "-h" || subcommand === "help") {
|
|
29
42
|
printHelp();
|
|
30
43
|
return;
|
|
31
44
|
}
|
|
@@ -37,6 +50,11 @@ export async function runConfigCommand(args, context) {
|
|
|
37
50
|
}
|
|
38
51
|
|
|
39
52
|
if (subcommand === "get") {
|
|
53
|
+
if (rest.includes("--help") || rest.includes("-h") || rest.includes("help")) {
|
|
54
|
+
printGetHelp();
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
40
58
|
const [key] = rest;
|
|
41
59
|
const config = await loadConfig();
|
|
42
60
|
const snapshot = configSnapshot(config, path);
|
|
@@ -55,6 +73,11 @@ export async function runConfigCommand(args, context) {
|
|
|
55
73
|
}
|
|
56
74
|
|
|
57
75
|
if (subcommand === "set") {
|
|
76
|
+
if (rest.includes("--help") || rest.includes("-h") || rest.includes("help")) {
|
|
77
|
+
printSetHelp();
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
58
81
|
const parsed = parseCommandArgs(
|
|
59
82
|
rest,
|
|
60
83
|
{
|
|
@@ -65,11 +88,11 @@ export async function runConfigCommand(args, context) {
|
|
|
65
88
|
false
|
|
66
89
|
);
|
|
67
90
|
|
|
68
|
-
const update = {
|
|
91
|
+
const update = pickDefined({
|
|
69
92
|
baseUrl: parsed.values["base-url"],
|
|
70
93
|
apiKey: parsed.values["api-key"],
|
|
71
94
|
workspace: parsed.values.workspace,
|
|
72
|
-
};
|
|
95
|
+
});
|
|
73
96
|
|
|
74
97
|
if (!update.baseUrl && !update.apiKey && !update.workspace) {
|
|
75
98
|
throw new CliError("Nothing to update. Pass at least one of --base-url, --api-key, or --workspace.");
|
package/src/commands/issue.js
CHANGED
|
@@ -8,6 +8,10 @@ import { printData, printTable } from "../core/output.js";
|
|
|
8
8
|
import { basename, extname } from "node:path";
|
|
9
9
|
import { readFile, stat } from "node:fs/promises";
|
|
10
10
|
|
|
11
|
+
function hasHelpFlag(args) {
|
|
12
|
+
return args.includes("--help") || args.includes("-h") || args.includes("help");
|
|
13
|
+
}
|
|
14
|
+
|
|
11
15
|
function renderIssueList(data) {
|
|
12
16
|
const rows = Array.isArray(data) ? data : data.results || [];
|
|
13
17
|
printTable(rows, [
|
|
@@ -291,14 +295,125 @@ function printHelp() {
|
|
|
291
295
|
`);
|
|
292
296
|
}
|
|
293
297
|
|
|
298
|
+
function printIssueCommentsHelp() {
|
|
299
|
+
console.log(`Usage:
|
|
300
|
+
plane issue comments ls --project <project-id> <issue-id>
|
|
301
|
+
plane issue comments ls GAEA-25
|
|
302
|
+
plane issue comments add --project <project-id> <issue-id> --html '<p>comment</p>' [--access <value>]
|
|
303
|
+
plane issue comments add GAEA-25 --html '<p>comment</p>' [--access <value>]
|
|
304
|
+
plane issue comments update --project <project-id> <issue-id> <comment-id> --html '<p>comment</p>' [--access <value>]
|
|
305
|
+
plane issue comments update GAEA-25 <comment-id> --html '<p>comment</p>' [--access <value>]
|
|
306
|
+
`);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function printIssueLinksHelp() {
|
|
310
|
+
console.log(`Usage:
|
|
311
|
+
plane issue links ls --project <project-id> <issue-id>
|
|
312
|
+
plane issue links ls GAEA-25
|
|
313
|
+
plane issue links add --project <project-id> <issue-id> --url <url> [--title <text>]
|
|
314
|
+
plane issue links add GAEA-25 --url <url> [--title <text>]
|
|
315
|
+
plane issue links update --project <project-id> <issue-id> <link-id> --url <url> [--title <text>]
|
|
316
|
+
plane issue links update GAEA-25 <link-id> --url <url> [--title <text>]
|
|
317
|
+
`);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function printIssueRelationsHelp() {
|
|
321
|
+
console.log(`Usage:
|
|
322
|
+
plane issue relations ls --project <project-id> <issue-id>
|
|
323
|
+
plane issue relations ls GAEA-25
|
|
324
|
+
plane issue relations add --project <project-id> <issue-id> --relation-type <blocking|blocked_by|duplicate|relates_to|start_before|start_after|finish_before|finish_after> --issues <id1,id2>
|
|
325
|
+
plane issue relations add GAEA-25 --relation-type <blocking|blocked_by|duplicate|relates_to|start_before|start_after|finish_before|finish_after> --issues <id1,id2>
|
|
326
|
+
`);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function printIssueAttachmentsHelp() {
|
|
330
|
+
console.log(`Usage:
|
|
331
|
+
plane issue attachments ls --project <project-id> <issue-id>
|
|
332
|
+
plane issue attachments ls GAEA-25
|
|
333
|
+
plane issue attachments upload --project <project-id> <issue-id> --file <path> [--name <filename>] [--type <mime>]
|
|
334
|
+
plane issue attachments upload GAEA-25 --file <path> [--name <filename>] [--type <mime>]
|
|
335
|
+
`);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function printIssueActivitiesHelp() {
|
|
339
|
+
console.log(`Usage:
|
|
340
|
+
plane issue activities ls --project <project-id> <issue-id>
|
|
341
|
+
plane issue activities ls GAEA-25
|
|
342
|
+
`);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function printIssueLabelsHelp() {
|
|
346
|
+
console.log(`Usage:
|
|
347
|
+
plane issue labels ls --project <project-id>
|
|
348
|
+
plane issue labels create --project <project-id> --name <name> [--color <hex>] [--description <text>] [--parent <label-id>] [--sort-order <n>]
|
|
349
|
+
`);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
function printIssueLabelsCreateHelp() {
|
|
353
|
+
console.log(`Usage:
|
|
354
|
+
plane issue labels create --project <project-id> --name <name> [--color <hex>] [--description <text>] [--parent <label-id>] [--sort-order <n>]
|
|
355
|
+
`);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function printIssueCommentsAddHelp() {
|
|
359
|
+
console.log(`Usage:
|
|
360
|
+
plane issue comments add --project <project-id> <issue-id> --html '<p>comment</p>' [--access <value>]
|
|
361
|
+
plane issue comments add GAEA-25 --html '<p>comment</p>' [--access <value>]
|
|
362
|
+
`);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function printIssueCommentsUpdateHelp() {
|
|
366
|
+
console.log(`Usage:
|
|
367
|
+
plane issue comments update --project <project-id> <issue-id> <comment-id> --html '<p>comment</p>' [--access <value>]
|
|
368
|
+
plane issue comments update GAEA-25 <comment-id> --html '<p>comment</p>' [--access <value>]
|
|
369
|
+
`);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function printIssueLinksAddHelp() {
|
|
373
|
+
console.log(`Usage:
|
|
374
|
+
plane issue links add --project <project-id> <issue-id> --url <url> [--title <text>]
|
|
375
|
+
plane issue links add GAEA-25 --url <url> [--title <text>]
|
|
376
|
+
`);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
function printIssueLinksUpdateHelp() {
|
|
380
|
+
console.log(`Usage:
|
|
381
|
+
plane issue links update --project <project-id> <issue-id> <link-id> --url <url> [--title <text>]
|
|
382
|
+
plane issue links update GAEA-25 <link-id> --url <url> [--title <text>]
|
|
383
|
+
`);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function printIssueRelationsAddHelp() {
|
|
387
|
+
console.log(`Usage:
|
|
388
|
+
plane issue relations add --project <project-id> <issue-id> --relation-type <blocking|blocked_by|duplicate|relates_to|start_before|start_after|finish_before|finish_after> --issues <id1,id2>
|
|
389
|
+
plane issue relations add GAEA-25 --relation-type <blocking|blocked_by|duplicate|relates_to|start_before|start_after|finish_before|finish_after> --issues <id1,id2>
|
|
390
|
+
`);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function printIssueAttachmentsUploadHelp() {
|
|
394
|
+
console.log(`Usage:
|
|
395
|
+
plane issue attachments upload --project <project-id> <issue-id> --file <path> [--name <filename>] [--type <mime>]
|
|
396
|
+
plane issue attachments upload GAEA-25 --file <path> [--name <filename>] [--type <mime>]
|
|
397
|
+
`);
|
|
398
|
+
}
|
|
399
|
+
|
|
294
400
|
async function runIssueLabelsCommand(issueClient, args, context) {
|
|
295
401
|
const [subcommand, ...rest] = args;
|
|
296
402
|
|
|
297
|
-
if (!subcommand || subcommand === "--help" || subcommand === "help") {
|
|
403
|
+
if (!subcommand || subcommand === "--help" || subcommand === "-h" || subcommand === "help") {
|
|
298
404
|
printHelp();
|
|
299
405
|
return;
|
|
300
406
|
}
|
|
301
407
|
|
|
408
|
+
if (hasHelpFlag(rest)) {
|
|
409
|
+
if (subcommand === "create") {
|
|
410
|
+
printIssueLabelsCreateHelp();
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
printIssueLabelsHelp();
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
|
|
302
417
|
if (subcommand === "ls") {
|
|
303
418
|
const parsed = parseCommandArgs(
|
|
304
419
|
rest,
|
|
@@ -353,11 +468,24 @@ async function runIssueLabelsCommand(issueClient, args, context) {
|
|
|
353
468
|
async function runIssueCommentsCommand(issueClient, args, context) {
|
|
354
469
|
const [subcommand, ...rest] = args;
|
|
355
470
|
|
|
356
|
-
if (!subcommand || subcommand === "--help" || subcommand === "help") {
|
|
471
|
+
if (!subcommand || subcommand === "--help" || subcommand === "-h" || subcommand === "help") {
|
|
357
472
|
printHelp();
|
|
358
473
|
return;
|
|
359
474
|
}
|
|
360
475
|
|
|
476
|
+
if (hasHelpFlag(rest)) {
|
|
477
|
+
if (subcommand === "add") {
|
|
478
|
+
printIssueCommentsAddHelp();
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
if (subcommand === "update") {
|
|
482
|
+
printIssueCommentsUpdateHelp();
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
printIssueCommentsHelp();
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
|
|
361
489
|
if (subcommand === "ls") {
|
|
362
490
|
const parsed = parseCommandArgs(
|
|
363
491
|
rest,
|
|
@@ -439,11 +567,16 @@ async function runIssueCommentsCommand(issueClient, args, context) {
|
|
|
439
567
|
async function runIssueActivitiesCommand(issueClient, args, context) {
|
|
440
568
|
const [subcommand, ...rest] = args;
|
|
441
569
|
|
|
442
|
-
if (!subcommand || subcommand === "--help" || subcommand === "help") {
|
|
570
|
+
if (!subcommand || subcommand === "--help" || subcommand === "-h" || subcommand === "help") {
|
|
443
571
|
printHelp();
|
|
444
572
|
return;
|
|
445
573
|
}
|
|
446
574
|
|
|
575
|
+
if (hasHelpFlag(rest)) {
|
|
576
|
+
printIssueActivitiesHelp();
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
|
|
447
580
|
if (subcommand !== "ls") {
|
|
448
581
|
throw new CliError(`Unknown issue activities subcommand: ${subcommand}`);
|
|
449
582
|
}
|
|
@@ -478,11 +611,24 @@ async function runIssueActivitiesCommand(issueClient, args, context) {
|
|
|
478
611
|
async function runIssueLinksCommand(issueClient, args, context) {
|
|
479
612
|
const [subcommand, ...rest] = args;
|
|
480
613
|
|
|
481
|
-
if (!subcommand || subcommand === "--help" || subcommand === "help") {
|
|
614
|
+
if (!subcommand || subcommand === "--help" || subcommand === "-h" || subcommand === "help") {
|
|
482
615
|
printHelp();
|
|
483
616
|
return;
|
|
484
617
|
}
|
|
485
618
|
|
|
619
|
+
if (hasHelpFlag(rest)) {
|
|
620
|
+
if (subcommand === "add") {
|
|
621
|
+
printIssueLinksAddHelp();
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
if (subcommand === "update") {
|
|
625
|
+
printIssueLinksUpdateHelp();
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
printIssueLinksHelp();
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
|
|
486
632
|
if (subcommand === "ls") {
|
|
487
633
|
const parsed = parseCommandArgs(
|
|
488
634
|
rest,
|
|
@@ -553,11 +699,20 @@ async function runIssueLinksCommand(issueClient, args, context) {
|
|
|
553
699
|
async function runIssueRelationsCommand(issueClient, args, context) {
|
|
554
700
|
const [subcommand, ...rest] = args;
|
|
555
701
|
|
|
556
|
-
if (!subcommand || subcommand === "--help" || subcommand === "help") {
|
|
702
|
+
if (!subcommand || subcommand === "--help" || subcommand === "-h" || subcommand === "help") {
|
|
557
703
|
printHelp();
|
|
558
704
|
return;
|
|
559
705
|
}
|
|
560
706
|
|
|
707
|
+
if (hasHelpFlag(rest)) {
|
|
708
|
+
if (subcommand === "add") {
|
|
709
|
+
printIssueRelationsAddHelp();
|
|
710
|
+
return;
|
|
711
|
+
}
|
|
712
|
+
printIssueRelationsHelp();
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
|
|
561
716
|
if (subcommand === "ls") {
|
|
562
717
|
const parsed = parseCommandArgs(
|
|
563
718
|
rest,
|
|
@@ -625,11 +780,20 @@ async function uploadAttachmentBinary(uploadData, filePath, fileName, mimeType)
|
|
|
625
780
|
async function runIssueAttachmentsCommand(issueClient, args, context) {
|
|
626
781
|
const [subcommand, ...rest] = args;
|
|
627
782
|
|
|
628
|
-
if (!subcommand || subcommand === "--help" || subcommand === "help") {
|
|
783
|
+
if (!subcommand || subcommand === "--help" || subcommand === "-h" || subcommand === "help") {
|
|
629
784
|
printHelp();
|
|
630
785
|
return;
|
|
631
786
|
}
|
|
632
787
|
|
|
788
|
+
if (hasHelpFlag(rest)) {
|
|
789
|
+
if (subcommand === "upload") {
|
|
790
|
+
printIssueAttachmentsUploadHelp();
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
printIssueAttachmentsHelp();
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
|
|
633
797
|
if (subcommand === "ls") {
|
|
634
798
|
const parsed = parseCommandArgs(
|
|
635
799
|
rest,
|
|
@@ -699,7 +863,36 @@ async function runIssueAttachmentsCommand(issueClient, args, context) {
|
|
|
699
863
|
export async function runIssueCommand(args, context) {
|
|
700
864
|
const [subcommand, ...rest] = args;
|
|
701
865
|
|
|
702
|
-
if (!subcommand || subcommand === "--help" || subcommand === "help") {
|
|
866
|
+
if (!subcommand || subcommand === "--help" || subcommand === "-h" || subcommand === "help") {
|
|
867
|
+
printHelp();
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
if (hasHelpFlag(rest)) {
|
|
872
|
+
if (subcommand === "labels") {
|
|
873
|
+
printIssueLabelsHelp();
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
if (subcommand === "comments") {
|
|
877
|
+
printIssueCommentsHelp();
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
880
|
+
if (subcommand === "activities") {
|
|
881
|
+
printIssueActivitiesHelp();
|
|
882
|
+
return;
|
|
883
|
+
}
|
|
884
|
+
if (subcommand === "links") {
|
|
885
|
+
printIssueLinksHelp();
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
888
|
+
if (subcommand === "relations") {
|
|
889
|
+
printIssueRelationsHelp();
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
892
|
+
if (subcommand === "attachments") {
|
|
893
|
+
printIssueAttachmentsHelp();
|
|
894
|
+
return;
|
|
895
|
+
}
|
|
703
896
|
printHelp();
|
|
704
897
|
return;
|
|
705
898
|
}
|
package/src/commands/me.js
CHANGED
|
@@ -5,7 +5,7 @@ import { PlaneClient } from "../core/http.js";
|
|
|
5
5
|
import { printData } from "../core/output.js";
|
|
6
6
|
|
|
7
7
|
export async function runMeCommand(args, context) {
|
|
8
|
-
if (args.includes("--help") || args.includes("help")) {
|
|
8
|
+
if (args.includes("--help") || args.includes("-h") || args.includes("help")) {
|
|
9
9
|
console.log("Usage:\n plane me");
|
|
10
10
|
return;
|
|
11
11
|
}
|
package/src/commands/project.js
CHANGED
|
@@ -5,6 +5,10 @@ import { PlaneClient } from "../core/http.js";
|
|
|
5
5
|
import { ensureValue, parseCommandArgs, pickDefined } from "../core/options.js";
|
|
6
6
|
import { printData, printTable } from "../core/output.js";
|
|
7
7
|
|
|
8
|
+
function hasHelpFlag(args) {
|
|
9
|
+
return args.includes("--help") || args.includes("-h") || args.includes("help");
|
|
10
|
+
}
|
|
11
|
+
|
|
8
12
|
function createProjectRender(data) {
|
|
9
13
|
const rows = Array.isArray(data) ? data : data.results || [];
|
|
10
14
|
printTable(rows, [
|
|
@@ -125,14 +129,63 @@ function printHelp() {
|
|
|
125
129
|
`);
|
|
126
130
|
}
|
|
127
131
|
|
|
132
|
+
function printProjectMembersHelp() {
|
|
133
|
+
console.log(`Usage:
|
|
134
|
+
plane project members ls --project <project-id>
|
|
135
|
+
plane project members workspace
|
|
136
|
+
plane project members add --project <project-id> --member <user-id> --role <admin|member|guest>
|
|
137
|
+
`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function printProjectMembersAddHelp() {
|
|
141
|
+
console.log(`Usage:
|
|
142
|
+
plane project members add --project <project-id> --member <user-id> --role <admin|member|guest>
|
|
143
|
+
`);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function printProjectFeaturesHelp() {
|
|
147
|
+
console.log(`Usage:
|
|
148
|
+
plane project features get <project-id>
|
|
149
|
+
plane project features set <project-id> [--issue-types on|off] [--epics on|off] [--milestones on|off] [--time-tracking on|off] [--auto-transition on|off] [--auto-assign on|off] [--auto-worklog on|off] [--require-worklog-before-completion on|off]
|
|
150
|
+
plane project features enable-all <project-id>
|
|
151
|
+
`);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function printProjectFeaturesSetHelp() {
|
|
155
|
+
console.log(`Usage:
|
|
156
|
+
plane project features set <project-id> [--issue-types on|off] [--epics on|off] [--milestones on|off] [--time-tracking on|off] [--auto-transition on|off] [--auto-assign on|off] [--auto-worklog on|off] [--require-worklog-before-completion on|off]
|
|
157
|
+
`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function printProjectCreateHelp() {
|
|
161
|
+
console.log(`Usage:
|
|
162
|
+
plane project create --name <name> --identifier <identifier> [--description <text>] [--project-lead <user-id>] [--default-assignee <user-id>]
|
|
163
|
+
`);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function printProjectUpdateHelp() {
|
|
167
|
+
console.log(`Usage:
|
|
168
|
+
plane project update <project-id> [--name <name>] [--identifier <identifier>] [--description <text>] [--project-lead <user-id>] [--default-assignee <user-id>]
|
|
169
|
+
`);
|
|
170
|
+
}
|
|
171
|
+
|
|
128
172
|
async function runProjectMembersCommand(projectClient, args, context) {
|
|
129
173
|
const [subcommand, ...rest] = args;
|
|
130
174
|
|
|
131
|
-
if (!subcommand || subcommand === "--help" || subcommand === "help") {
|
|
175
|
+
if (!subcommand || subcommand === "--help" || subcommand === "-h" || subcommand === "help") {
|
|
132
176
|
printHelp();
|
|
133
177
|
return;
|
|
134
178
|
}
|
|
135
179
|
|
|
180
|
+
if (hasHelpFlag(rest)) {
|
|
181
|
+
if (subcommand === "add") {
|
|
182
|
+
printProjectMembersAddHelp();
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
printProjectMembersHelp();
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
136
189
|
if (subcommand === "ls") {
|
|
137
190
|
const parsed = parseCommandArgs(
|
|
138
191
|
rest,
|
|
@@ -189,11 +242,20 @@ async function runProjectMembersCommand(projectClient, args, context) {
|
|
|
189
242
|
async function runProjectFeaturesCommand(projectClient, args, context) {
|
|
190
243
|
const [subcommand, ...rest] = args;
|
|
191
244
|
|
|
192
|
-
if (!subcommand || subcommand === "--help" || subcommand === "help") {
|
|
245
|
+
if (!subcommand || subcommand === "--help" || subcommand === "-h" || subcommand === "help") {
|
|
193
246
|
printHelp();
|
|
194
247
|
return;
|
|
195
248
|
}
|
|
196
249
|
|
|
250
|
+
if (hasHelpFlag(rest)) {
|
|
251
|
+
if (subcommand === "set") {
|
|
252
|
+
printProjectFeaturesSetHelp();
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
printProjectFeaturesHelp();
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
|
|
197
259
|
if (subcommand === "get") {
|
|
198
260
|
const [projectId] = rest;
|
|
199
261
|
ensureValue(projectId, "Project ID is required.");
|
|
@@ -270,7 +332,28 @@ async function runProjectFeaturesCommand(projectClient, args, context) {
|
|
|
270
332
|
export async function runProjectCommand(args, context) {
|
|
271
333
|
const [subcommand, ...rest] = args;
|
|
272
334
|
|
|
273
|
-
if (!subcommand || subcommand === "--help" || subcommand === "help") {
|
|
335
|
+
if (!subcommand || subcommand === "--help" || subcommand === "-h" || subcommand === "help") {
|
|
336
|
+
printHelp();
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (hasHelpFlag(rest)) {
|
|
341
|
+
if (subcommand === "members") {
|
|
342
|
+
printProjectMembersHelp();
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
if (subcommand === "features") {
|
|
346
|
+
printProjectFeaturesHelp();
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
if (subcommand === "create") {
|
|
350
|
+
printProjectCreateHelp();
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
if (subcommand === "update") {
|
|
354
|
+
printProjectUpdateHelp();
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
274
357
|
printHelp();
|
|
275
358
|
return;
|
|
276
359
|
}
|
|
@@ -22,12 +22,12 @@ function workspaceRows(config) {
|
|
|
22
22
|
export async function runWorkspaceCommand(args, context) {
|
|
23
23
|
const [subcommand = "ls", ...rest] = args;
|
|
24
24
|
|
|
25
|
-
if (subcommand === "--help" || subcommand === "help") {
|
|
25
|
+
if (subcommand === "--help" || subcommand === "-h" || subcommand === "help") {
|
|
26
26
|
printHelp();
|
|
27
27
|
return;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
if (rest.includes("--help") || rest.includes("help")) {
|
|
30
|
+
if (rest.includes("--help") || rest.includes("-h") || rest.includes("help")) {
|
|
31
31
|
printHelp();
|
|
32
32
|
return;
|
|
33
33
|
}
|
package/src/core/config.js
CHANGED