From 94e2e83e73498479fe1164140df9b7b764bebb26 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Wed, 6 May 2020 11:18:38 +0100 Subject: [PATCH] ADF CLI fixes (#5674) * safety checks and better path eval * do not execute command on help * rewrite 'update-version' command --- lib/cli/README.md | 62 ++++++--- lib/cli/bin/adf-cli | 20 ++- lib/cli/package-lock.json | 49 ++++++- lib/cli/package.json | 10 +- lib/cli/scripts/artifact-from-s3.ts | 1 + lib/cli/scripts/artifact-to-s3.ts | 1 + lib/cli/scripts/docker-publish.ts | 1 + lib/cli/scripts/init-aae-env.ts | 1 + lib/cli/scripts/kubectl-clean-app.ts | 1 + lib/cli/scripts/kubectl-delete.ts | 1 + lib/cli/scripts/kubectl-image.ts | 1 + lib/cli/scripts/npm-publish.ts | 1 + lib/cli/scripts/update-commit-sha.ts | 1 + lib/cli/scripts/update-version.ts | 183 +++++++++++---------------- 14 files changed, 195 insertions(+), 138 deletions(-) diff --git a/lib/cli/README.md b/lib/cli/README.md index bc228e089e..7763e8a44a 100644 --- a/lib/cli/README.md +++ b/lib/cli/README.md @@ -1,24 +1,47 @@ # Alfresco ADF Cli - -## The Goal of ADF CLI - -The ADF CLI manages, builds , doc and test your ADF Application projects. - +The ADF CLI provides a set of utilities to manage your ADF projects. ## Installation + To get started follow these instructions: -`` +```bash npm install @alfresco/adf-cli -g -`` +``` -To know more about any command use the -h or --help option +To know more about any command use the -h or --help option: + +```bash +adf-cli --help +``` + +## Developing + +Link the project as a global tool + +```bash +npm link +``` + +Build the tool in the **develop** mode (automatically watches for changes and rebuilds the commands): + +```bash +npm run develop +``` + +Run the tool with the `DEVELOP` environment variable: + +```bash +DEVELOP=true adf-cli +``` + +In develop mode, the CLI takes the prebuilt scripts from the dist folder. ## Commands -|**Commands** |**Description** | -|--- |--- | +| **Commands** |**Description** | +|--- |--- | |artifact-from-s3 |Get artifact from S3 | |artifact-to-s3 |Get artifact to S3 | |docker-publish |publish docker image| @@ -26,26 +49,26 @@ To know more about any command use the -h or --help option |kubectl-delete |delete kubectl | |kubectl-image |This command allows you to update a specific service on the rancher env with a specifig tag | |npm-publish | publish on npm | -| update-commit-sha | his command allows you to update the commit sha as part of the package.json. Your package.json must to have an existing property called "commit" | +| update-commit-sha | his command allows you to update the commit sha as part of the `package.json`. Your `package.json` must to have an existing property called "commit" | |update-version |This command allows you to update the adf dependencies and js-api with different versions Update adf libs and js-api with latest alpha| |adf-license |Create a 3th party license file | |adf-audit |Check the security risk dependency in your package.json | - ## Examples ### License Check -Move in the folder where you have your package.json and run the command: +Move in the folder where you have your `package.json` and run the command: ```bash npm install adf-license ``` + ### Audit Check -Move in the folder where you have your package.json and run the command: +Move in the folder where you have your `package.json` and run the command: ```bash npm install @@ -55,7 +78,7 @@ adf-audit ### Docker publish -Move in the folder where you have your Dockerfile and run the command: +Move in the folder where you have your `Dockerfile` and run the command: ```bash adf-cli docker-publish --dockerRepo "${docker_repository}" --dockerTags "${TAGS}" --pathProject "$(pwd)" @@ -68,7 +91,7 @@ If you want to specify a different docker registry you can run ### Kubectl update pod image -This command allows you to update a specific service on the rancher env with a specifig tag +This command allows you to update a specific service on the rancher env with a specific tag ```bash adf-cli kubectl-image --clusterEnv ${clusterEnv} --clusterUrl ${clusterUrl} --username ${username} --token ${token} --deployName ${deployName} --dockerRepo ${dockerRepo} --tag ${tag} @@ -118,8 +141,8 @@ adf-cli update-version --alpha --pathPackage "$(pwd)" --skipGnu ### Update commit sha -This command allows you to update the commit sha as part of the package.json. -Your package.json must to have an existing property called "commit" +This command allows you to update the commit sha as part of the `package.json`. +Your `package.json` must to have an existing property called "commit" ```bash adf-cli update-commit-sha --pathProject "$(pwd)" @@ -145,7 +168,8 @@ adf-cli init-aae-env --host "gateway_env" --oauth "identity_env" --identityHost ``` If you want to add a new app the schema needs to be: -``` + +```text TEST_APP: {         name: 'testapp',         file_location: 'https://github.com/Alfresco/alfresco-ng2-components/blob/branch/e2e/resources/testapp.zip?raw=true', diff --git a/lib/cli/bin/adf-cli b/lib/cli/bin/adf-cli index ef64e6794e..c256a1bd92 100755 --- a/lib/cli/bin/adf-cli +++ b/lib/cli/bin/adf-cli @@ -1,16 +1,30 @@ #!/usr/bin/env node +// tslint:disable: adf-file-name +// tslint:disable: no-var-requires const minimist = require('minimist'); const path = require('path'); +const fs = require('fs'); const args = minimist(process.argv.slice(2), { boolean: ['verbose'] }); + +if (args._.length === 0) { + console.error('Error: no commands provided'); + process.exit(1); +} + const scriptName = args._.shift(); -const scriptPath = path.join('../scripts', scriptName); +const scriptPath = process.env.DEVELOP + ? path.resolve(path.join(__dirname, '../dist/scripts', scriptName)) + : path.resolve(path.join(__dirname, '../scripts', scriptName)); + +if (!fs.existsSync(`${scriptPath}.js`)) { + console.error(`Error: command ${scriptName} not found.`); + process.exit(1); +} const cwd = process.cwd(); -process.chdir(path.join(__dirname, '..')); - try { Promise.resolve() diff --git a/lib/cli/package-lock.json b/lib/cli/package-lock.json index 6957830ff8..026fc7e38f 100644 --- a/lib/cli/package-lock.json +++ b/lib/cli/package-lock.json @@ -1,9 +1,17 @@ { "name": "@alfresco/adf-cli", - "version": "3.5.0", + "version": "3.8.0", "lockfileVersion": 1, "requires": true, "dependencies": { + "@alfresco/adf-testing": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/@alfresco/adf-testing/-/adf-testing-3.8.0.tgz", + "integrity": "sha512-feinvQ62LLpIHca7SnCc6mRK2vhGeK8w+VCmSZlHkcf97YF+nou0JuFi/CQ6aAWWfaQtNZrm9VjXEeUUvh1s1Q==", + "requires": { + "tslib": "^1.9.0" + } + }, "@angular-devkit/core": { "version": "7.3.9", "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-7.3.9.tgz", @@ -353,6 +361,45 @@ } } }, + "@types/events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", + "dev": true + }, + "@types/glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", + "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", + "dev": true, + "requires": { + "@types/events": "*", + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "@types/node": { + "version": "13.13.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.4.tgz", + "integrity": "sha512-x26ur3dSXgv5AwKS0lNfbjpCakGIduWU1DU91Zz58ONRWrIKGunmZBNv4P7N+e27sJkiGDsw/3fT4AtsqQBrBA==", + "dev": true + }, + "@types/shelljs": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.7.tgz", + "integrity": "sha512-Mg2qGjLIJIieeJ1/NjswAOY9qXDShLeh6JwpD1NZsvUvI0hxdUCNDpnBXv9YQeugKi2EHU+BqkbUE4jpY4GKmQ==", + "dev": true, + "requires": { + "@types/glob": "*", + "@types/node": "*" + } + }, "JSONStream": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", diff --git a/lib/cli/package.json b/lib/cli/package.json index 504ad3ba63..e9eedbee9f 100644 --- a/lib/cli/package.json +++ b/lib/cli/package.json @@ -16,8 +16,9 @@ "url": "https://github.com/Alfresco/alfresco-ng2-components/issues" }, "scripts": { - "build-tsc": "tsc -p tsconfig.json", - "dist": "rm -rf ./dist/ && npm run build-tsc && cp -R ./bin ./dist/ && cp ./package.json ./dist/" + "build": "tsc -p tsconfig.json", + "develop": "tsc -p tsconfig.json --watch", + "dist": "rm -rf ./dist/ && npm run build && cp -R ./bin ./dist/ && cp ./package.json ./dist/" }, "dependencies": { "commander": "^4.0.0", @@ -33,5 +34,8 @@ "keywords": [ "alfresco-component" ], - "license": "Apache-2.0" + "license": "Apache-2.0", + "devDependencies": { + "@types/shelljs": "^0.8.7" + } } diff --git a/lib/cli/scripts/artifact-from-s3.ts b/lib/cli/scripts/artifact-from-s3.ts index 97c38c8987..3ed08ee494 100644 --- a/lib/cli/scripts/artifact-from-s3.ts +++ b/lib/cli/scripts/artifact-from-s3.ts @@ -52,6 +52,7 @@ function main() { if (process.argv.includes('-h') || process.argv.includes('--help')) { program.outputHelp(); + return; } if (!program.artifact || program.artifact === '' || !program.output || program.output === '') { diff --git a/lib/cli/scripts/artifact-to-s3.ts b/lib/cli/scripts/artifact-to-s3.ts index 597bb97da7..020c17755a 100644 --- a/lib/cli/scripts/artifact-to-s3.ts +++ b/lib/cli/scripts/artifact-to-s3.ts @@ -48,6 +48,7 @@ function main() { if (process.argv.includes('-h') || process.argv.includes('--help')) { program.outputHelp(); + return; } if (!program.artifact || program.artifact === '' || !program.output || program.output === '') { diff --git a/lib/cli/scripts/docker-publish.ts b/lib/cli/scripts/docker-publish.ts index 058d51d9c6..d348df88f7 100644 --- a/lib/cli/scripts/docker-publish.ts +++ b/lib/cli/scripts/docker-publish.ts @@ -83,6 +83,7 @@ function main(args) { if (process.argv.includes('-h') || process.argv.includes('--help')) { program.outputHelp(); + return; } if (args.loginCheck === true) { diff --git a/lib/cli/scripts/init-aae-env.ts b/lib/cli/scripts/init-aae-env.ts index f05ea00fd0..16d0101785 100644 --- a/lib/cli/scripts/init-aae-env.ts +++ b/lib/cli/scripts/init-aae-env.ts @@ -302,6 +302,7 @@ async function main(args: ConfigArgs) { if (process.argv.includes('-h') || process.argv.includes('--help')) { program.outputHelp(); + return; } await initConfiguration(args); diff --git a/lib/cli/scripts/kubectl-clean-app.ts b/lib/cli/scripts/kubectl-clean-app.ts index b143d50472..e15fed012d 100644 --- a/lib/cli/scripts/kubectl-clean-app.ts +++ b/lib/cli/scripts/kubectl-clean-app.ts @@ -278,6 +278,7 @@ async function main(args) { if (process.argv.includes('-h') || process.argv.includes('--help')) { program.outputHelp(); + return; } const configModeler = getAlfrescoJsApiInstance(args); diff --git a/lib/cli/scripts/kubectl-delete.ts b/lib/cli/scripts/kubectl-delete.ts index 3106447eba..841dad34e4 100644 --- a/lib/cli/scripts/kubectl-delete.ts +++ b/lib/cli/scripts/kubectl-delete.ts @@ -77,6 +77,7 @@ function main(args) { if (process.argv.includes('-h') || process.argv.includes('--help')) { program.outputHelp(); + return; } if (args.label !== undefined) { diff --git a/lib/cli/scripts/kubectl-image.ts b/lib/cli/scripts/kubectl-image.ts index 76eab9a057..1f3e8bbf57 100644 --- a/lib/cli/scripts/kubectl-image.ts +++ b/lib/cli/scripts/kubectl-image.ts @@ -92,6 +92,7 @@ function main(args) { if (process.argv.includes('-h') || process.argv.includes('--help')) { program.outputHelp(); + return; } if (args.installCheck === true) { diff --git a/lib/cli/scripts/npm-publish.ts b/lib/cli/scripts/npm-publish.ts index 4fa4f8869d..0706b293f4 100644 --- a/lib/cli/scripts/npm-publish.ts +++ b/lib/cli/scripts/npm-publish.ts @@ -115,6 +115,7 @@ async function main(args) { if (process.argv.includes('-h') || process.argv.includes('--help')) { program.outputHelp(); + return; } for (let i = 0; i < projects.length; i++) { diff --git a/lib/cli/scripts/update-commit-sha.ts b/lib/cli/scripts/update-commit-sha.ts index 80ca0b830c..a41a80be0b 100644 --- a/lib/cli/scripts/update-commit-sha.ts +++ b/lib/cli/scripts/update-commit-sha.ts @@ -66,6 +66,7 @@ function main(args) { if (process.argv.includes('-h') || process.argv.includes('--help')) { program.outputHelp(); + return; } const sha = getSha(args); diff --git a/lib/cli/scripts/update-version.ts b/lib/cli/scripts/update-version.ts index 713bfb1ffb..71fb8884f7 100644 --- a/lib/cli/scripts/update-version.ts +++ b/lib/cli/scripts/update-version.ts @@ -17,9 +17,10 @@ * limitations under the License. */ -import { exec } from './exec'; import * as program from 'commander'; -import { logger } from './logger'; +import * as path from 'path'; +import * as fs from 'fs'; +import * as shell from 'shelljs'; export interface UpdateArgs { pathPackage: string; @@ -28,140 +29,98 @@ export interface UpdateArgs { beta?: boolean; version: string; vjs: string; - skipGnu: boolean; } -const ALPHA = 'alpha'; -const BETA = 'beta'; -const LATEST = 'latest'; -const ADF_LIBS_PREFIX = '\"@alfresco/adf-[^"]*\":'; -const JS_API_DEPENDENCY = '@alfresco/js-api'; - -let projects = ['']; - -function latestPerform(args: UpdateArgs) { - tagPerform(args, LATEST); +export interface PackageInfo { + dependencies?: string[]; + devDependencies?: string[]; } -function versionPerform(args: UpdateArgs) { - updateLibsVersionPerform(args.pathPackage, args.version, args.skipGnu); +function parseAlfrescoLibs(workingDir: string): PackageInfo { + const packagePath = path.resolve(path.join(workingDir, 'package.json')); + + let dependencies: string[] = []; + let devDependencies: string[] = []; + + if (fs.existsSync(packagePath)) { + const json = require(packagePath); + const isAlfrescoLib = (key: string) => key.startsWith('@alfresco'); + + dependencies = Object.keys((json.dependencies || [])).filter(isAlfrescoLib); + devDependencies = Object.keys((json.devDependencies || [])).filter(isAlfrescoLib); + } + + return { + dependencies, + devDependencies + }; } -function versionJsPerform(args: UpdateArgs) { - updateJsAPIVersionPerform(args.pathPackage, args.vjs, args.skipGnu); +function formatNpmCommand(deps: string[], tag: string): string { + return [ + 'npm i -E', + deps.map(name => `${name}@${tag}`).join(' ') + ].join(' '); } -function alphaPerform(args: UpdateArgs) { - tagPerform(args, ALPHA); -} - -function betaPerform(args: UpdateArgs) { - tagPerform(args, BETA); -} - -function findADFLibsDependencies(args: UpdateArgs) { - const prjs: any = []; - const result = exec('grep', [`${ADF_LIBS_PREFIX}`, `${args.pathPackage}/package.json`], {}).trim(); - const res = result.replace(/,\s*$/, '').split(','); - res.forEach( (dependecy) => { - const dep = dependecy.split(':'); - const depName = dep[0].trim(); - prjs.push(depName.replace(/"/g, '')); - }); - return prjs; -} - -function getLatestVersionFromNpm(tag: string, project: string): string { - logger.info(`====== Auto find latest ${tag} version of ${project}`); - const latestVersion = exec('npm', ['view', `${project}@${tag}`, `version`], {}).trim(); - logger.info(`====== version lib ${latestVersion} =====`); - return latestVersion; -} - -function updateLibsVersionPerform(path: string, version: string, skipGnu = false) { - logger.info('Perform libs version...'); - projects.forEach( (project) => { - logger.info(`apply version ${version} on ${project} ...`); - project = project.replace('/', '\\/'); - replaceVersionPerform(project, version, path, skipGnu); - }); -} - -function updateJsAPIVersionPerform(path: string, version: string, skipGnu = false) { - logger.info('Perform js-api version...'); - logger.info(`apply version ${version} on ${JS_API_DEPENDENCY} ...`); - const project = JS_API_DEPENDENCY.replace('/', '\\/'); - replaceVersionPerform(project, version, path, skipGnu); -} - -function replaceVersionPerform(project: string, version: string, path: string, skipGnu = false) { - const rule = `s/\"${project}\": \".*\"/\"${project}\": \"${version}\"/g`; - if (skipGnu) { - exec('sed', ['-i', '', `${rule}`, `${path}/package.json`], {}).trim(); - } else { - exec('sed', ['-i', `${rule}`, `${path}/package.json`], {}).trim(); +function runNpmCommand(command: string, workingDir: string) { + if (shell.exec(command, { cwd: workingDir }).code !== 0) { + shell.echo('Error running NPM command'); + shell.exit(1); } } -function tagPerform(args: UpdateArgs, tag: string) { - logger.info(`Perform ${tag} update...`); - tagLibPerform(args, tag); - tagJsPerform(args, tag); +function updateLibs(pkg: PackageInfo, tag: string, workingDir: string) { + if (pkg.dependencies && pkg.dependencies.length > 0) { + runNpmCommand( + formatNpmCommand(pkg.dependencies, tag), + workingDir + ); + } + + if (pkg.devDependencies && pkg.devDependencies.length > 0) { + runNpmCommand( + formatNpmCommand(pkg.devDependencies, tag) + ' -D', + workingDir + ); + } } -function tagLibPerform(args: UpdateArgs, tag: string) { - const libVersion = getLatestVersionFromNpm(tag, '@alfresco/adf-extensions'); - updateLibsVersionPerform(args.pathPackage, libVersion, args.skipGnu); +function parseTag(args: UpdateArgs): string { + if (args.alpha) { + return 'alpha'; + } + + if (args.beta) { + return 'beta'; + } + + return args.version || 'latest'; } -function tagJsPerform(args: UpdateArgs, tag: string) { - const jsApiVersion = getLatestVersionFromNpm(tag, JS_API_DEPENDENCY); - updateJsAPIVersionPerform(args.pathPackage, jsApiVersion, args.skipGnu); -} - -export default function (args: UpdateArgs) { - main(args); -} - -function main(args) { - +export default function main(args: UpdateArgs, workingDir: string) { program - .version('0.1.0', '-vers') .description('This command allows you to update the adf dependencies and js-api with different versions\n\n' + 'Update adf libs and js-api with latest alpha\n\n' + - 'adf-cli update-version --alpha --pathPackage "$(pwd)"') - .option('--pathPackage [type]', 'pathPackage') - .option('--alpha [type]', 'use alpha') - .option('--beta [type]', 'use beta') - .option('--version [type]', 'use version') - .option('--vjs [type]', 'vjs use version js api') - .option('--skipGnu [type]', 'skipGnu') + 'adf-cli update-version --alpha') + .option('--pathPackage [dir]', 'Directory that contains package.json file', 'current directory') + .option('--alpha', 'use alpha') + .option('--beta', 'use beta') + .option('--version [tag]', 'use specific version can be also alpha/beta/latest', 'latest') + .option('--vjs [tag]', 'Upgrade only JS-API to a specific version') .parse(process.argv); if (process.argv.includes('-h') || process.argv.includes('--help')) { program.outputHelp(); + return; } - projects = findADFLibsDependencies(args); + workingDir = args.pathPackage || workingDir; - if (args.version) { - versionPerform(args); - } - - if (args.vjs) { - versionJsPerform(args); - } - - if (args.latest === true) { - latestPerform(args); - } - - if (args.alpha === true) { - alphaPerform(args); - } - - if (args.beta === true) { - betaPerform(args); - } + const tag = args.vjs || parseTag(args); + const pkg = args.vjs + ? { dependencies: ['@alfresco/js-api'] } + : parseAlfrescoLibs(workingDir); + updateLibs(pkg, tag, workingDir); }