@leeguoo/zentao-mcp 0.5.0 → 0.5.4
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 +67 -2
- package/package.json +9 -1
- package/skills/zentao-cli.md +75 -14
- package/src/cli/help.js +4 -4
- package/src/commands/bug.js +45 -3
- package/src/commands/bugs.js +75 -5
- package/src/commands/products.js +34 -3
package/README.md
CHANGED
|
@@ -4,10 +4,17 @@ ZenTao CLI for products + bugs.
|
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
|
-
Global install:
|
|
7
|
+
Global install (recommended):
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
|
|
10
|
+
pnpm i -g @leeguoo/zentao-mcp
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
If you don't have pnpm:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm i -g pnpm
|
|
17
|
+
pnpm i -g @leeguoo/zentao-mcp
|
|
11
18
|
```
|
|
12
19
|
|
|
13
20
|
Or use without installing:
|
|
@@ -38,6 +45,12 @@ Environment variables:
|
|
|
38
45
|
|
|
39
46
|
Tip: `ZENTAO_URL` should include the ZenTao base path (often `/zentao`).
|
|
40
47
|
|
|
48
|
+
Example:
|
|
49
|
+
|
|
50
|
+
- `https://zentao.example.com/zentao` (common)
|
|
51
|
+
|
|
52
|
+
If you see `404 Not Found` when logging in, your base path is likely missing `/zentao`.
|
|
53
|
+
|
|
41
54
|
## Commands
|
|
42
55
|
|
|
43
56
|
List products:
|
|
@@ -46,24 +59,48 @@ List products:
|
|
|
46
59
|
zentao products list
|
|
47
60
|
```
|
|
48
61
|
|
|
62
|
+
Full JSON output:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
zentao products list --json
|
|
66
|
+
```
|
|
67
|
+
|
|
49
68
|
List bugs for a product:
|
|
50
69
|
|
|
51
70
|
```bash
|
|
52
71
|
zentao bugs list --product 1
|
|
53
72
|
```
|
|
54
73
|
|
|
74
|
+
Full JSON output:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
zentao bugs list --product 1 --json
|
|
78
|
+
```
|
|
79
|
+
|
|
55
80
|
Get bug details:
|
|
56
81
|
|
|
57
82
|
```bash
|
|
58
83
|
zentao bug get --id 123
|
|
59
84
|
```
|
|
60
85
|
|
|
86
|
+
Full JSON output:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
zentao bug get --id 123 --json
|
|
90
|
+
```
|
|
91
|
+
|
|
61
92
|
List my bugs:
|
|
62
93
|
|
|
63
94
|
```bash
|
|
64
95
|
zentao bugs mine --scope assigned --status active
|
|
65
96
|
```
|
|
66
97
|
|
|
98
|
+
Full JSON output:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
zentao bugs mine --scope assigned --status active --json
|
|
102
|
+
```
|
|
103
|
+
|
|
67
104
|
Self test:
|
|
68
105
|
|
|
69
106
|
```bash
|
|
@@ -89,14 +126,42 @@ zentao whoami
|
|
|
89
126
|
zentao products list
|
|
90
127
|
```
|
|
91
128
|
|
|
129
|
+
Troubleshooting login:
|
|
130
|
+
|
|
131
|
+
- If `Token response parse failed: <html>...404 Not Found...`, try:
|
|
132
|
+
- `https://your-host/zentao` instead of `https://your-host/`
|
|
133
|
+
|
|
92
134
|
## Release (maintainers)
|
|
93
135
|
|
|
136
|
+
### GitHub Actions (recommended)
|
|
137
|
+
|
|
138
|
+
This repo supports npm Trusted Publisher (OIDC) via GitHub Actions.
|
|
139
|
+
|
|
140
|
+
1. Create a tag matching `package.json` version:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
git tag v0.5.1
|
|
144
|
+
git push origin v0.5.1
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
2. The workflow `.github/workflows/publish-npm.yml` will run tests and publish to npm.
|
|
148
|
+
|
|
149
|
+
In npm Trusted Publisher settings, set the workflow filename to `publish-npm.yml`.
|
|
150
|
+
|
|
151
|
+
### Local release (fallback)
|
|
152
|
+
|
|
94
153
|
Requires `git`, `npm`, and `gh`.
|
|
95
154
|
|
|
96
155
|
```bash
|
|
97
156
|
zentao release patch --dry-run
|
|
98
157
|
```
|
|
99
158
|
|
|
159
|
+
If you are using GitHub Actions publishing, prefer tagging + pushing, or run local release with:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
zentao release patch --skip-publish
|
|
163
|
+
```
|
|
164
|
+
|
|
100
165
|
## Local Development
|
|
101
166
|
|
|
102
167
|
```bash
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leeguoo/zentao-mcp",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.4",
|
|
4
4
|
"description": "ZenTao CLI for products + bugs",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"zentao",
|
|
@@ -27,6 +27,14 @@
|
|
|
27
27
|
"publishConfig": {
|
|
28
28
|
"access": "public"
|
|
29
29
|
},
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/leeguooooo/zentao-mcp"
|
|
33
|
+
},
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/leeguooooo/zentao-mcp/issues"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://github.com/leeguooooo/zentao-mcp#readme",
|
|
30
38
|
"scripts": {
|
|
31
39
|
"start": "node src/index.js",
|
|
32
40
|
"self-test": "node src/index.js self-test",
|
package/skills/zentao-cli.md
CHANGED
|
@@ -2,12 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
This package provides a CLI for ZenTao REST API (products + bugs).
|
|
4
4
|
|
|
5
|
+
When instructing users, assume the primary workflow is:
|
|
6
|
+
|
|
7
|
+
1) install with pnpm globally
|
|
8
|
+
2) `zentao login` once
|
|
9
|
+
3) run `zentao ...` commands without passing credentials each time
|
|
10
|
+
|
|
5
11
|
## Installation
|
|
6
12
|
|
|
7
|
-
Global install:
|
|
13
|
+
Global install (recommended):
|
|
8
14
|
|
|
9
15
|
```bash
|
|
10
|
-
|
|
16
|
+
pnpm i -g @leeguoo/zentao-mcp
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
If pnpm is not installed:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm i -g pnpm
|
|
23
|
+
pnpm i -g @leeguoo/zentao-mcp
|
|
11
24
|
```
|
|
12
25
|
|
|
13
26
|
Or use without installing:
|
|
@@ -20,6 +33,19 @@ This installs the `zentao` command (and keeps `zentao-mcp` as a compatibility al
|
|
|
20
33
|
|
|
21
34
|
## Authentication
|
|
22
35
|
|
|
36
|
+
Recommended: login once (stored locally):
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
zentao login --zentao-url=https://zentao.example.com/zentao --zentao-account=leo --zentao-password=***
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
This writes:
|
|
43
|
+
|
|
44
|
+
- `~/.config/zentao/config.toml` (or `$XDG_CONFIG_HOME/zentao/config.toml`)
|
|
45
|
+
|
|
46
|
+
IMPORTANT: `zentaoUrl` should usually include `/zentao`.
|
|
47
|
+
If login returns 404 HTML, your base path is likely missing `/zentao`.
|
|
48
|
+
|
|
23
49
|
You can pass credentials via environment variables:
|
|
24
50
|
|
|
25
51
|
```bash
|
|
@@ -42,24 +68,60 @@ Or via CLI flags:
|
|
|
42
68
|
zentao products list
|
|
43
69
|
```
|
|
44
70
|
|
|
71
|
+
By default, this prints a simple TSV table (key fields). To get full JSON:
|
|
72
|
+
|
|
73
|
+
Full JSON output:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
zentao products list --json
|
|
77
|
+
```
|
|
78
|
+
|
|
45
79
|
### List bugs for a product
|
|
46
80
|
|
|
47
81
|
```bash
|
|
48
82
|
zentao bugs list --product 1
|
|
49
83
|
```
|
|
50
84
|
|
|
85
|
+
By default, this prints a simple TSV table. To get full JSON:
|
|
86
|
+
|
|
87
|
+
Full JSON output:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
zentao bugs list --product 1 --json
|
|
91
|
+
```
|
|
92
|
+
|
|
51
93
|
### Get bug details
|
|
52
94
|
|
|
53
95
|
```bash
|
|
54
96
|
zentao bug get --id 123
|
|
55
97
|
```
|
|
56
98
|
|
|
99
|
+
By default, this prints a simple TSV (single row). To get full JSON:
|
|
100
|
+
|
|
101
|
+
Full JSON output:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
zentao bug get --id 123 --json
|
|
105
|
+
```
|
|
106
|
+
|
|
57
107
|
### List my bugs
|
|
58
108
|
|
|
59
109
|
```bash
|
|
60
110
|
zentao bugs mine --scope assigned --status active
|
|
61
111
|
```
|
|
62
112
|
|
|
113
|
+
By default, this prints a simple summary table. To include bug details:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
zentao bugs mine --status active --include-details
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Full JSON output:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
zentao bugs mine --scope assigned --status active --json
|
|
123
|
+
```
|
|
124
|
+
|
|
63
125
|
Common options:
|
|
64
126
|
|
|
65
127
|
- `--scope`: `assigned|opened|resolved|all`
|
|
@@ -79,19 +141,9 @@ Use `--expected N` to make it CI-friendly (exit code 2 when mismatch):
|
|
|
79
141
|
zentao self-test --expected 0
|
|
80
142
|
```
|
|
81
143
|
|
|
82
|
-
##
|
|
83
|
-
|
|
84
|
-
Save credentials locally:
|
|
85
|
-
|
|
86
|
-
```bash
|
|
87
|
-
zentao login --zentao-url=https://zentao.example.com/zentao --zentao-account=leo --zentao-password=***
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
Config file:
|
|
91
|
-
|
|
92
|
-
- `~/.config/zentao/config.toml` (or `$XDG_CONFIG_HOME/zentao/config.toml`)
|
|
144
|
+
## Whoami
|
|
93
145
|
|
|
94
|
-
|
|
146
|
+
After login:
|
|
95
147
|
|
|
96
148
|
```bash
|
|
97
149
|
zentao whoami
|
|
@@ -104,3 +156,12 @@ Requires `git`, `npm`, and `gh`.
|
|
|
104
156
|
```bash
|
|
105
157
|
zentao release patch --dry-run
|
|
106
158
|
```
|
|
159
|
+
|
|
160
|
+
Recommended publishing flow is via GitHub Actions npm Trusted Publisher (OIDC):
|
|
161
|
+
|
|
162
|
+
1) bump `package.json` version
|
|
163
|
+
2) create a matching tag `vX.Y.Z`
|
|
164
|
+
3) push the tag to GitHub
|
|
165
|
+
4) workflow `publish-npm.yml` publishes to npm
|
|
166
|
+
|
|
167
|
+
If you use Actions publishing, prefer `zentao release patch --skip-publish` locally.
|
package/src/cli/help.js
CHANGED
|
@@ -4,10 +4,10 @@ export function printRootHelp() {
|
|
|
4
4
|
process.stdout.write(`Usage:\n`);
|
|
5
5
|
process.stdout.write(` zentao login [--zentao-url ... --zentao-account ... --zentao-password ...] [--yes]\n`);
|
|
6
6
|
process.stdout.write(` zentao whoami\n`);
|
|
7
|
-
process.stdout.write(` zentao products list [--page N] [--limit N]\n`);
|
|
8
|
-
process.stdout.write(` zentao bugs list --product <id> [--page N] [--limit N]\n`);
|
|
9
|
-
process.stdout.write(` zentao bug get --id <bugId
|
|
10
|
-
process.stdout.write(` zentao bugs mine [--scope ...] [--status ...] [--include-details]\n`);
|
|
7
|
+
process.stdout.write(` zentao products list [--page N] [--limit N] [--json]\n`);
|
|
8
|
+
process.stdout.write(` zentao bugs list --product <id> [--page N] [--limit N] [--json]\n`);
|
|
9
|
+
process.stdout.write(` zentao bug get --id <bugId> [--json]\n`);
|
|
10
|
+
process.stdout.write(` zentao bugs mine [--scope ...] [--status ...] [--include-details] [--json]\n`);
|
|
11
11
|
process.stdout.write(` zentao self-test [--expected N]\n`);
|
|
12
12
|
process.stdout.write(` zentao release [patch|minor|major] [--dry-run] [--yes]\n\n`);
|
|
13
13
|
process.stdout.write(`Auth options:\n`);
|
package/src/commands/bug.js
CHANGED
|
@@ -3,9 +3,40 @@ import { extractCommand, hasHelpFlag, parseCliArgs } from "../cli/args.js";
|
|
|
3
3
|
import { createClientFromCli } from "../zentao/client.js";
|
|
4
4
|
|
|
5
5
|
function printHelp() {
|
|
6
|
-
process.stdout.write(`zentao
|
|
6
|
+
process.stdout.write(`zentao bug get\n\n`);
|
|
7
7
|
process.stdout.write(`Usage:\n`);
|
|
8
|
-
process.stdout.write(` zentao
|
|
8
|
+
process.stdout.write(` zentao bug get --id <bugId> [--json]\n`);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function formatAccount(value) {
|
|
12
|
+
if (!value) return "";
|
|
13
|
+
if (typeof value === "string" || typeof value === "number") return String(value);
|
|
14
|
+
if (typeof value === "object") return String(value.account || value.name || value.realname || "");
|
|
15
|
+
return "";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function formatBugSimple(bug) {
|
|
19
|
+
const header = [
|
|
20
|
+
"id",
|
|
21
|
+
"title",
|
|
22
|
+
"status",
|
|
23
|
+
"pri",
|
|
24
|
+
"severity",
|
|
25
|
+
"assignedTo",
|
|
26
|
+
"openedBy",
|
|
27
|
+
"resolvedBy",
|
|
28
|
+
].join("\t");
|
|
29
|
+
const row = [
|
|
30
|
+
String(bug?.id ?? ""),
|
|
31
|
+
String(bug?.title ?? ""),
|
|
32
|
+
String(bug?.status ?? ""),
|
|
33
|
+
String(bug?.pri ?? ""),
|
|
34
|
+
String(bug?.severity ?? ""),
|
|
35
|
+
formatAccount(bug?.assignedTo),
|
|
36
|
+
formatAccount(bug?.openedBy),
|
|
37
|
+
formatAccount(bug?.resolvedBy),
|
|
38
|
+
].join("\t");
|
|
39
|
+
return `${header}\n${row}\n`;
|
|
9
40
|
}
|
|
10
41
|
|
|
11
42
|
export async function runBug({ argv = [], env = process.env } = {}) {
|
|
@@ -23,5 +54,16 @@ export async function runBug({ argv = [], env = process.env } = {}) {
|
|
|
23
54
|
|
|
24
55
|
const api = createClientFromCli({ argv: argvWithoutSub, env });
|
|
25
56
|
const result = await api.getBug({ id });
|
|
26
|
-
|
|
57
|
+
if (cliArgs.json) {
|
|
58
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const bug = result?.result?.bug;
|
|
63
|
+
if (!bug || typeof bug !== "object") {
|
|
64
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
process.stdout.write(formatBugSimple(bug));
|
|
27
69
|
}
|
package/src/commands/bugs.js
CHANGED
|
@@ -18,10 +18,62 @@ function parseCsvIntegers(value) {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
function printHelp() {
|
|
21
|
-
process.stdout.write(`zentao
|
|
21
|
+
process.stdout.write(`zentao bugs <subcommand>\n\n`);
|
|
22
22
|
process.stdout.write(`Usage:\n`);
|
|
23
|
-
process.stdout.write(` zentao
|
|
24
|
-
process.stdout.write(` zentao
|
|
23
|
+
process.stdout.write(` zentao bugs list --product <id> [--page N] [--limit N] [--json]\n`);
|
|
24
|
+
process.stdout.write(` zentao bugs mine [--scope assigned|opened|resolved|all] [--status active|resolved|closed|all] [--include-details] [--json]\n`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function formatAccount(value) {
|
|
28
|
+
if (!value) return "";
|
|
29
|
+
if (typeof value === "string" || typeof value === "number") return String(value);
|
|
30
|
+
if (typeof value === "object") return String(value.account || value.name || value.realname || "");
|
|
31
|
+
return "";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function formatBugsSimple(bugs) {
|
|
35
|
+
const rows = [];
|
|
36
|
+
rows.push(["id", "title", "status", "pri", "severity", "assignedTo"].join("\t"));
|
|
37
|
+
for (const bug of bugs) {
|
|
38
|
+
rows.push(
|
|
39
|
+
[
|
|
40
|
+
String(bug?.id ?? ""),
|
|
41
|
+
String(bug?.title ?? ""),
|
|
42
|
+
String(bug?.status ?? ""),
|
|
43
|
+
String(bug?.pri ?? ""),
|
|
44
|
+
String(bug?.severity ?? ""),
|
|
45
|
+
formatAccount(bug?.assignedTo),
|
|
46
|
+
].join("\t")
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
return `${rows.join("\n")}\n`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function formatBugsMineSimple(result) {
|
|
53
|
+
const total = result?.total ?? 0;
|
|
54
|
+
const products = Array.isArray(result?.products) ? result.products : [];
|
|
55
|
+
const rows = [];
|
|
56
|
+
rows.push(`total\t${total}`);
|
|
57
|
+
rows.push(["id", "name", "myBugs", "totalBugs"].join("\t"));
|
|
58
|
+
for (const product of products) {
|
|
59
|
+
rows.push(
|
|
60
|
+
[
|
|
61
|
+
String(product?.id ?? ""),
|
|
62
|
+
String(product?.name ?? ""),
|
|
63
|
+
String(product?.myBugs ?? ""),
|
|
64
|
+
String(product?.totalBugs ?? ""),
|
|
65
|
+
].join("\t")
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const bugs = Array.isArray(result?.bugs) ? result.bugs : [];
|
|
70
|
+
if (bugs.length) {
|
|
71
|
+
rows.push("");
|
|
72
|
+
rows.push("bugs");
|
|
73
|
+
rows.push(formatBugsSimple(bugs).trimEnd());
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return `${rows.join("\n")}\n`;
|
|
25
77
|
}
|
|
26
78
|
|
|
27
79
|
export async function runBugs({ argv = [], env = process.env } = {}) {
|
|
@@ -42,7 +94,19 @@ export async function runBugs({ argv = [], env = process.env } = {}) {
|
|
|
42
94
|
page: cliArgs.page,
|
|
43
95
|
limit: cliArgs.limit,
|
|
44
96
|
});
|
|
45
|
-
|
|
97
|
+
|
|
98
|
+
if (cliArgs.json) {
|
|
99
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const bugs = result?.result?.bugs;
|
|
104
|
+
if (!Array.isArray(bugs)) {
|
|
105
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
process.stdout.write(formatBugsSimple(bugs));
|
|
46
110
|
return;
|
|
47
111
|
}
|
|
48
112
|
|
|
@@ -60,7 +124,13 @@ export async function runBugs({ argv = [], env = process.env } = {}) {
|
|
|
60
124
|
maxItems: cliArgs["max-items"],
|
|
61
125
|
includeDetails,
|
|
62
126
|
});
|
|
63
|
-
|
|
127
|
+
|
|
128
|
+
if (cliArgs.json) {
|
|
129
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
process.stdout.write(formatBugsMineSimple(result?.result));
|
|
64
134
|
return;
|
|
65
135
|
}
|
|
66
136
|
|
package/src/commands/products.js
CHANGED
|
@@ -3,9 +3,28 @@ import { extractCommand, hasHelpFlag, parseCliArgs } from "../cli/args.js";
|
|
|
3
3
|
import { createClientFromCli } from "../zentao/client.js";
|
|
4
4
|
|
|
5
5
|
function printHelp() {
|
|
6
|
-
process.stdout.write(`zentao
|
|
6
|
+
process.stdout.write(`zentao products list\n\n`);
|
|
7
7
|
process.stdout.write(`Usage:\n`);
|
|
8
|
-
process.stdout.write(` zentao
|
|
8
|
+
process.stdout.write(` zentao products list [--page N] [--limit N] [--json]\n`);
|
|
9
|
+
process.stdout.write(`\n`);
|
|
10
|
+
process.stdout.write(`Options:\n`);
|
|
11
|
+
process.stdout.write(` --json print full JSON payload\n`);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function formatProductsSimple(products) {
|
|
15
|
+
const rows = [];
|
|
16
|
+
rows.push(["id", "name", "totalBugs", "status"].join("\t"));
|
|
17
|
+
for (const product of products) {
|
|
18
|
+
rows.push(
|
|
19
|
+
[
|
|
20
|
+
String(product.id ?? ""),
|
|
21
|
+
String(product.name ?? ""),
|
|
22
|
+
String(product.totalBugs ?? product.totalBugsCount ?? ""),
|
|
23
|
+
String(product.status ?? product.productStatus ?? ""),
|
|
24
|
+
].join("\t")
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
return `${rows.join("\n")}\n`;
|
|
9
28
|
}
|
|
10
29
|
|
|
11
30
|
export async function runProducts({ argv = [], env = process.env } = {}) {
|
|
@@ -23,5 +42,17 @@ export async function runProducts({ argv = [], env = process.env } = {}) {
|
|
|
23
42
|
page: cliArgs.page,
|
|
24
43
|
limit: cliArgs.limit,
|
|
25
44
|
});
|
|
26
|
-
|
|
45
|
+
|
|
46
|
+
if (cliArgs.json) {
|
|
47
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const products = result?.result?.products;
|
|
52
|
+
if (!Array.isArray(products)) {
|
|
53
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
process.stdout.write(formatProductsSimple(products));
|
|
27
58
|
}
|