@sasjs/cli
Version:
Command line interface for SASjs
399 lines (398 loc) • 29.5 kB
JavaScript
;
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.printHelpText = void 0;
var chalk_1 = __importDefault(require("chalk"));
function printHelpText() {
return __awaiter(this, void 0, void 0, function () {
var commands, aliases, outputCommands, outputAliases;
return __generator(this, function (_a) {
commands = [
{
name: 'init',
title: 'init',
description: [
"Creates the 'sasjs' folder and doxy subfolder (with content files + configuration) for docs",
"- Inserted in the current working directory.",
"- If an existing NPM project, package.json is updated with the @sasjs/core dependency."
]
},
{
name: 'create',
title: 'create <foldername>.',
description: [
"Creates the folder structure specified in config.json, inside the provided parent folder e.g. ".concat(chalk_1.default.cyanBright('sasjs create my-sas-project'), "."),
"- if no foldername is specified, it creates the folder structure in the current working directory.",
"- If this is an existing NPM project, it will update package.json with the @sasjs/core dependency.",
"- An additional option can be specified to create a web app from a template. This supports creation of Angular, React and minimal web apps. There is also a sasonly option. e.g. ".concat(chalk_1.default.cyanBright('sasjs create my-sas-project --template react'), " and ").concat(chalk_1.default.cyanBright('sasjs create my-sas-project -t angular'))
],
syntax: "creates the folder structure specified in config.json, inside the provided parent folder\n e.g. sasjs create my-sas-project\n - if no foldername is specified, it creates the folder structure in the current working directory.\n - If this is an existing NPM project, it will update package.json with the @sasjs/core dependency.\n - An additional option can be specified to create a web app from a template.\n This supports creation of Angular, React and minimal web apps. There are also sasonly and jobs options.\n e.g. ".concat(chalk_1.default.cyanBright('sasjs create my-sas-project --template react'), "\n ").concat(chalk_1.default.cyanBright('sasjs create my-sas-project -t angular'))
},
{
name: 'version',
title: 'version',
description: ["displays currently installed version."]
},
{
name: 'help',
title: 'help',
description: ["displays this help text."]
},
{
name: 'web',
title: 'web <targetName>',
description: [
"compiles the web app service and place at ".concat(chalk_1.default.cyanBright('webSourcePath'), ".")
]
},
{
name: 'db',
title: 'db <targetName>',
description: [
"compiles the dbfiles specified in the ".concat(chalk_1.default.cyanBright('db'), " folder.")
]
},
{
name: 'compile',
title: 'compile <targetName>',
description: [
"compiles the services specified in the ".concat(chalk_1.default.cyanBright('serviceFolders'), " property of the 'serviceConfig' in your target and common configuration.")
]
},
{
name: 'build',
title: 'build <targetName>',
description: [
"Prepares a single deployment script (SAS9 or Viya program) per configuration",
"in sasjsconfig.json.",
"First Build (macro) variables are inserted, then all of the buildinit / buildterm dependencies,then the buildinit (a good place to source the Viya app tokens), then all of the compiled services are added, and finally the buildterm script (where you might perform additional deployment actions such as database build).",
"This SAS file could be executed as part of a web service (executed by the Deploy command) or simply copy pasted into Enterprise Guide or SAS Studio.",
"It will also perform ".concat(chalk_1.default.greenBright('compile'), " command if services are not compiled.")
]
},
{
name: 'compilebuild',
title: 'compilebuild <targetName>',
description: [
"compiles the services specified in the ".concat(chalk_1.default.cyanBright('serviceFolders'), "in the 'serviceConfig' in your target and common configurations."),
"It will also perform ".concat(chalk_1.default.greenBright('build'), " command.")
]
},
{
name: 'deploy',
title: 'deploy <targetName>',
description: [
"triggers a shell command as specified in the ".concat(chalk_1.default.cyanBright('deployScripts'), " property in your target's 'deployConfig' and the common 'deployConfig')."),
"This command would perform tasks such as executing the deployment script, exporting the SPK, triggering tests etc.",
"The ".concat(chalk_1.default.cyanBright('deployScripts'), " specified in each target's 'deployConfig' can include an array of scripts."),
"Each script can be a SAS file or a shell script.",
"If it is a shell script, it is executed locally and the output is displayed on the command line.",
"If it is a SAS file, it is sent to the SAS server for execution.",
"To facilitate this, some configuration needs to be provided.",
"This configuration is different for SAS VIYA and SAS9 servers:",
"For SAS VIYA servers, the following items are required:",
"[2spaces]* ".concat(chalk_1.default.cyanBright('ACCESS_TOKEN'), " - An access token for performing operations with the SAS VIYA API."),
"If the target has been specified in your project's local sasjsconfig.json file, this token needs to be present in a '.env' file corresponding to your target's name.",
"So if your target was called 'viya-test', your '.env' file must be called '.env.viya-test'.",
"You can automatically generate an access token and add it to the correct .env file using the sasjs add or sasjs add cred commands.",
"[2spaces]* ".concat(chalk_1.default.cyanBright('contextName'), " - The name of the compute context that must be used to execute SAS code, e.g. \"SharedCompute\". This needs to be specified as part of the target JSON as the 'contextName' property."),
"For SAS9 servers, the following items are required to be specified in the target JSON:",
"[2spaces]* ".concat(chalk_1.default.cyanBright('serverName'), " - The name of the server where SAS code will be executed, e.g. \"SASApp\"."),
"[2spaces]* ".concat(chalk_1.default.cyanBright('repositoryName'), " - The metadata repository, e.g. \"Foundation\"."),
"In addition the following variables must be set:",
"[2spaces]* ".concat(chalk_1.default.cyanBright('serverUrl'), " - The full path to the server (eg https://yourserver)"),
"[2spaces]* ".concat(chalk_1.default.cyanBright('serverType'), " - Eg SAS9 or SASVIYA"),
"NOTE: By default deploy will overwrite an existing deploy (force deploy)."
]
},
{
name: 'compilebuilddeploy',
title: 'compilebuilddeploy <targetName>',
description: [
"executes script file specified in the ".concat(chalk_1.default.cyanBright('deployScripts'), " property in the target and common 'deployConfig'"),
"It will also perform ".concat(chalk_1.default.greenBright('compilebuild'), " command."),
"",
"NOTE: If no target name is specified/matched, it will build the first target present in config.json.",
"NOTE: By default deploy will overwrite an existing deploy (force deploy)."
]
},
{
name: 'servicepack',
title: 'servicepack <targetName>',
description: [
"performs operations on Service Packs (collections of jobs & folders).",
"* ".concat(chalk_1.default.cyanBright('deploy'), " - deploys service pack from json file."),
"[2spaces]command example: sasjs servicepack deploy --source ./path/services.json --target targetName",
"",
"[4spaces]You can force deploy (overwrite an existing deploy) by passing the (-f) flag.",
"[4spaces]Default target name will be used if target name was omitted.",
"",
"NOTE: The sasjs servicepack operation is only supported for SAS Viya build targets.",
"More information available in the online documentation: ".concat(chalk_1.default.cyanBright('https://sasjs.io/sasjs-cli-servicepack'))
]
},
{
name: 'context',
title: 'context <targetName>',
description: [
"performs operations on contexts.",
"* ".concat(chalk_1.default.cyanBright('create'), " - creates new context."),
"[2spaces]command example: sasjs context create --source ../contextConfig.json --target targetName",
"* ".concat(chalk_1.default.cyanBright('edit'), " - edits existing context."),
"[2spaces]command example: sasjs context edit contextName --source ../contextConfig.json --target targetName",
"* ".concat(chalk_1.default.cyanBright('delete'), " - deletes existing context."),
"[2spaces]command example: sasjs context delete contextName --target targetName",
"* ".concat(chalk_1.default.cyanBright('list'), " - lists all accessible and inaccessible contexts."),
"[2spaces]command example: sasjs context list --target targetName",
"* ".concat(chalk_1.default.cyanBright('export'), " - exports context to contextName.json in the current folder."),
"[2spaces]command example: sasjs context export contextName --target targetName",
"[2spaces]exported context example:\n [4spaces]{\n [4spaces]\"createdBy\": \"admin\",\n [4spaces]\"links\": [...],\n [4spaces]\"id\": \"id...\",\n [4spaces]\"version\": 2,\n [4spaces]\"name\": \"Compute Context\"\n [4spaces]}",
"",
"NOTE: The sasjs context operation is only supported for SAS Viya build targets. More information available in the online documentation: ".concat(chalk_1.default.cyanBright('https://sasjs.io/sasjs-cli-context'))
]
},
{
name: 'add',
title: 'add',
description: [
"lets the user add a build target to either the local project configuration, or to the global .sasjsrc file.",
"",
"NOTE: This command requires the user to input all the required parameters. More information available in the online documentation: ".concat(chalk_1.default.cyanBright('https://sasjs.io/sasjs-cli-add'))
]
},
{
name: 'auth',
title: 'auth',
description: [
"lets the user add credentials for target to either the local project configuration, or to the global .sasjsrc file.",
"",
"NOTE: This command requires the user to input all the required parameters. More information available in the online documentation: ".concat(chalk_1.default.cyanBright('https://cli.sasjs.io/auth/'))
]
},
{
name: 'run',
title: 'run <sasFilePath> -t <targetName> --source /local/run.json -l <log/file/path> --compile',
description: [
"lets the user run a given SAS file against a specified target.",
"The target can exist either in the local project configuration or in the global .sasjsrc file.",
"Providing log flag (--log or -l) is optional. If not present, the log is stored locally with a timestamp. If present, CLI will fetch and save the log to the specified location. If a relative location, it will be relative to the directory in which the command is invoked.",
"Providing source flag (--source or -s) is optional. It should point to a JSON file with the following structure: {\"macroVars\": {\"var1\": \"val1\", \"var2\": \"val2\"}}. These will be parsed into SAS \"%let\" statements and pre-append to the SAS code being run.",
"Providing compile flag (--compile or -c) is optional. It is used to compile the program prior to execution. Useful for including dependent macros and includes. More info here: https://cli.sasjs.io/compile"
]
},
{
name: 'request',
title: 'request <sasProgramPath> -d <path/to/datafile> -c <path/to/configfile> -t <targetName> -l <path/to/log> -o <path/to/output>',
description: [
"lets",
"the user run a SAS job against a specified target.",
"The target can exist either in the local project configuration or in the global .sasjsrc file.",
"<sasProgramPath> - if this has a leading slash (eg /Public/app/folder/servicename) then it must be the full path. If it is a relative path (eg path/servicename) then it will be pre-pended with the appLoc - which must then be defined in the sasjs config.",
"<path/to/log> - Location in which to store the log file. If not provided AND current directory is a sasjs project, it will be saved in sasjsresults else in the current directory",
"<path/to/output> - Location to store the output file. If not provided AND current directory is a sasjs project, an output file will be saved in the sasjsresults folder else in current directory."
]
},
{
name: 'folder',
title: 'folder <command>',
description: [
"performs operations on folders.",
"* ".concat(chalk_1.default.cyanBright('create'), " - creates new folder."),
"[2spaces]command example: sasjs folder create /Public/folder -t targetName -f",
"",
"[2spaces]NOTE: Providing force flag (-f or --force) is optional. If provided and target folder already exists, its content and all subfolders will be deleted.",
"",
"* ".concat(chalk_1.default.cyanBright('delete'), " - deletes folder."),
"[2spaces]command example: sasjs folder delete /Public/folder --target targetName",
"",
"* ".concat(chalk_1.default.cyanBright('move'), " - moves folder to a new location"),
"[2spaces]command example: sasjs folder move /Public/sourceFolder /Public/targetFolder --target targetName"
]
},
{
name: 'fs',
title: 'fs <command>',
description: [
"Handles operations around file system synchronisation.",
"* ".concat(chalk_1.default.cyanBright('sync'), " - Synchronise the remote SAS file system with the local project folder according to the target 'syncDirectories' array."),
"[2spaces]command example: sasjs fs sync /Public/localFolder /Public/remoteFolder",
"",
"* ".concat(chalk_1.default.cyanBright('compile'), " - Compiles a SAS program with the contents of a local directory."),
"[2spaces]command example: sasjs fs compile /Public/folder --output ./outputProgram",
"",
"[2spaces]NOTE: If output flag (-o or --output) is not provided, output will be stored in './fs-compile/{timestamp}' directory relative to working directory."
]
},
{
name: 'job',
title: 'job <command>',
description: [
"performs operations on jobs.",
"[2spaces]* ".concat(chalk_1.default.cyanBright('execute'), " - triggers job for execution."),
"[2spaces]command example: sasjs job execute /Public/job -t targetName --output ./outputFolder/output.json --ignoreWarnings --verbose",
"[2spaces]command example: sasjs job execute /Public/job -t targetName --wait --log ./logFolder/log.json -i -v",
"",
"[2spaces]NOTE: Providing wait flag (--wait or -w) is optional. If present, CLI will wait for job completion.",
"[2spaces]NOTE: Providing output flag (--output or -o) is optional. If present, CLI will immediately print out the response JSON. If value is provided, it will be treated as file path to save the response JSON.",
"[2spaces]NOTE: Providing log flag (--log or -l) is optional. If present, CLI will fetch and save job log to local file.",
"[2spaces]NOTE: Providing ignore warnings (--ignoreWarnings or -i) flag is optional. If present, CLI will return status '0', when the job state is warning.",
"[2spaces]NOTE: Providing verbose (--verbose or -v) flag is optional. If present, CLI will log summary of every HTTP response. If set to 'bleached', CLI will log summary of every HTTP response without extra colors."
]
},
{
name: 'flow',
title: 'flow <command>',
description: [
"Performs operations on flows of jobs.",
"[2spaces]* ".concat(chalk_1.default.cyanBright('execute'), " - triggers flow for execution."),
"[2spaces]command example: sasjs flow execute --source /local/flow.json --logFolder /local/log/folder --csvFile /local/some.csv"
]
},
{
name: 'doc',
title: 'doc <command>',
description: [
"Generates docs for SAS Programs / Macros / Jobs / Services listed in the sasjsconfig.json file by default and supplied Target. If target is not provided, it will pick first target present in config.json",
"[2spaces]command example: sasjs doc -t <targetName> --outDirectory <sasFilePath>",
"",
"[2spaces]* ".concat(chalk_1.default.cyanBright('lineage'), " - Generates dot files for all Jobs / Services listed in the sasjsconfig.json file by default and supplied Target."),
"[2spaces]command example: sasjs doc lineage -t <targetName> --outDirectory <sasFilePath>",
"",
"[2spaces]NOTE: Providing outDirectory flag is optional. If not present, CLI will generate docs in the sasjsbuild/docs directory.",
"The target can exist either in the local project configuration or in the global .sasjsrc file.",
"",
"[2spaces]* ".concat(chalk_1.default.cyanBright('init'), " - Initialize/reset doxy folder (having content files + configuration) for docs"),
"[2spaces]command example: sasjs doc init"
]
},
{
name: 'lint',
title: 'lint',
description: [
"Provides the capability to identify, for SAS file, whether there are any ERRORs or WARNINGs present and if so, which line number they are on."
]
},
{
name: 'test',
title: 'test',
description: [
"Triggers SAS unit tests.",
"[2spaces]command example: sasjs test <filteringString> --source <testFlowPath> --outDirectory <folderPath> -t <targetName> --force",
"",
"[2spaces]NOTE: Providing <filteringString> is optional. If not present, all tests mentioned in test flow file will be executed.",
"[2spaces]NOTE: Providing source flag is optional. If not present, CLI will use test flow located at sasjsbuild/testFlow.json.",
"[2spaces]NOTE: Providing outDirectory flag is optional. If not present, CLI will use save outputs into sasjsresults folder.",
"[2spaces]NOTE: Providing force (--force or -f) flag is optional. If present, CLI will force command to finish running all tests and will not return an error code even when some are failing. Useful when the requirement is not to make CI Pipeline fail."
]
},
{
name: 'snippets',
title: 'snippets',
description: [
"Generates VS Code snippets from the Doxygen headers in the SAS Macros.",
"[2spaces]command example: sasjs snippets --outDirectory <folderPath> --target <targetName>",
"",
"[2spaces]NOTE: Providing <folderPath> is optional. If not present, generated snippets will be saved to 'sasjsresults/sasjs-macro-snippets.json' file.",
"[2spaces]NOTE: more information can be found here https://cli.sasjs.io/snippets/."
]
}
];
aliases = [
{ name: 'add', aliases: ['auth'] },
{ name: 'build', aliases: ['b'] },
{ name: 'compile', aliases: ['c'] },
{ name: 'compilebuild', aliases: ['cb'] },
{ name: 'compilebuilddeploy', aliases: ['cbd'] },
{ name: 'db', aliases: ['DB', 'build-DB', 'build-db'] },
{ name: 'deploy', aliases: ['d'] },
{ name: 'doc', aliases: ['docs'] },
{ name: 'help', aliases: ['h'] },
{ name: 'request', aliases: ['rq'] },
{ name: 'run', aliases: ['r'] },
{ name: 'version', aliases: ['v'] },
{ name: 'web', aliases: ['w'] }
];
outputCommands = "".concat(commands
.sort(function (a, b) { return (a.name < b.name ? -1 : 1); })
.map(function (command) {
return "* ".concat(chalk_1.default.greenBright(limitLineLength(command.title)), " - ").concat(command.description
.map(function (line) { return limitLineLength(line); })
.join("\n\t"));
}).join("\n "));
outputAliases = "".concat(aliases
.sort(function (a, b) { return (a.name < b.name ? -1 : 1); })
.map(function (alias) {
return "* ".concat(chalk_1.default.greenBright(alias.name), " : ").concat(alias.aliases
.sort(function (a, b) { return (a > b ? -1 : 1); })
.join(', '));
}).join("\n "));
console.log("\n ".concat(chalk_1.default.yellow.bold('Welcome to the Command Line Interface for SASjs!'), "\n\n ").concat(chalk_1.default.cyan('Here are the commands currently available:'), "\n ").concat(outputCommands, "\n\n\n ").concat(limitLineLength('GENERAL NOTE: Providing target name (--target targetName or -t targetName) is optional. [6spaces]Default target name will be used if target name was omitted.'), "\n\n ").concat(chalk_1.default.cyan('Alias commands:'), "\n ").concat(outputAliases, "\n "));
return [2 /*return*/, { outputCommands: outputCommands, outputAliases: outputAliases }];
});
});
}
exports.printHelpText = printHelpText;
var limitLineLength = function (str, maxLength) {
var _a;
if (maxLength === void 0) { maxLength = 80; }
var words = str.split(' ');
var lines = [];
var line = '';
while (words.length) {
while (line.length <= maxLength && words.length) {
var word = words.shift();
if (!word) {
return;
}
var spaces = void 0;
if ((_a = word.match(/\[\dspaces\]/)) === null || _a === void 0 ? void 0 : _a.length) {
spaces = word.match(/\[\dspaces\]/)[0].match(/\d/)[0];
}
word = spaces
? ' '.repeat(spaces.length) + word.split("[".concat(spaces, "spaces]")).join('')
: word;
line += line.length ? ' ' + word : word;
}
lines.push(line);
line = '';
}
return lines.join("\n\t ");
};