@coderpp/yunxiao-cli 0.1.4 → 0.1.5

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 CHANGED
@@ -28,7 +28,7 @@ npx @coderpp/yunxiao-cli mr list --state opened
28
28
  也可以指定版本:
29
29
 
30
30
  ```bash
31
- npx @coderpp/yunxiao-cli@0.1.0 mr list --json
31
+ npx @coderpp/yunxiao-cli@0.1.4 mr list --output json
32
32
  ```
33
33
 
34
34
  包内的可执行命令名仍然是 `yunxiao`,全局安装后可这样使用:
@@ -97,7 +97,7 @@ node dist/src/index.js mr list --state opened --project-ids 2813489 --per-page 2
97
97
  输出 JSON:
98
98
 
99
99
  ```bash
100
- node dist/src/index.js mr list --state opened --json
100
+ node dist/src/index.js mr list --state opened --output json
101
101
  ```
102
102
 
103
103
  评审通过指定合并请求:
@@ -132,6 +132,24 @@ node dist/src/index.js mr tree 2813489 12 \
132
132
  node dist/src/index.js mr patches 2813489 12
133
133
  ```
134
134
 
135
+ ## 输出格式
136
+
137
+ 所有会输出 API 结果的命令都支持 `--output`:
138
+
139
+ ```bash
140
+ node dist/src/index.js mr list --output table
141
+ node dist/src/index.js mr list --output json
142
+ node dist/src/index.js mr review 2813489 12 --output table
143
+ node dist/src/index.js mr patches 2813489 12 --output json
144
+ ```
145
+
146
+ 支持的格式:
147
+
148
+ - `table`:普通表格文本,默认值。
149
+ - `json`:格式化 JSON。
150
+
151
+ `--json` 仍然可用,等价于 `--output json`。
152
+
135
153
  ## 参数补充
136
154
 
137
155
  `repositoryId` 可以是代码库 ID,也可以是仓库完整路径,工具会自动做 URL 编码。
package/dist/src/cli.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { YunxiaoClient } from "./client.js";
2
2
  const mergeTypes = new Set(["ff-only", "no-fast-forward", "squash", "rebase"]);
3
+ const outputFormats = new Set(["table", "json"]);
3
4
  export async function runCli(args = process.argv.slice(2), env = process.env, io = {}) {
4
5
  const stdout = io.stdout ?? ((text) => process.stdout.write(text));
5
6
  const stderr = io.stderr ?? ((text) => process.stderr.write(text));
@@ -13,11 +14,12 @@ export async function runCli(args = process.argv.slice(2), env = process.env, io
13
14
  if (scope !== "mr" || !command) {
14
15
  throw new Error(`Unknown command: ${parsed.positionals.join(" ")}`);
15
16
  }
17
+ const outputFormat = outputFormatFromFlags(parsed.flags);
16
18
  const client = createClient(parsed.flags, env, io.fetcher);
17
19
  let result;
18
20
  if (command === "list") {
19
21
  result = await client.listChangeRequests(listOptions(parsed.flags));
20
- printResult(result, Boolean(parsed.flags.json), stdout);
22
+ printResult(result, outputFormat, stdout);
21
23
  return 0;
22
24
  }
23
25
  if (!repositoryId || !localIdRaw) {
@@ -53,7 +55,7 @@ export async function runCli(args = process.argv.slice(2), env = process.env, io
53
55
  default:
54
56
  throw new Error(`Unknown mr command: ${command}`);
55
57
  }
56
- printResult(result, Boolean(parsed.flags.json), stdout);
58
+ printResult(result, outputFormat, stdout);
57
59
  return 0;
58
60
  }
59
61
  catch (error) {
@@ -126,8 +128,19 @@ function requireConfirmation(flags) {
126
128
  throw new Error("This command changes repository state. Re-run with --yes after you have reviewed the merge request.");
127
129
  }
128
130
  }
129
- function printResult(result, asJson, stdout) {
130
- if (asJson) {
131
+ function outputFormatFromFlags(flags) {
132
+ const requestedOutput = optionalString(flags.output);
133
+ if (flags.json && requestedOutput && requestedOutput !== "json") {
134
+ throw new Error("--json cannot be combined with --output table.");
135
+ }
136
+ const output = flags.json ? "json" : requestedOutput ?? "table";
137
+ if (!outputFormats.has(output)) {
138
+ throw new Error(`Invalid --output: ${output}. Supported formats: table, json.`);
139
+ }
140
+ return output;
141
+ }
142
+ function printResult(result, outputFormat, stdout) {
143
+ if (outputFormat === "json") {
131
144
  stdout(`${JSON.stringify(result, null, 2)}\n`);
132
145
  return;
133
146
  }
@@ -135,22 +148,50 @@ function printResult(result, asJson, stdout) {
135
148
  stdout(formatTable(result));
136
149
  return;
137
150
  }
138
- stdout(`${JSON.stringify(result, null, 2)}\n`);
151
+ if (isRecord(result)) {
152
+ stdout(formatKeyValueTable(result));
153
+ return;
154
+ }
155
+ if (result === null || result === undefined) {
156
+ stdout("No result.\n");
157
+ return;
158
+ }
159
+ stdout(`${String(result)}\n`);
139
160
  }
140
161
  function formatTable(rows) {
141
162
  if (rows.length === 0) {
142
163
  return "No records found.\n";
143
164
  }
144
165
  const normalizedRows = rows.map((row) => (isRecord(row) ? row : { value: row }));
145
- const keys = ["localId", "projectId", "title", "state", "sourceBranch", "targetBranch", "detailUrl"].filter((key) => normalizedRows.some((row) => row[key] !== undefined));
146
- const widths = keys.map((key) => Math.max(key.length, ...normalizedRows.map((row) => String(row[key] ?? "").length)));
166
+ const preferredKeys = ["localId", "projectId", "title", "state", "sourceBranch", "targetBranch", "detailUrl"].filter((key) => normalizedRows.some((row) => row[key] !== undefined));
167
+ const keys = preferredKeys.length > 0 ? preferredKeys : uniqueKeys(normalizedRows);
168
+ const widths = keys.map((key) => Math.max(key.length, ...normalizedRows.map((row) => formatCellValue(row[key]).length)));
147
169
  const line = (values) => values.map((value, index) => value.padEnd(widths[index])).join(" ");
148
170
  return [
149
171
  line(keys),
150
172
  line(keys.map((_, index) => "-".repeat(widths[index]))),
151
- ...normalizedRows.map((row) => line(keys.map((key) => String(row[key] ?? ""))))
173
+ ...normalizedRows.map((row) => line(keys.map((key) => formatCellValue(row[key]))))
152
174
  ].join("\n") + "\n";
153
175
  }
176
+ function uniqueKeys(rows) {
177
+ return Array.from(new Set(rows.flatMap((row) => Object.keys(row))));
178
+ }
179
+ function formatKeyValueTable(record) {
180
+ const rows = Object.entries(record).map(([key, value]) => ({
181
+ key,
182
+ value: formatCellValue(value)
183
+ }));
184
+ return formatTable(rows);
185
+ }
186
+ function formatCellValue(value) {
187
+ if (value === null || value === undefined) {
188
+ return "";
189
+ }
190
+ if (typeof value === "object") {
191
+ return JSON.stringify(value);
192
+ }
193
+ return String(value);
194
+ }
154
195
  function parseLocalId(value) {
155
196
  const localId = Number(value);
156
197
  if (!Number.isInteger(localId) || localId <= 0) {
@@ -188,12 +229,17 @@ function helpText() {
188
229
  return `yunxiao - Yunxiao Codeup merge request helper
