diff --git a/README.md b/README.md index 1e514db..c56ce3c 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,9 @@ module.exports = { yarn: '~1.17.3', nginx: { semver: '>= 1.16.x', - optional: true // optional (won't fail) + optional: true, // optional (won't fail) + installMessage: '', // custom message when binary is not found + updateMessage: '' // custom message when binary has wrong version }, httpd: { semver: '^1.x', @@ -58,7 +60,7 @@ $ npx requirements Or use a custom path: ```bash -$ npx requirements --config= +$ npx requirements --config ``` # CLI options @@ -105,8 +107,19 @@ checkSoftware() returns an Array with results ]; ``` +# testing + +```bash +# test functionality +yarn build +node bin/requirements.js --config tests/requirements.config.js + +# unit tests +yarn test +``` + # license The MIT License (MIT) -Copyright (c) 2017-2019 Steven Chim +Copyright (c) 2017-2020 Steven Chim diff --git a/src/__tests__/results.spec.ts b/src/__tests__/results.spec.ts new file mode 100644 index 0000000..5c730db --- /dev/null +++ b/src/__tests__/results.spec.ts @@ -0,0 +1,52 @@ +import * as fs from 'fs'; +import { isAllOK, getMessages } from '../results'; +import { RawResult } from '../types'; + +describe('results', () => { + describe('all results OK', () => { + it('should indicate all results are OK', async () => { + const rawResults: RawResult[] = [ + { + bin: 'mvn', + satisfies: true + } as RawResult + ]; + + const result = isAllOK(rawResults); + expect(result).toBe(true); + }); + + it('should indicate all results are OK', async () => { + const rawResults: RawResult[] = [ + { + bin: 'mvn', + satisfies: false + } as RawResult + ]; + + const result = isAllOK(rawResults); + expect(result).toBe(false); + }); + }); + + describe('custom messages', () => { + it('should return messages', async () => { + const rawResults: RawResult[] = [ + { + bin: 'mvn', + installed: false, + installMessage: '' + } as RawResult, + { + bin: 'nginx', + satisfies: false, + updateMessage: '' + } as RawResult + ]; + + const result = getMessages(rawResults); + const expectation = ['', '']; + expect(result).toEqual(expectation); + }); + }); +}); diff --git a/src/bin.ts b/src/bin.ts index a0165b2..880732b 100644 --- a/src/bin.ts +++ b/src/bin.ts @@ -2,9 +2,10 @@ import * as yargs from 'yargs'; import * as path from 'path'; import * as chalk from 'chalk'; import { checkSoftware } from './requirements'; -import { renderTable } from './reporter'; +import { renderTable, renderMessages } from './reporter'; import { Configuration } from './types'; import { scaffold } from './scaffold'; +import { isAllOK, getMessages } from './results'; export async function exec(_debug_argv_?) { const argv = _debug_argv_ ?? getArgv(); @@ -21,9 +22,7 @@ export async function exec(_debug_argv_?) { const config = getConfiguration(argv); let rawResults = await checkSoftware(config.software); - const ALL_OK = rawResults - .filter(result => !result.optional) - .every(result => result.satisfies === true); + const ALL_OK = isAllOK(rawResults); if (argv.debug) { console.debug('👀 RAW data:\n', rawResults); @@ -31,7 +30,9 @@ export async function exec(_debug_argv_?) { } if (!ALL_OK && !argv.force) { + const messages = getMessages(rawResults); console.error(renderTable(rawResults)); + console.log(renderMessages(messages)); throw new Error(`❌ Not all requirements are satisfied`); } diff --git a/src/reporter.ts b/src/reporter.ts index 00da46a..ceb4f32 100644 --- a/src/reporter.ts +++ b/src/reporter.ts @@ -3,6 +3,10 @@ import * as logSymbols from 'log-symbols'; import * as chalk from 'chalk'; import { RawResult } from './types'; +export function renderMessages(messages: string[] = []) { + return messages.map(message => `${chalk.red('❗️')} ${message}`).join('\n') + '\n'; +} + export function renderTable(rawResults: RawResult[] = []) { let results = rawResults.map(item => { const { bin, semver, installed, version, satisfies, optional } = item; diff --git a/src/results.ts b/src/results.ts new file mode 100644 index 0000000..2dccd07 --- /dev/null +++ b/src/results.ts @@ -0,0 +1,18 @@ +import { RawResult } from './types'; + +export function isAllOK(rawResults: RawResult[]) { + return rawResults.filter(result => !result.optional).every(result => result.satisfies === true); +} + +export function getMessages(rawResults: RawResult[]) { + const notInstalledItems = rawResults.filter(item => !item.installed && item.installMessage); + const unsatisfiedInstalledItems = rawResults.filter( + item => !item.satisfies && item.updateMessage + ); + + const messages = [...notInstalledItems, ...unsatisfiedInstalledItems].map(item => { + return item.installMessage || item.updateMessage; + }); + + return messages; +} diff --git a/src/scaffold.ts b/src/scaffold.ts index 2ab1f3f..e0f3eab 100644 --- a/src/scaffold.ts +++ b/src/scaffold.ts @@ -9,11 +9,13 @@ const TEMPLATE = `module.exports = { node: '^${semver.clean(process.version)}', nginx: { semver: '^666.x', - optional: true // won't fail if missing or wrong version + optional: true // won't fail if missing or wrong version }, // httpd: { // semver: '^2.x', - // flag: '-v' // custom flag to print version + // flag: '-v', // custom flag to print version + // installMessage: '', // custom message when binary is not found + // updateMessage: '', // custom message when binary has wrong version // }, } };`; diff --git a/src/types.ts b/src/types.ts index 17d75cd..4169238 100644 --- a/src/types.ts +++ b/src/types.ts @@ -10,18 +10,17 @@ export type ConfigurationValue = ConfigurationStringValue | ConfigurationObjectV export type ConfigurationStringValue = string; -export type ConfigurationObjectValue = { +export interface ConfigurationObjectValue { semver: string; flag: string; optional?: boolean; -}; + installMessage?: string; + updateMessage?: string; +} -export interface RawResult { +export interface RawResult extends ConfigurationObjectValue { bin: string; - semver: string; - flag: string; installed: boolean; version?: string; satisfies?: boolean; - optional?: boolean; } diff --git a/tests/requirements.config.js b/tests/requirements.config.js index 5f381dc..1600dfb 100644 --- a/tests/requirements.config.js +++ b/tests/requirements.config.js @@ -4,11 +4,15 @@ module.exports = { git: '~1.9.4 || 2.0.0 - 2.10.0', node: '8 || 10 || 12', npm: '>= 6.x', - yarn: '>= 1.19.x', + yarn: { + semver: '1.16.x', + updateMessage: `Outdated 'yarn' found. Run 'brew upgrade yarn' to update.` + }, mvn: '^3.x', nginx: { semver: '^6.x', - optional: true + optional: true, + installMessage: `This project is configured for NGINX but 'nginx' was not found on your path. Run 'brew install nginx' to install.` }, httpd: { semver: '^2.x',