UNPKG

@sasjs/cli

Version:

Command line interface for SASjs

432 lines (431 loc) 23.1 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getIsDefault = exports.getDefaultValues = exports.getCredentialsInputSas9 = exports.getCredentialsInputSasjs = exports.getCredentialsInputForViya = exports.getAndValidateSasjsFields = exports.getAndValidateSasViyaFields = exports.shouldAuthenticate = exports.getAndValidateSas9Fields = exports.getAndValidateServerUrl = exports.getCommonFields = void 0; var input_1 = require("@sasjs/utils/input"); var types_1 = require("@sasjs/utils/types"); var utils_1 = require("@sasjs/utils"); var path_1 = __importDefault(require("path")); var dotenv_1 = __importDefault(require("dotenv")); var targetScope_1 = require("../../../types/targetScope"); var utils_2 = require("../../../utils"); function getCommonFields() { var _a; return __awaiter(this, void 0, void 0, function () { var scope, serverType, name, _b, existingTarget, retry, appLoc, serverUrl; return __generator(this, function (_c) { switch (_c.label) { case 0: return [4 /*yield*/, getAndValidateScope()]; case 1: scope = _c.sent(); return [4 /*yield*/, getAndValidateServerType()]; case 2: serverType = _c.sent(); return [4 /*yield*/, getAndValidateTargetName(serverType)]; case 3: name = _c.sent(); return [4 /*yield*/, getAndValidateUpdateExisting(scope, name)]; case 4: _b = _c.sent(), existingTarget = _b.targetJson, retry = _b.retry; if (!retry) return [3 /*break*/, 6]; return [4 /*yield*/, getCommonFields()]; case 5: return [2 /*return*/, _c.sent()]; case 6: if (existingTarget) { (_a = process.logger) === null || _a === void 0 ? void 0 : _a.info("Updating current target '".concat(name, "'")); } return [4 /*yield*/, getAndValidateAppLoc(name, existingTarget)]; case 7: appLoc = _c.sent(); return [4 /*yield*/, getAndValidateServerUrl(existingTarget)]; case 8: serverUrl = _c.sent(); return [2 /*return*/, { scope: scope, serverType: serverType, name: name, appLoc: appLoc, serverUrl: serverUrl, existingTarget: existingTarget }]; } }); }); } exports.getCommonFields = getCommonFields; function getAndValidateScope() { return __awaiter(this, void 0, void 0, function () { var errorMessage, scope; return __generator(this, function (_a) { switch (_a.label) { case 0: errorMessage = 'Target scope must be either 1 or 2.'; return [4 /*yield*/, (0, input_1.getChoice)('Please pick a scope for the new target: ', 'Please choose either option 1 or 2.', [ { title: '1. Local project config file', value: 1 }, { title: '2. Global config file', value: 2 } ]).catch(function () { throw new Error(errorMessage); })]; case 1: scope = _a.sent(); if (!scope) { throw new Error(errorMessage); } return [2 /*return*/, scope === 1 ? targetScope_1.TargetScope.Local : targetScope_1.TargetScope.Global]; } }); }); } function getAndValidateServerType() { return __awaiter(this, void 0, void 0, function () { var serverType; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, (0, input_1.getChoice)('Please pick a server type: ', 'Please choose either option 1 or 2.', [ { title: '1. SAS Viya', value: 1 }, { title: '2. SAS 9', value: 2 }, { title: '3. SAS JS', value: 3 } ])]; case 1: serverType = _a.sent(); switch (serverType) { case 1: return [2 /*return*/, types_1.ServerType.SasViya]; case 2: return [2 /*return*/, types_1.ServerType.Sas9]; default: return [2 /*return*/, types_1.ServerType.Sasjs]; } return [2 /*return*/]; } }); }); } function getAndValidateServerUrl(target) { return __awaiter(this, void 0, void 0, function () { var serverUrl; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, (0, input_1.getUrl)('Please enter a target server URL (including port, if relevant): ', 'Server URL is required.', target === null || target === void 0 ? void 0 : target.serverUrl)]; case 1: serverUrl = _a.sent(); return [2 /*return*/, serverUrl.replace(/\/$/, '')]; } }); }); } exports.getAndValidateServerUrl = getAndValidateServerUrl; function getAndValidateTargetName(serverType) { return __awaiter(this, void 0, void 0, function () { var validator, defaultName, targetName; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: validator = function (value) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { if (!value) { return [2 /*return*/, 'Target name is required.']; } if (value.trim().includes(' ')) { return [2 /*return*/, 'Target names cannot include spaces. Please try again with a valid target name.']; } if (!/^[a-z0-9]+$/i.test(value)) return [2 /*return*/, 'Target names can only contain alphanumeric characters. Please try again with a valid target name.']; return [2 /*return*/, true]; }); }); }; defaultName = serverType === types_1.ServerType.SasViya ? 'viya' : serverType === types_1.ServerType.Sas9 ? 'sas9' : 'server'; return [4 /*yield*/, (0, input_1.getString)('Please enter a target name: ', validator, defaultName)]; case 1: targetName = _a.sent(); return [2 /*return*/, targetName]; } }); }); } function getAndValidateUpdateExisting(targetScope, targetName) { var _a; return __awaiter(this, void 0, void 0, function () { var targetJson, errorMessage_1, choice; return __generator(this, function (_b) { switch (_b.label) { case 0: return [4 /*yield*/, (0, utils_2.findTargetInConfiguration)(targetName, targetScope) .then(function (res) { return res.target.toJson(false); }) .catch(function (_) { return undefined; })]; case 1: targetJson = _b.sent(); if (!targetJson) return [3 /*break*/, 3]; (_a = process.logger) === null || _a === void 0 ? void 0 : _a.info("Found target with same name: '".concat(targetName, "'")); errorMessage_1 = 'Target update choice must be either 1 or 2.'; return [4 /*yield*/, (0, input_1.getChoice)('Please pick an option for the current target: ', 'Please choose either option 1 or 2.', [ { title: '1. Update this target', value: 1 }, { title: '2. Go back and create a new target', value: 2 } ]).catch(function () { throw new Error(errorMessage_1); })]; case 2: choice = _b.sent(); if (!choice) { throw new Error(errorMessage_1); } return [2 /*return*/, { targetJson: targetJson, retry: choice === 2 }]; case 3: return [2 /*return*/, { targetJson: targetJson, retry: false }]; } }); }); } function getAndValidateSas9Fields(target, scope) { return __awaiter(this, void 0, void 0, function () { var serverName, repositoryName, _a, userName, password; return __generator(this, function (_b) { switch (_b.label) { case 0: return [4 /*yield*/, (0, input_1.getString)('Please enter a server name (default is SASApp): ', function (v) { return !!v || 'Server name is required.'; }, 'SASApp')]; case 1: serverName = _b.sent(); return [4 /*yield*/, (0, input_1.getString)('Please enter a repository name (default is Foundation): ', function (v) { return !!v || 'Repository name is required.'; }, 'Foundation')]; case 2: repositoryName = _b.sent(); return [4 /*yield*/, (0, exports.getCredentialsInputSas9)(target, scope)]; case 3: _a = _b.sent(), userName = _a.userName, password = _a.password; return [2 /*return*/, { serverName: serverName, repositoryName: repositoryName, userName: userName, password: password }]; } }); }); } exports.getAndValidateSas9Fields = getAndValidateSas9Fields; var shouldAuthenticate = function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, (0, input_1.getConfirmation)('Would you like to authenticate against this target?', true)]; }); }); }; exports.shouldAuthenticate = shouldAuthenticate; function getAndValidateSasViyaFields(target, scope, serverUrl, insecure, authenticateCallback) { return __awaiter(this, void 0, void 0, function () { var contextName, httpsAgentOptions, sasjs, contexts, contextNumberErrorMessage, contextNumber; return __generator(this, function (_a) { switch (_a.label) { case 0: contextName = 'SAS Job Execution compute context'; return [4 /*yield*/, (0, exports.shouldAuthenticate)()]; case 1: if (!_a.sent()) return [3 /*break*/, 8]; return [4 /*yield*/, authenticateCallback(target, insecure, scope)]; case 2: target = _a.sent(); httpsAgentOptions = insecure ? __assign(__assign({}, target.httpsAgentOptions), { allowInsecureRequests: true, rejectUnauthorized: false }) : target.httpsAgentOptions; sasjs = (0, utils_2.getSASjs)(target); contexts = []; if (!(scope === targetScope_1.TargetScope.Local)) return [3 /*break*/, 4]; dotenv_1.default.config({ path: path_1.default.join(process.projectDir, ".env.".concat(target.name)) }); return [4 /*yield*/, sasjs.getComputeContexts(process.env.ACCESS_TOKEN)]; case 3: contexts = _a.sent(); return [3 /*break*/, 6]; case 4: if (!target.authConfig || !target.authConfig.access_token) { throw new Error("No access token available for target ".concat(target.name, ". Please run `sasjs add cred -t ").concat(target.name, "` to authenticate.")); } return [4 /*yield*/, sasjs.getComputeContexts(target.authConfig.access_token)]; case 5: contexts = _a.sent(); _a.label = 6; case 6: contextNumberErrorMessage = "Context number must be between 1 and ".concat(contexts.length); return [4 /*yield*/, (0, input_1.getChoice)('Please pick your SAS Viya execution context: ', contextNumberErrorMessage, contexts.map(function (c, i) { return ({ title: c.name, value: i }); }))]; case 7: contextNumber = _a.sent(); contextName = contexts[contextNumber].name; return [2 /*return*/, { contextName: contextName, target: target }]; case 8: return [2 /*return*/, { contextName: contextName, target: target }]; } }); }); } exports.getAndValidateSasViyaFields = getAndValidateSasViyaFields; function getAndValidateSasjsFields(target, scope, insecure, authenticateCallback) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, (0, exports.shouldAuthenticate)()]; case 1: if (!_a.sent()) return [3 /*break*/, 3]; return [4 /*yield*/, authenticateCallback(target, insecure, scope)]; case 2: target = _a.sent(); _a.label = 3; case 3: return [2 /*return*/, { target: target }]; } }); }); } exports.getAndValidateSasjsFields = getAndValidateSasjsFields; function getAndValidateAppLoc(targetName, target) { var _a; return __awaiter(this, void 0, void 0, function () { var errorMessage, appLoc; return __generator(this, function (_b) { switch (_b.label) { case 0: errorMessage = 'App location is required.'; return [4 /*yield*/, (0, input_1.getString)('Please provide an app location: ', function (v) { return !!v || errorMessage; }, (_a = target === null || target === void 0 ? void 0 : target.appLoc) !== null && _a !== void 0 ? _a : "/Public/app/".concat(targetName))]; case 1: appLoc = _b.sent(); return [2 /*return*/, appLoc]; } }); }); } var getCredentialsInputForViya = function (targetName) { return __awaiter(void 0, void 0, void 0, function () { var defaultValues, client, secret; return __generator(this, function (_a) { switch (_a.label) { case 0: defaultValues = (0, exports.getDefaultValues)(targetName); return [4 /*yield*/, (0, input_1.getString)('Please enter your Client ID: ', function (v) { return !!v || 'Client ID is required.'; }, defaultValues.client)]; case 1: client = _a.sent(); return [4 /*yield*/, (0, input_1.getString)('Please enter your Client Secret: ', function (v) { return !!v || 'Client Secret is required.'; }, defaultValues.secret)]; case 2: secret = _a.sent(); return [2 /*return*/, { client: client, secret: secret }]; } }); }); }; exports.getCredentialsInputForViya = getCredentialsInputForViya; var getCredentialsInputSasjs = function (target) { return __awaiter(void 0, void 0, void 0, function () { var client; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, (0, input_1.getString)('Please enter your Client ID: ', function (v) { return !!v || 'Client ID is required.'; }, (0, exports.getDefaultValues)(target.name, types_1.ServerType.Sasjs).client)]; case 1: client = _a.sent(); return [2 /*return*/, { client: client }]; } }); }); }; exports.getCredentialsInputSasjs = getCredentialsInputSasjs; var getCredentialsInputSas9 = function (target, scope) { return __awaiter(void 0, void 0, void 0, function () { var targetName, name, result, userName, password; var _a, _b, _c, _d; return __generator(this, function (_e) { switch (_e.label) { case 0: targetName = target.name; name = ''; if (scope === targetScope_1.TargetScope.Local) { result = dotenv_1.default.config({ path: path_1.default.join(process.projectDir, ".env.".concat(targetName)) }); if (result.error) { process.logger.info("A .env.".concat(targetName, " file does not exist. It will be created.")); } else { name = process.env.SAS_USERNAME; } } else { name = (_b = (_a = target.authConfigSas9) === null || _a === void 0 ? void 0 : _a.userName) !== null && _b !== void 0 ? _b : ''; } return [4 /*yield*/, (0, input_1.getString)('Please enter your SAS username', function (v) { return !!v || 'username is required.'; }, name)]; case 1: userName = _e.sent(); return [4 /*yield*/, (0, input_1.getString)('Please enter your SAS password', function (v) { return !!v || 'password is required.'; })]; case 2: password = _e.sent(); if (!/{sas00/i.test(password)) { (_c = process.logger) === null || _c === void 0 ? void 0 : _c.warn('Cleartext passwords pose a security risk. Please consider SAS encoded passwords. For this a server config change is required (AllowEncodedPassword). More info here: https://support.sas.com/kb/36/831.html'); } else if (!/^({sas00)[3-9]/i.test(password)) { (_d = process.logger) === null || _d === void 0 ? void 0 : _d.warn('This password type can be easily decrypted. Please consider {sas003} or above.'); } password = (0, utils_1.encodeToBase64)(password); return [2 /*return*/, { userName: userName, password: password }]; } }); }); }; exports.getCredentialsInputSas9 = getCredentialsInputSas9; var getDefaultValues = function (targetName, serverType) { dotenv_1.default.config({ path: path_1.default.join(process.projectDir, ".env.".concat(targetName)) }); var defaultClient = process.env.CLIENT === 'undefined' || process.env.CLIENT === 'null' || !process.env.CLIENT ? '' : process.env.CLIENT; var defaultSecret = process.env.SECRET === 'undefined' || process.env.SECRET === 'null' || !process.env.SECRET ? '' : process.env.SECRET; if (serverType === types_1.ServerType.Sasjs && defaultClient === '') defaultClient = 'clientID1'; return { client: defaultClient, secret: defaultSecret }; }; exports.getDefaultValues = getDefaultValues; var getIsDefault = function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, (0, input_1.getConfirmation)('Would you like to set this as your default target?', false)]; case 1: return [2 /*return*/, _a.sent()]; } }); }); }; exports.getIsDefault = getIsDefault;