Add browser profile option and TSV output mode
- add --browser-profile for login and validate browser/profile combinations\n- validate browser options eagerly and keep default-browser behavior when omitted\n- add TSV output format (no header)\n- change header default to auto; add --header original/-H o\n- remove explicit json/j output mode usage and keep JSON as implicit default\n- add tini to Dockerfile entrypoint path to improve signal handling
This commit is contained in:
@@ -17,6 +17,7 @@ const RESOURCE_SCOPE_BY_NAME = {
|
||||
const DEFAULT_RESOURCES = ["graph", "devops", "arm"];
|
||||
const LOGIN_REQUIRED_MESSAGE = "Login required. Run: sk-az-tools login";
|
||||
const BROWSER_KEYWORDS = Object.keys(apps).sort();
|
||||
const CHROMIUM_BROWSERS = new Set(["edge", "chrome", "brave"]);
|
||||
|
||||
function getCacheRoot() {
|
||||
const isWindows = process.platform === "win32";
|
||||
@@ -80,21 +81,70 @@ function getBrowserAppName(browser) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const requested = browser.trim().toLowerCase();
|
||||
if (requested === "default") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const keyword = BROWSER_KEYWORDS.find((name) => name.toLowerCase() === requested);
|
||||
const keyword = BROWSER_KEYWORDS.find(
|
||||
(name) => name.toLowerCase() === browser.trim().toLowerCase(),
|
||||
);
|
||||
if (!keyword) {
|
||||
throw new Error(
|
||||
`Invalid browser '${browser}'. Allowed: default, ${BROWSER_KEYWORDS.join(", ")}`,
|
||||
`Invalid browser '${browser}'. Allowed: ${BROWSER_KEYWORDS.join(", ")}`,
|
||||
);
|
||||
}
|
||||
|
||||
return apps[keyword];
|
||||
}
|
||||
|
||||
function getBrowserKeyword(browser) {
|
||||
if (!browser || browser.trim() === "") {
|
||||
return "";
|
||||
}
|
||||
|
||||
const requested = browser.trim().toLowerCase();
|
||||
const keyword = BROWSER_KEYWORDS.find((name) => name.toLowerCase() === requested);
|
||||
if (!keyword) {
|
||||
throw new Error(
|
||||
`Invalid browser '${browser}'. Allowed: ${BROWSER_KEYWORDS.join(", ")}`,
|
||||
);
|
||||
}
|
||||
|
||||
return keyword.toLowerCase();
|
||||
}
|
||||
|
||||
function getBrowserOpenOptions({ browser, browserProfile }) {
|
||||
const browserName = getBrowserAppName(browser);
|
||||
const options = browserName
|
||||
? { wait: false, app: { name: browserName } }
|
||||
: { wait: false };
|
||||
|
||||
if (!browserProfile || browserProfile.trim() === "") {
|
||||
return options;
|
||||
}
|
||||
|
||||
const browserKeyword = getBrowserKeyword(browser);
|
||||
if (!CHROMIUM_BROWSERS.has(browserKeyword)) {
|
||||
throw new Error(
|
||||
"--browser-profile is supported only with --browser edge|chrome|brave",
|
||||
);
|
||||
}
|
||||
|
||||
options.app.arguments = [`--profile-directory=${browserProfile.trim()}`];
|
||||
return options;
|
||||
}
|
||||
|
||||
function validateBrowserOptions({ browser, browserProfile }) {
|
||||
if (browser && browser.trim() !== "") {
|
||||
getBrowserAppName(browser);
|
||||
}
|
||||
|
||||
if (browserProfile && browserProfile.trim() !== "") {
|
||||
const browserKeyword = getBrowserKeyword(browser);
|
||||
if (!CHROMIUM_BROWSERS.has(browserKeyword)) {
|
||||
throw new Error(
|
||||
"--browser-profile is supported only with --browser edge|chrome|brave",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function parseResources(resourcesCsv) {
|
||||
if (!resourcesCsv || resourcesCsv.trim() === "") {
|
||||
return [...DEFAULT_RESOURCES];
|
||||
@@ -217,11 +267,13 @@ export async function loginInteractive({
|
||||
scopes,
|
||||
showAuthUrlOnly = false,
|
||||
browser,
|
||||
browserProfile,
|
||||
}) {
|
||||
if (!tenantId) throw new Error("tenantId is required");
|
||||
if (!clientId) throw new Error("clientId is required");
|
||||
if (!Array.isArray(scopes) || scopes.length === 0)
|
||||
throw new Error("scopes[] is required");
|
||||
validateBrowserOptions({ browser, browserProfile });
|
||||
|
||||
const pca = await createPca({ tenantId, clientId });
|
||||
|
||||
@@ -235,10 +287,7 @@ export async function loginInteractive({
|
||||
writeStderr(`Visit:\n${url}`);
|
||||
return;
|
||||
}
|
||||
const browserName = getBrowserAppName(browser);
|
||||
const options = browserName
|
||||
? { wait: false, app: { name: browserName } }
|
||||
: { wait: false };
|
||||
const options = getBrowserOpenOptions({ browser, browserProfile });
|
||||
return open(url, options).catch(() => {
|
||||
writeStderr(`Visit:\n${url}`);
|
||||
});
|
||||
@@ -272,9 +321,11 @@ export async function login({
|
||||
useDeviceCode = false,
|
||||
noBrowser = false,
|
||||
browser,
|
||||
browserProfile,
|
||||
}) {
|
||||
if (!tenantId) throw new Error("tenantId is required");
|
||||
if (!clientId) throw new Error("clientId is required");
|
||||
validateBrowserOptions({ browser, browserProfile });
|
||||
|
||||
const resources = parseResources(resourcesCsv);
|
||||
const scopes = getScopesForResources(resources);
|
||||
@@ -312,10 +363,7 @@ export async function login({
|
||||
writeStderr(`Visit:\n${url}`);
|
||||
return;
|
||||
}
|
||||
const browserName = getBrowserAppName(browser);
|
||||
const options = browserName
|
||||
? { wait: false, app: { name: browserName } }
|
||||
: { wait: false };
|
||||
const options = getBrowserOpenOptions({ browser, browserProfile });
|
||||
return open(url, options).catch(() => {
|
||||
writeStderr(`Visit:\n${url}`);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user