diff --git a/package-lock.json b/package-lock.json index 14f82e7..ccd5ae9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,8 @@ "axios": "^0.21.1", "chalk": "^3.0.0", "codecov": "^3.8.1", + "cron-validator": "^1.2.1", + "cronstrue": "^1.110.0", "crypto-js": "^4.0.0", "detect-character-encoding": "^0.8.0", "encoding-japanese": "^1.0.30", @@ -3174,6 +3176,16 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, + "node_modules/cron-validator": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/cron-validator/-/cron-validator-1.2.1.tgz", + "integrity": "sha512-RqdpGSokGFICPc8qAkT38aXqZLLanXghQTK2q7a2x2FabSwDd2ARrazd5ElEWAXzToUcMG4cZIwDH+5RM0q1mA==" + }, + "node_modules/cronstrue": { + "version": "1.110.0", + "resolved": "https://registry.npmjs.org/cronstrue/-/cronstrue-1.110.0.tgz", + "integrity": "sha512-+ABuGZl/nqf/0TemAsPlMSGaB9xEobWhctfRGEqEvH3g6pB/2FGbsUHQPSL8Wt1W3nmOHe1w8GWjacN5k8d3hg==" + }, "node_modules/cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -12539,6 +12551,16 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, + "cron-validator": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/cron-validator/-/cron-validator-1.2.1.tgz", + "integrity": "sha512-RqdpGSokGFICPc8qAkT38aXqZLLanXghQTK2q7a2x2FabSwDd2ARrazd5ElEWAXzToUcMG4cZIwDH+5RM0q1mA==" + }, + "cronstrue": { + "version": "1.110.0", + "resolved": "https://registry.npmjs.org/cronstrue/-/cronstrue-1.110.0.tgz", + "integrity": "sha512-+ABuGZl/nqf/0TemAsPlMSGaB9xEobWhctfRGEqEvH3g6pB/2FGbsUHQPSL8Wt1W3nmOHe1w8GWjacN5k8d3hg==" + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", diff --git a/package.json b/package.json index 48e9b49..f55fc37 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,8 @@ "axios": "^0.21.1", "chalk": "^3.0.0", "codecov": "^3.8.1", + "cron-validator": "^1.2.1", + "cronstrue": "^1.110.0", "crypto-js": "^4.0.0", "detect-character-encoding": "^0.8.0", "encoding-japanese": "^1.0.30", diff --git a/src/commands/cron.ts b/src/commands/cron.ts new file mode 100644 index 0000000..e41072a --- /dev/null +++ b/src/commands/cron.ts @@ -0,0 +1,71 @@ +import {Command, flags} from '@oclif/command' +import chalk from 'chalk' +import {isValidCron} from 'cron-validator' +import cronstrue from 'cronstrue' + +import Logger from '../utilities/logger' +import Utilities from '../utilities/utilities' +/* +* this Commands add support for cron jobs +* */ +export default class Cron extends Command { + static description = 'Cron Expressions helper and scheduler' + + static RUN = 'run' + static DESCRIBE = 'desc' + + static flags = { + help: flags.help({char: 'h'}), + string: flags.string({char: 's' , description: 'Cron expression'}), + describe: flags.boolean({char: 'd' , description: 'Describe cron expressions into human readable descriptions'}), + run: flags.boolean({char: 'r' , description: 'run command using cron expression'}), + } + + static args = [{name: 'string'}] + + // only 2 parameters required HASH_TYPE and INPUT_STRING + async run() { + const {args, flags} = this.parse(Cron) + + args.string = Utilities.getInputStringFromCmd(this, flags, args) // from either -s or args + args.action = this.getAction(flags, args) //by default let it be sha1 + + //check params after evaluating all + this.checkParameters(flags, args) + this.evalCron(flags, args) + } + + // to check required parameters passed or not + // tslint:disable-next-line:no-unused + private checkParameters(flags: any, args: any) { + if (args.string === undefined || args.string === '') + Logger.error(this, 'Input string is empty or undefined') + + if (!isValidCron(args.string)) { + Logger.error(this, `Invalid Cron expression : ${chalk.red(args.string)}`) + } + + if (args.action === undefined || args.string === '') + Logger.error(this, 'Action empty or undefined') + } + + // tslint:disable-next-line:no-unused + private evalCron(flags: any, args: any) { + // Logger.success(this, `Action: ${chalk.green(args.action)}`) + if (args.action === Cron.DESCRIBE) { + let output = cronstrue.toString(args.string) + Logger.success(this, output) + } else if (args.action === Cron.RUN) { + Logger.success(this, 'run command, coming soon...') + } + } + + // tslint:disable-next-line:no-unused + private getAction(flags: any, args: any) { + if (flags.describe) // find human readable descriptions for cron + return Cron.DESCRIBE + else if (flags.run) // if run is given + return Cron.RUN + Logger.error(this, 'Invalid Or Unsupported action') + } +} diff --git a/src/utilities/utilities.ts b/src/utilities/utilities.ts index f9d3dc7..37d222e 100644 --- a/src/utilities/utilities.ts +++ b/src/utilities/utilities.ts @@ -40,6 +40,15 @@ export default class Utilities { return args.string } + // tslint:disable-next-line:no-unused + public static getInputStringFromCmd(thisRef: Command, flags: any, args: any) { //need to make it static so Crypto can use this + // if -s is not passed we will take it from args + if (flags.string) //if -s given + return flags.string + else + return args.string + } + public static writeStringToFile(thisRef: Command, filePath: string, string: string) { if (!fs.existsSync(filePath)) Logger.info(thisRef, `Could not find file: ${chalk.yellow(filePath + ', creating new one')}`) // this will output error and exit command diff --git a/test/commands/cron.test.ts b/test/commands/cron.test.ts new file mode 100644 index 0000000..764bbb2 --- /dev/null +++ b/test/commands/cron.test.ts @@ -0,0 +1,33 @@ +import {expect, test} from '@oclif/test' + +describe('cron', () => { + test + .stdout() + .command(['cron']) + .exit(0) + .it('Nothing is passed', ctx => { + expect(ctx.stdout).to.contain('Invalid Or Unsupported action') + }) + test + .stdout() + .command(['cron', '-d', '* * * x *']) + .exit(0) + .it('Invalid Cron Expression', ctx => { + expect(ctx.stdout).to.contain('Invalid Cron expression') + }) + + test + .stdout() + .command(['cron', '-d', '15 14 1 * *']) + .it('Describe cron with arg for input', ctx => { + expect(ctx.stdout).to.contain('At 02:15 PM, on day 1 of the month') + }) + + test + .stdout() + .command(['cron', '-d', '-s', '0 22 * * 1-5']) + .it('Describe cron with -s flag for input', ctx => { + expect(ctx.stdout).to.contain('At 10:00 PM, Monday through Friday') + }) + +})