UNPKG

@gitbeaker/cli

Version:

CLI implementation of the GitLab API.

219 lines (214 loc) 6.83 kB
#!/usr/bin/env node // src/cli.ts import Chalk from "chalk"; import Sywac from "sywac"; import * as Gitbeaker from "@gitbeaker/rest"; import API_MAP from "@gitbeaker/core/map.json" with { type: "json" }; // src/utils.ts import { camelize, decamelize, depascalize } from "xcase"; function param(value) { let cleaned = value; const exceptions = [ "GitLabCI", "YML", "GPG", "SSH", "IId", "NPM", "NuGet", "DORA4", "LDAP", "CICD", "SAML", "SCIM", "PyPI" ]; exceptions.filter((e) => value.includes(e)).forEach((ex) => { cleaned = cleaned.replace(ex, ex.charAt(0).toUpperCase() + ex.slice(1).toLowerCase()); }); const decamelized = decamelize(cleaned, "-"); return decamelized !== cleaned ? decamelized : depascalize(cleaned, "-"); } function normalizeEnviromentVariables(env) { const normalized = {}; const suffixes = [ "TOKEN", "OAUTH_TOKEN", "JOB_TOKEN", "HOST", "SUDO", "CAMELIZE", "REQUEST_TIMEOUT", "PROFILE_TOKEN", "PROFILE_MODE" ]; suffixes.forEach((s) => { if (env[`GITLAB_${s}`]) normalized[`GITBEAKER_${s}`] = env[`GITLAB_${s}`]; if (env[`GITBEAKER_${s}`]) normalized[`GITBEAKER_${s}`] = env[`GITBEAKER_${s}`]; }); return normalized; } function buildArgumentObjects(globalConfig, method, rawArgs) { const ignoreOptions = ["_", "$0", "v", "version", "h", "help", "g", "global-args"]; const coreArgs = {}; const optionalArgs = {}; const initArgs = {}; Object.entries(rawArgs).forEach(([argName, value]) => { if (ignoreOptions.includes(argName) || value == null) return; const camelCased = camelize(argName.replace("gb-", "").replace("gl-", ""), "-"); if (globalConfig[argName.replace("gl-", "gb-")]) { initArgs[camelCased] = value; } else if (method.args.includes(camelCased)) coreArgs[camelCased] = value; else optionalArgs[camelCased] = value; }); return { initArgs, coreArgs, optionalArgs }; } function getDisplayConfig(globalConfig) { const display = {}; Object.entries(globalConfig).forEach(([k, v]) => { if (v.defaultValue == null) return; display[k] = { alias: v.alias, description: v.desc, value: v.defaultValue }; }); return display; } function getGlobalConfig(env = process.env) { const normalEnv = normalizeEnviromentVariables(env); return { "gb-token": { alias: "gl-token", desc: "Your Gitlab Personal Token", type: "string", defaultValue: normalEnv.GITBEAKER_TOKEN }, "gb-oauth-token": { alias: "gl-oauth-token", desc: "Your Gitlab OAuth Token", type: "string", defaultValue: normalEnv.GITBEAKER_OAUTH_TOKEN }, "gb-job-token": { alias: "gl-job-token", desc: "Your Gitlab Job Token", type: "string", defaultValue: normalEnv.GITBEAKER_JOB_TOKEN }, "gb-host": { alias: "gl-host", desc: "Your Gitlab API host (Defaults to https://www.gitlab.com)", type: "string", defaultValue: normalEnv.GITBEAKER_HOST }, "gb-sudo": { alias: "gl-sudo", desc: "[Sudo](https://docs.gitlab.com/ee/api/#sudo) query parameter", type: "string", defaultValue: normalEnv.GITBEAKER_SUDO }, "gb-camelize": { alias: "gl-camelize", desc: "Camelizes all response body keys", type: "boolean", defaultValue: normalEnv.GITBEAKER_CAMELIZE }, "gb-request-timeout": { alias: "gl-request-timeout", desc: "Timeout for API requests. Measured in ms", type: "number", defaultValue: normalEnv.GITBEAKER_REQUEST_TIMEOUT && parseInt(normalEnv.GITBEAKER_REQUEST_TIMEOUT, 10) }, "gb-profile-token": { alias: "gl-profile-token", desc: "[Requests Profiles Token](https://docs.gitlab.com/ee/administration/monitoring/performance/request_profiling.html)", type: "string", defaultValue: normalEnv.GITBEAKER_PROFILE_TOKEN }, "gb-profile-mode": { alias: "gl-profile-mode", desc: "[Requests Profiles Token](https://docs.gitlab.com/ee/administration/monitoring/performance/request_profiling.html)", type: "string", defaultValue: normalEnv.GITBEAKER_PROFILE_MODE } }; } function getExposedAPIs(map) { const { Gitlab, AccessLevel, ...exposed } = map; return exposed; } // src/cli.ts function setupAPIMethods(setupArgs, methodArgs) { methodArgs.forEach((name) => { setupArgs.positional(`[--${param(name)}] <${param(name)}>`, { group: "Required Options", type: "string" }); }); return setupArgs; } function runAPIMethod(ctx, args, apiName, method) { const globalConfig = getGlobalConfig(); const { initArgs, coreArgs, optionalArgs } = buildArgumentObjects(globalConfig, method, args); const s = new Gitbeaker[apiName](initArgs); return s[method.name](...Object.values(coreArgs), optionalArgs).then((r) => { ctx.output = JSON.stringify(r, null, 3); }).catch((e) => { ctx.output = e; }); } function setupAPIs(setupArgs, apiName, methods) { const globalConfig = getGlobalConfig(); Object.entries(globalConfig).forEach(([k, v]) => { setupArgs.option(`${k} <value>`, { group: "Base Options", ...v }); }); for (let i = 1; i < methods.length; i += 1) { const method = methods[i]; setupArgs.command(param(method.name), { setup: (setupMethodArgs) => setupAPIMethods(setupMethodArgs, method.args), run: (args, ctx) => runAPIMethod(ctx, args, apiName, method) }); } return setupArgs; } var commandStyle = Chalk.hex("#e34329").bold; var groupStyle = Chalk.hex("#fca325").bold; var usageStyle = Chalk.hex("#fc6e26").bold; var optionStyle = Chalk.white.bold; var descriptionStyle = Chalk.hex("#848484"); var hintStyle = Chalk.hex("#6a5f88"); var cli = Sywac.version("-v, --version").help("-h, --help").showHelpByDefault().epilogue(`Copyright ${(/* @__PURE__ */ new Date()).getFullYear()}`).style({ usagePrefix: usageStyle, group: groupStyle, flags: optionStyle, usageCommandPlaceholder: commandStyle, usageOptionsPlaceholder: optionStyle, desc: descriptionStyle, hints: hintStyle }); cli.boolean("-g --global-args", { desc: "Show global arguments currently set in the environment variables" }); cli.command("*", (argv, ctx) => { if (!argv.g) return; const globalConfig = getGlobalConfig(); const display = getDisplayConfig(globalConfig); ctx.output = Object.keys(display).length === 0 ? "No global variables have been set!" : JSON.stringify(display, null, 3); }); var exposedAPIs = getExposedAPIs(API_MAP); Object.entries(exposedAPIs).forEach(([apiName, methods]) => { cli.command(param(apiName), { desc: `The ${apiName} API`, setup: (setupArgs) => setupAPIs(setupArgs, apiName, methods) }); }); // src/index.ts cli.parseAndExit();