update: adopted new output options. Various optimizations.
Some checks failed
build / build (push) Failing after 15s
Some checks failed
build / build (push) Failing after 15s
This commit is contained in:
@@ -6,6 +6,22 @@ The `sk-az-tools` package may act as a CLI tool that provides various commands f
|
|||||||
- Azure Resource Manager
|
- Azure Resource Manager
|
||||||
- Azure DevOps Services
|
- Azure DevOps Services
|
||||||
|
|
||||||
|
## Global Options
|
||||||
|
|
||||||
|
These options apply to all commands unless stated otherwise:
|
||||||
|
|
||||||
|
- `--query`, `-q` <jmespath> - Apply JMESPath filter before output rendering.
|
||||||
|
- `--output`, `-o` <format> - Output format: `table|t|alignedtable|at|prettytable|pt|tsv`.
|
||||||
|
- `--columns`, `-C` <definition> - Column selection for table outputs:
|
||||||
|
- `col1` - Select column (case-insensitive match), keep raw header label.
|
||||||
|
- `col1:` - Select column (case-insensitive match), use auto-generated header label.
|
||||||
|
- `col1: Label 1` - Select column (case-insensitive match), use custom header label.
|
||||||
|
- Prefix token with `=` for exact column-name match: `=col1`, `=col1:`, `=col1:Label`.
|
||||||
|
- Tokens are comma-separated and rendered in the specified order.
|
||||||
|
- `--help`, `-h` - Show command help.
|
||||||
|
|
||||||
|
Note: `rest --header` is a command-specific HTTP header option and is unrelated to `--columns`.
|
||||||
|
|
||||||
## Login
|
## Login
|
||||||
|
|
||||||
**Command name:** `login`
|
**Command name:** `login`
|
||||||
|
|||||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@slawek/sk-az-tools",
|
"name": "@slawek/sk-az-tools",
|
||||||
"version": "0.4.5",
|
"version": "0.5.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@slawek/sk-az-tools",
|
"name": "@slawek/sk-az-tools",
|
||||||
"version": "0.4.5",
|
"version": "0.5.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"files": [
|
"files": [
|
||||||
"dist",
|
"dist",
|
||||||
|
|||||||
35
src/cli.ts
35
src/cli.ts
@@ -13,10 +13,7 @@ import { usageLogin } from "./cli/commands/login.ts";
|
|||||||
import { usageLogout } from "./cli/commands/logout.ts";
|
import { usageLogout } from "./cli/commands/logout.ts";
|
||||||
import { usageRest } from "./cli/commands/rest.ts";
|
import { usageRest } from "./cli/commands/rest.ts";
|
||||||
import {
|
import {
|
||||||
normalizeOutputFormat,
|
renderCliOutput,
|
||||||
outputFiltered,
|
|
||||||
parseHeaderSpec,
|
|
||||||
renderOutput,
|
|
||||||
} from "@slawek/sk-tools";
|
} from "@slawek/sk-tools";
|
||||||
|
|
||||||
type CliValues = {
|
type CliValues = {
|
||||||
@@ -36,6 +33,7 @@ type CliValues = {
|
|||||||
short?: boolean;
|
short?: boolean;
|
||||||
filter?: string;
|
filter?: string;
|
||||||
query?: string;
|
query?: string;
|
||||||
|
columns?: string;
|
||||||
header?: string;
|
header?: string;
|
||||||
output?: string;
|
output?: string;
|
||||||
[key: string]: string | boolean | undefined;
|
[key: string]: string | boolean | undefined;
|
||||||
@@ -56,6 +54,7 @@ Commands:
|
|||||||
|
|
||||||
Global options (all commands):
|
Global options (all commands):
|
||||||
-q, --query <jmespath>
|
-q, --query <jmespath>
|
||||||
|
-C, --columns <definition> Column tokens: col (raw), col: (auto), col:Label (custom), exact via = prefix
|
||||||
-o, --output <format> table|t|alignedtable|at|prettytable|pt|tsv
|
-o, --output <format> table|t|alignedtable|at|prettytable|pt|tsv
|
||||||
-h, --help
|
-h, --help
|
||||||
|
|
||||||
@@ -86,16 +85,6 @@ function usageCommand(command: string): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function omitRecords(record: Record<string, unknown>, names: Set<string>): Record<string, unknown> {
|
|
||||||
return Object.fromEntries(
|
|
||||||
Object.entries(record).filter(([key]) => !names.has(key)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
||||||
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function main(): Promise<void> {
|
async function main(): Promise<void> {
|
||||||
const argv = process.argv.slice(2);
|
const argv = process.argv.slice(2);
|
||||||
const command = argv[0];
|
const command = argv[0];
|
||||||
@@ -128,7 +117,8 @@ async function main(): Promise<void> {
|
|||||||
short: { type: "boolean", short: "s" },
|
short: { type: "boolean", short: "s" },
|
||||||
filter: { type: "string", short: "f" },
|
filter: { type: "string", short: "f" },
|
||||||
query: { type: "string", short: "q" },
|
query: { type: "string", short: "q" },
|
||||||
header: { type: "string", short: "H" },
|
columns: { type: "string", short: "C" },
|
||||||
|
header: { type: "string" },
|
||||||
output: { type: "string", short: "o" },
|
output: { type: "string", short: "o" },
|
||||||
},
|
},
|
||||||
strict: true,
|
strict: true,
|
||||||
@@ -142,19 +132,8 @@ async function main(): Promise<void> {
|
|||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const outputFormat = normalizeOutputFormat(typedValues.output);
|
const output = await runCommand(command, typedValues);
|
||||||
const result = await runCommand(command, typedValues);
|
renderCliOutput(output, typedValues.output, typedValues.query, typedValues.columns);
|
||||||
const filtered = outputFiltered(result, typedValues.query);
|
|
||||||
let output: unknown = filtered;
|
|
||||||
if (command === "list-app-permissions" && typedValues.short && Array.isArray(filtered) && filtered.every(isRecord)) {
|
|
||||||
const names = new Set(["resourceAppId", "permissionId"]);
|
|
||||||
output = filtered.map((item) => omitRecords(item, names));
|
|
||||||
}
|
|
||||||
const headerSpec = command === "rest"
|
|
||||||
? parseHeaderSpec(undefined)
|
|
||||||
: parseHeaderSpec(typedValues.header);
|
|
||||||
|
|
||||||
renderOutput(outputFormat, headerSpec, output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch((err: unknown) => {
|
main().catch((err: unknown) => {
|
||||||
|
|||||||
@@ -5,6 +5,23 @@ import { listAppPermissions, listAppPermissionsResolved } from "../../graph/app.
|
|||||||
import { filterByPermissionName, getGraphClientFromPublicConfig } from "./shared.ts";
|
import { filterByPermissionName, getGraphClientFromPublicConfig } from "./shared.ts";
|
||||||
import type { CommandValues } from "./types.ts";
|
import type { CommandValues } from "./types.ts";
|
||||||
|
|
||||||
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||||
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function omitColumns(input: unknown, names: string[]): unknown {
|
||||||
|
if (!Array.isArray(input) || !input.every(isRecord)) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
const namesSet = new Set(names);
|
||||||
|
return input.map((record) =>
|
||||||
|
Object.fromEntries(
|
||||||
|
Object.entries(record).filter(([key]) => !namesSet.has(key)),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function usageListAppPermissions(): string {
|
export function usageListAppPermissions(): string {
|
||||||
return `Usage: sk-az-tools list-app-permissions --app-id|-i <appId> [--resolve|-r] [--short|-s] [--filter|-f <glob>] [global options]
|
return `Usage: sk-az-tools list-app-permissions --app-id|-i <appId> [--resolve|-r] [--short|-s] [--filter|-f <glob>] [global options]
|
||||||
|
|
||||||
@@ -21,11 +38,14 @@ export async function runListAppPermissionsCommand(values: CommandValues): Promi
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { client } = await getGraphClientFromPublicConfig();
|
const { client } = await getGraphClientFromPublicConfig();
|
||||||
let result = values.resolve || values.filter
|
let result: unknown = values.resolve || values.filter
|
||||||
? await listAppPermissionsResolved(client, values["app-id"])
|
? await listAppPermissionsResolved(client, values["app-id"])
|
||||||
: await listAppPermissions(client, values["app-id"]);
|
: await listAppPermissions(client, values["app-id"]);
|
||||||
|
if (values.short) {
|
||||||
|
result = omitColumns(result, ["resourceAppId", "permissionId"]);
|
||||||
|
}
|
||||||
if (values.filter) {
|
if (values.filter) {
|
||||||
result = filterByPermissionName(result, values.filter);
|
result = filterByPermissionName(result as Array<Record<string, unknown>>, values.filter);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user