Migrated from parseArgs from node:util to commander.js.
All checks were successful
build / build (push) Successful in 14s
All checks were successful
build / build (push) Successful in 14s
This commit is contained in:
@@ -4,7 +4,9 @@ import { getAccessToken } from "../../azure/index.ts";
|
||||
import { getDevOpsApiToken } from "../../devops/index.ts";
|
||||
import { loadAuthConfig } from "../../index.ts";
|
||||
|
||||
import type { CommandValues } from "./types.ts";
|
||||
type GetTokenOptions = {
|
||||
type?: string;
|
||||
};
|
||||
|
||||
export function usageGetToken(): string {
|
||||
return `Usage: sk-az-tools get-token --type|-t <azurerm|devops> [global options]
|
||||
@@ -14,9 +16,9 @@ Options:
|
||||
}
|
||||
|
||||
export async function runGetTokenCommand(
|
||||
values: CommandValues,
|
||||
options: GetTokenOptions,
|
||||
): Promise<unknown> {
|
||||
const tokenType = (values.type ?? "").toString().trim().toLowerCase();
|
||||
const tokenType = (options.type ?? "").toString().trim().toLowerCase();
|
||||
if (!tokenType) {
|
||||
throw new Error(
|
||||
"--type is required for get-token (allowed: azurerm, devops)",
|
||||
@@ -49,5 +51,5 @@ export async function runGetTokenCommand(
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error(`Invalid --type '${values.type}'. Allowed: azurerm, devops`);
|
||||
throw new Error(`Invalid --type '${options.type}'. Allowed: azurerm, devops`);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
|
||||
import { listAppGrants } from "../../graph/app.ts";
|
||||
import { getGraphClient } from "../../graph/index.ts";
|
||||
import type { CommandValues } from "./types.ts";
|
||||
|
||||
type ListAppGrantsOptions = {
|
||||
appId?: string;
|
||||
};
|
||||
|
||||
export function usageListAppGrants(): string {
|
||||
return `Usage: sk-az-tools list-app-grants --app-id|-i <appId> [global options]
|
||||
@@ -11,11 +14,11 @@ Options:
|
||||
--app-id, -i <appId> Application (client) ID (required)`;
|
||||
}
|
||||
|
||||
export async function runListAppGrantsCommand(values: CommandValues): Promise<unknown> {
|
||||
if (!values["app-id"]) {
|
||||
export async function runListAppGrantsCommand(options: ListAppGrantsOptions): Promise<unknown> {
|
||||
if (!options.appId) {
|
||||
throw new Error("--app-id is required for list-app-grants");
|
||||
}
|
||||
|
||||
const client = await getGraphClient();
|
||||
return listAppGrants(client, values["app-id"]);
|
||||
return listAppGrants(client, options.appId);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,13 @@ import { listAppPermissions, listAppPermissionsResolved } from "../../graph/app.
|
||||
|
||||
import { filterByPermissionName } from "./shared.ts";
|
||||
import { getGraphClient } from "../../graph/index.ts";
|
||||
import type { CommandValues } from "./types.ts";
|
||||
|
||||
type ListAppPermissionsOptions = {
|
||||
appId?: string;
|
||||
resolve?: boolean;
|
||||
short?: boolean;
|
||||
filter?: string;
|
||||
};
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return value !== null && typeof value === "object" && !Array.isArray(value);
|
||||
@@ -33,20 +39,20 @@ Options:
|
||||
--filter, -f <glob> Filter by permission name glob`;
|
||||
}
|
||||
|
||||
export async function runListAppPermissionsCommand(values: CommandValues): Promise<unknown> {
|
||||
if (!values["app-id"]) {
|
||||
export async function runListAppPermissionsCommand(options: ListAppPermissionsOptions): Promise<unknown> {
|
||||
if (!options.appId) {
|
||||
throw new Error("--app-id is required for list-app-permissions");
|
||||
}
|
||||
|
||||
const client = await getGraphClient();
|
||||
let result: unknown = values.resolve || values.filter
|
||||
? await listAppPermissionsResolved(client, values["app-id"])
|
||||
: await listAppPermissions(client, values["app-id"]);
|
||||
if (values.short) {
|
||||
let result: unknown = options.resolve || options.filter
|
||||
? await listAppPermissionsResolved(client, options.appId)
|
||||
: await listAppPermissions(client, options.appId);
|
||||
if (options.short) {
|
||||
result = omitColumns(result, ["resourceAppId", "permissionId"]);
|
||||
}
|
||||
if (values.filter) {
|
||||
result = filterByPermissionName(result as Array<Record<string, unknown>>, values.filter);
|
||||
if (options.filter) {
|
||||
result = filterByPermissionName(result as Array<Record<string, unknown>>, options.filter);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -3,26 +3,23 @@
|
||||
import { listApps } from "../../graph/app.ts";
|
||||
import { filterByDisplayName } from "./shared.ts";
|
||||
import { getGraphClient } from "../../graph/index.ts";
|
||||
import type { CommandValues } from "./types.ts";
|
||||
|
||||
export function usageListApps(): string {
|
||||
return `Usage: sk-az-tools list-apps [--display-name|-n <name>] [--app-id|-i <appId>] [--filter|-f <glob>] [global options]
|
||||
type ListAppsOptions = {
|
||||
displayName?: string;
|
||||
appId?: string;
|
||||
filter?: string;
|
||||
};
|
||||
|
||||
Options:
|
||||
--display-name, -n <name> Get app by name
|
||||
--app-id, -i <appId> Get app by id
|
||||
--filter, -f <glob> Filter by app display name glob`;
|
||||
}
|
||||
|
||||
export async function runListAppsCommand(values: CommandValues): Promise<unknown> {
|
||||
export async function runListAppsCommand(options: ListAppsOptions): Promise<unknown> {
|
||||
const client = await getGraphClient();
|
||||
|
||||
let result = await listApps(client, values["display-name"], values["app-id"]);
|
||||
if (values["app-id"] && result.length > 1) {
|
||||
throw new Error(`Expected a single app for --app-id ${values["app-id"]}, but got ${result.length}`);
|
||||
let result = await listApps(client, options.displayName, options.appId);
|
||||
|
||||
if (options.appId && result.length > 1) {
|
||||
throw new Error(`Expected a single app for --app-id ${options.appId}, but got ${result.length}`);
|
||||
}
|
||||
if (values.filter) {
|
||||
result = filterByDisplayName(result, values.filter);
|
||||
if (options.filter) {
|
||||
result = filterByDisplayName(result, options.filter);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,12 @@
|
||||
import { listResourcePermissions } from "../../graph/app.ts";
|
||||
import { getGraphClient } from "../../graph/index.ts";
|
||||
import { filterByPermissionName } from "./shared.ts";
|
||||
import type { CommandValues } from "./types.ts";
|
||||
|
||||
type ListResourcePermissionsOptions = {
|
||||
appId?: string;
|
||||
displayName?: string;
|
||||
filter?: string;
|
||||
};
|
||||
|
||||
export function usageListResourcePermissions(): string {
|
||||
return `Usage: sk-az-tools list-resource-permissions [--app-id|-i <appId> | --display-name|-n <name>] [--filter|-f <glob>] [global options]
|
||||
@@ -14,22 +19,22 @@ Options:
|
||||
--filter, -f <glob> Filter by permission name glob`;
|
||||
}
|
||||
|
||||
export async function runListResourcePermissionsCommand(values: CommandValues): Promise<unknown> {
|
||||
if (!values["app-id"] && !values["display-name"]) {
|
||||
export async function runListResourcePermissionsCommand(options: ListResourcePermissionsOptions): Promise<unknown> {
|
||||
if (!options.appId && !options.displayName) {
|
||||
throw new Error("--app-id or --display-name is required for list-resource-permissions");
|
||||
}
|
||||
if (values["app-id"] && values["display-name"]) {
|
||||
if (options.appId && options.displayName) {
|
||||
throw new Error("Use either --app-id or --display-name for list-resource-permissions, not both");
|
||||
}
|
||||
|
||||
const client = await getGraphClient();
|
||||
let result = await listResourcePermissions(
|
||||
client,
|
||||
values["app-id"],
|
||||
values["display-name"],
|
||||
options.appId,
|
||||
options.displayName,
|
||||
);
|
||||
if (values.filter) {
|
||||
result = filterByPermissionName(result, values.filter);
|
||||
if (options.filter) {
|
||||
result = filterByPermissionName(result, options.filter);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,13 @@
|
||||
import { login } from "../../azure/index.ts";
|
||||
import { loadAuthConfig } from "../../index.ts";
|
||||
|
||||
import type { CommandValues } from "./types.ts";
|
||||
type LoginOptions = {
|
||||
resources?: string;
|
||||
useDeviceCode?: boolean;
|
||||
noBrowser?: boolean;
|
||||
browser?: string;
|
||||
browserProfile?: string;
|
||||
};
|
||||
|
||||
export function usageLogin(): string {
|
||||
return `Usage: sk-az-tools login [--resources <csv>] [--use-device-code] [--no-browser] [--browser <name>] [--browser-profile <profile>] [global options]
|
||||
@@ -16,15 +22,15 @@ Options:
|
||||
--browser-profile <name> Chromium profile name (e.g. Default, "Profile 1")`;
|
||||
}
|
||||
|
||||
export async function runLoginCommand(values: CommandValues): Promise<unknown> {
|
||||
export async function runLoginCommand(options: LoginOptions): Promise<unknown> {
|
||||
const config = await loadAuthConfig("public-config");
|
||||
return login(
|
||||
config.tenantId,
|
||||
config.clientId,
|
||||
values.resources,
|
||||
Boolean(values["use-device-code"]),
|
||||
Boolean(values["no-browser"]),
|
||||
values.browser,
|
||||
values["browser-profile"],
|
||||
options.resources,
|
||||
Boolean(options.useDeviceCode),
|
||||
Boolean(options.noBrowser),
|
||||
options.browser,
|
||||
options.browserProfile,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
import { logout } from "../../azure/index.ts";
|
||||
import { loadAuthConfig } from "../../index.ts";
|
||||
|
||||
import type { CommandValues } from "./types.ts";
|
||||
type LogoutOptions = {
|
||||
all?: boolean;
|
||||
};
|
||||
|
||||
export function usageLogout(): string {
|
||||
return `Usage: sk-az-tools logout [--all] [global options]
|
||||
@@ -12,7 +14,7 @@ Options:
|
||||
--all Clear login state and remove all cached accounts`;
|
||||
}
|
||||
|
||||
export async function runLogoutCommand(values: CommandValues): Promise<unknown> {
|
||||
export async function runLogoutCommand(options: LogoutOptions): Promise<unknown> {
|
||||
const config = await loadAuthConfig("public-config");
|
||||
return logout(config.tenantId, config.clientId, Boolean(values.all));
|
||||
return logout(config.tenantId, config.clientId, Boolean(options.all));
|
||||
}
|
||||
|
||||
@@ -4,21 +4,6 @@ import { getAccessToken } from "../../azure/index.ts";
|
||||
import { getDevOpsApiToken } from "../../devops/index.ts";
|
||||
import { loadAuthConfig } from "../../index.ts";
|
||||
|
||||
import type { CommandValues } from "./types.ts";
|
||||
|
||||
export function usageRest(): string {
|
||||
return `Usage: sk-az-tools rest [--method <httpMethod>] --url <url> [--header <name: value>] [global options]
|
||||
|
||||
Options:
|
||||
--method <httpMethod> HTTP method (default: GET; examples: GET, POST, PATCH, DELETE)
|
||||
--url <url> Full URL to call
|
||||
--header <name: value> Extra request header; example: "Content-Type: application/json"
|
||||
|
||||
Authorization is added automatically for:
|
||||
management.azure.com Uses azurerm token
|
||||
dev.azure.com Uses devops token`;
|
||||
}
|
||||
|
||||
function parseHeaderLine(
|
||||
header?: string,
|
||||
): { name: string; value: string } | null {
|
||||
@@ -70,24 +55,30 @@ async function getAutoAuthorizationHeader(url: URL): Promise<string | null> {
|
||||
return `Bearer ${accessToken}`;
|
||||
}
|
||||
|
||||
export async function runRestCommand(values: CommandValues): Promise<unknown> {
|
||||
const method =
|
||||
(values.method ?? "GET").toString().trim().toUpperCase() || "GET";
|
||||
const urlValue = (values.url ?? "").toString().trim();
|
||||
type httpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
||||
|
||||
type restOptions = {
|
||||
method?: httpMethod;
|
||||
header?: string;
|
||||
};
|
||||
|
||||
export async function runRestCommand(url: string, options: restOptions): Promise<unknown> {
|
||||
const method = options.method || "GET";
|
||||
const urlValue = (url ?? "").toString().trim();
|
||||
|
||||
if (!urlValue) {
|
||||
throw new Error("--url is required for rest");
|
||||
throw new Error("URL is required for rest");
|
||||
}
|
||||
|
||||
let targetUrl: URL;
|
||||
try {
|
||||
targetUrl = new URL(urlValue);
|
||||
} catch {
|
||||
throw new Error(`Invalid --url '${urlValue}'`);
|
||||
throw new Error(`Invalid URL '${urlValue}'`);
|
||||
}
|
||||
|
||||
const headers = new Headers();
|
||||
const customHeader = parseHeaderLine(values.header);
|
||||
const customHeader = parseHeaderLine(options.header);
|
||||
if (customHeader) {
|
||||
headers.set(customHeader.name, customHeader.value);
|
||||
}
|
||||
@@ -105,9 +96,9 @@ export async function runRestCommand(values: CommandValues): Promise<unknown> {
|
||||
});
|
||||
|
||||
const contentType = response.headers.get("content-type") ?? "";
|
||||
let body: unknown;
|
||||
let body: string;
|
||||
if (contentType.toLowerCase().includes("application/json")) {
|
||||
body = await response.json();
|
||||
body = JSON.stringify(await response.json());
|
||||
} else {
|
||||
body = await response.text();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user