189
230
 
190
231
  Usage:
191
- yunxiao mr list [--state opened] [--project-ids 2813489] [--json]
192
- yunxiao mr review <repositoryId> <localId> [--comment "LGTM"]
193
- yunxiao mr merge <repositoryId> <localId> --yes [--merge-type no-fast-forward]
194
- yunxiao mr approve-and-merge <repositoryId> <localId> --yes [--merge-type no-fast-forward]
195
- yunxiao mr tree <repositoryId> <localId> --from-patch-set-id <id> --to-patch-set-id <id>
196
- yunxiao mr patches <repositoryId> <localId>
232
+ yunxiao mr list [--state opened] [--project-ids 2813489] [--output table|json]
233
+ yunxiao mr review <repositoryId> <localId> [--comment "LGTM"] [--output table|json]
234
+ yunxiao mr merge <repositoryId> <localId> --yes [--merge-type no-fast-forward] [--output table|json]
235
+ yunxiao mr approve-and-merge <repositoryId> <localId> --yes [--merge-type no-fast-forward] [--output table|json]
236
+ yunxiao mr tree <repositoryId> <localId> --from-patch-set-id <id> --to-patch-set-id <id> [--output table|json]
237
+ yunxiao mr patches <repositoryId> <localId> [--output table|json]
238
+
239
+ Output:
240
+ --output table Plain text table output, default
241
+ --output json Pretty JSON output
242
+ --json Alias for --output json
197
243
 
198
244
  Config:
199
245
  YUNXIAO_TOKEN Personal access token
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coderpp/yunxiao-cli",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "A CLI for Yunxiao Codeup merge request review and merge workflows.",
5
5
  "type": "module",
6
6
  "repository": {