Skip to content

Commit

Permalink
feat: make log messages and styles configurable with theme.
Browse files Browse the repository at this point in the history
  • Loading branch information
sttk committed Feb 12, 2024
1 parent f71effa commit be0955c
Show file tree
Hide file tree
Showing 29 changed files with 671 additions and 467 deletions.
2 changes: 1 addition & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"extends": "gulp",
"rules": {
"max-len": [1, 130],
"max-statements": [1, 40],
"max-statements": [1, 60],
"no-console": "off"
}
}
6 changes: 6 additions & 0 deletions .github/workflows/dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ jobs:
# Run test without coverage because a behavior about esm is different with nyc or not
run: npm test

- name: Run tests with coloring
run: npx mocha test/lib/theme.js
env:
FORCE_COLOR: 2
CI: ""

coveralls:
needs: test
name: Finish up
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ Supported configurations properties:
| flags.series | Run tasks given on the CLI in series (the default is parallel) |
| flags.preload | An array of modules to preload before running the gulpfile. Any relative paths will be resolved against the `--cwd` directory (if you don't want that behavior, use absolute paths) |
| flags.nodeFlags | An array of flags used to forcibly respawn the process upon startup. For example, if you always want your gulpfiles to run in node's harmony mode, you can set `--harmony` here |
| log.messages.* | Configure log messages. |
| log.theme.* | Configure log theme. |

## Flags

Expand Down
80 changes: 25 additions & 55 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,22 @@
var fs = require('fs');
var path = require('path');
var log = require('gulplog');

var Liftoff = require('liftoff');
var interpret = require('interpret');
var v8flags = require('v8flags');
var findRange = require('semver-greatest-satisfied-range');
var chalk = require('chalk');
var format = require('theming-log').format;

var exit = require('./lib/shared/exit');
var tildify = require('./lib/shared/tildify');
var makeTitle = require('./lib/shared/make-title');
var parser = require('./lib/shared/options/parser');
var makeHelp = require('./lib/shared/options/make-help');
var completion = require('./lib/shared/completion');
var cliVersion = require('./package.json').version;
var toConsole = require('./lib/shared/log/to-console');
var theme = require('./lib/shared/log/theme');
var msgs = require('./lib/shared/log/messages');

var mergeProjectAndUserHomeConfigs = require('./lib/shared/config/merge-configs');
var overrideEnvFlagsByConfigAndCliOpts = require('./lib/shared/config/env-flags');
Expand Down Expand Up @@ -55,22 +58,15 @@ var cli = new Liftoff({
var opts = parser.argv;

cli.on('preload:before', function(name) {
log.info('Preloading external module:', chalk.magenta(name));
log.info(msgs.info.preloadBefore, name);
});

cli.on('preload:success', function(name) {
log.info('Preloaded external module:', chalk.magenta(name));
log.info(msgs.info.preloadSuccess, name);
});

cli.on('preload:failure', function(name, error) {
log.warn(
chalk.yellow('Failed to preload external module:'),
chalk.magenta(name)
);
/* istanbul ignore else */
if (error) {
log.warn(chalk.yellow(error.toString()));
}
log.warn(msgs.warn.preloadFailure, name, Boolean(error), error.toString());
});

cli.on('loader:success', function(name) {
Expand All @@ -79,26 +75,16 @@ cli.on('loader:success', function(name) {
// However, we don't want to show the mjs-stub loader in the logs
/* istanbul ignore else */
if (path.basename(name, '.js') !== 'mjs-stub') {
log.info('Loaded external module:', chalk.magenta(name));
log.info(msgs.info.loaderSuccess, name);
}
});

cli.on('loader:failure', function(name, error) {
log.warn(
chalk.yellow('Failed to load external module:'),
chalk.magenta(name)
);
/* istanbul ignore else */
if (error) {
log.warn(chalk.yellow(error.toString()));
}
log.warn(msgs.warn.loaderFailure, name, Boolean(error), error.toString());
});

cli.on('respawn', function(flags, child) {
var nodeFlags = chalk.magenta(flags.join(', '));
var pid = chalk.magenta(child.pid);
log.info('Node flags detected:', nodeFlags);
log.info('Respawned to PID:', pid);
log.info(msgs.info.respawn, flags.join(', '), child.pid);
});

function run() {
Expand Down Expand Up @@ -133,14 +119,14 @@ function onExecute(env) {
}

if (env.config.flags.help) {
parser.showHelp(console.log);
makeHelp(parser).showHelp(console.log);
exit(0);
}

// Anything that needs to print outside of the logging mechanism should use console.log
if (env.config.flags.version) {
console.log('CLI version:', cliVersion);
console.log('Local version:', env.modulePackage.version || 'Unknown');
var gulpVersion = env.modulePackage.version || 'Unknown';
console.log(format(theme, msgs.info.version, cliVersion, gulpVersion));
exit(0);
}

Expand All @@ -150,51 +136,35 @@ function onExecute(env) {
fs.existsSync(path.join(env.cwd, 'package.json'))
&& !fs.existsSync(path.join(env.cwd, 'node_modules'));

/* istanbul ignore next */
var missingGulpMessage =
missingNodeModules
? 'Local modules not found in'
: 'Local gulp not found in';
log.error(
chalk.red(missingGulpMessage),
chalk.magenta(tildify(env.cwd))
);
var hasYarn = fs.existsSync(path.join(env.cwd, 'yarn.lock'));
/* istanbul ignore next */
var installCommand =
missingNodeModules
? hasYarn
? 'yarn install'
: 'npm install'
: hasYarn
? 'yarn add gulp'
: 'npm install gulp';
log.error(chalk.red('Try running: ' + installCommand));
var hasNpm = !hasYarn;

/* istanbul ignore if */
if (missingNodeModules) {
log.error(msgs.error.nodeModulesNotFound, tildify(env.cwd), hasYarn, hasNpm);
} else {
log.error(msgs.error.gulpNotFound, tildify(env.cwd), hasYarn, hasNpm);
}
exit(1);
}

if (!env.configPath) {
log.error(chalk.red('No gulpfile found'));
log.error(msgs.error.gulpfileNotFound);
exit(1);
}

// Chdir before requiring gulpfile to make sure
// we let them chdir as needed
if (process.cwd() !== env.cwd) {
process.chdir(env.cwd);
log.info(
'Working directory changed to',
chalk.magenta(tildify(env.cwd))
);
log.info(msgs.info.cwdChanged, tildify(env.cwd));
}

// Find the correct CLI version to run
var range = findRange(env.modulePackage.version, ranges);

if (!range) {
log.error(
chalk.red('Unsupported gulp version', env.modulePackage.version)
);
log.error(msgs.error.badGulpVersion, env.modulePackage.version);
exit(1);
}

Expand Down
12 changes: 6 additions & 6 deletions lib/shared/completion.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@

var fs = require('fs');
var path = require('path');
var format = require('theming-log').format;

var theme = require('./log/theme');
var msgs = require('./log/messages');

module.exports = function(name) {
if (typeof name !== 'string') {
throw new Error('Missing completion type');
throw new Error(format(theme, msgs.error.noCompletionType));
}
var file = path.join(__dirname, '../../completion', name);
try {
console.log(fs.readFileSync(file, 'utf8'));
process.exit(0);
} catch (err) {
console.log(
'echo "gulp autocompletion rules for',
'\'' + name + '\'',
'not found"'
);
console.log(format(theme, msgs.error.unknownCompletionType, name));
process.exit(5);
}
};
175 changes: 175 additions & 0 deletions lib/shared/log/messages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
'use strict';

/* eslint max-len: 0 */

module.exports = {
help: {
usage:
'\n{TITLE: Usage:} gulp {OPTION: [options]} {TASK: tasks}',

flags: {
help:
'{HELP.DESC: Show this help.}',

version:
'{HELP.DESC: Print the global and local gulp versions.}',

preload:
'{HELP.DESC: Will preload a module before running the gulpfile. ' +
'This is useful for transpilers but also has other applications.}',

gulpfile:
'{HELP.DESC: Manually set path of gulpfile. Useful if you have ' +
'multiple gulpfiles. This will set the CWD to the gulpfile ' +
'directory as well.}',

cwd:
'{HELP.DESC: Manually set the CWD. The search for the gulpfile, ' +
'as well as the relativity of all requires will be from here.}',

tasks:
'{HELP.DESC: Print the task dependency tree for the loaded ' +
'gulpfile.}',

'tasks-simple':
'{HELP.DESC: Print a plaintext list of tasks for the loaded ' +
'gulpfile.}',

'tasks-json':
'{HELP.DESC: Print the task dependency tree, in JSON format, ' +
'for the loaded gulpfile.}',

'tasks-depth':
'{HELP.DESC: Specify the depth of the task dependency tree.}',

'compact-tasks':
'{HELP.DESC: Reduce the output of task dependency tree by ' +
'printing only top tasks and their child tasks.}',

'sort-tasks':
'{HELP.DESC: Will sort top tasks of task dependency tree.}',

color:
'{HELP.DESC: Will force gulp and gulp plugins to display ' +
'colors, even when no color support is detected.}',

'no-color':
'{HELP.DESC: Will force gulp and gulp plugins to not display ' +
'colors, even when color support is detected.}',

silent:
'{HELP.DESC: Suppress all gulp logging.}',

continue:
'{HELP.DESC: Continue execution of tasks upon failure.}',

series:
'{HELP.DESC: Run tasks given on the CLI in series (the default ' +
'is parallel).}',

'log-level':
'{HELP.DESC: Set the loglevel. -L for least verbose and -LLLL ' +
'for most verbose. -LLL is default.}',
},
},
tasks: {
gulpfile:
'{DESC: Tasks for} {PATH: {1:gulpfile path}}',

topTask:
'{TASKS.BRANCH: {1:branch line}}{TASKS.NAME: {2:task name}}{IF:{3:has desc}?{4:space}{TASKS.DESC: {5:task description}}}',

option:
'{TASKS.BRANCH: {1:branch line}}{TASKS.OPTION: {2:option name}}{IF:{3:has desc}?{4:space}…{TASKS.DESC: {5:option description}}',

childTask:
'{TASKS.BRANCH: {1:branch line}{TASKS.CHILD: {2:task name}}',
},

tasksJson: {
gulpfile:
'Tasks for {1:gulpfile path}',
},

info: {
preloadBefore:
'{TIMESTAMP}{DESC: Preloading external module:} {MODULE: {1:module name}}',

preloadSuccess:
'{TIMESTAMP}{DESC: Preloaded external module:} {MODULE: {1:module name}}',

loaderSuccess:
'{TIMESTAMP}{DESC: Loaded external module:} {MODULE: {1:module name}}',

respawn:
'{TIMESTAMP}{DESC: Node flags detected:} {OPTION: {1:node flags}}\n' +
'{TIMESTAMP}{DESC: Respawned to PID: {PID: {2:pid}}',

version:
'{DESC: CLI version}: {VERSION: {1:CLI version}}\n' +
'{DESC: Local version}: {VERSION: {2:gulp version}}',

cwdChanged:
'{TIMESTAMP}{DESC: Working directory changed to} {PATH: {1:cwd}}',

usingGulpfile:
'{TIMESTAMP}{DESC: Using gulpfile} {PATH: {1:gulpfile path}}',

taskStart:
'{TIMESTAMP}{DESC: Starting \'}{TASK: {1:task name}}{DESC: \'...}',

taskStop:
'{TIMESTAMP}{DESC: Finished \'}{TASK: {1:task name}}{DESC: \' after} ' +
'{DURATION: {2:duration}}',
},

warn: {
preloadFailure:
'{TIMESTAMP}{WARN: Failed to preload external module:} {MODULE: {1: module name}}\n' +
'{IF:{2:exists error}?{TIMESTAMP}{WARN: {3:error message}} ',

loaderFailure:
'{TIMESTAMP}{WARN: Failed to load external module:} {MODULE: {1: module name}}\n' +
'{IF:{2:exists error}?{TIMESTAMP}{WARN: {3:error message}} ',

taskNotComplete:
'{TIMESTAMP}{WARN: The following tasks did not complete:} {TASK: {1}}\n' +
'{TIMESTAMP}{WARN: Did you forget to signal async completion? }',
},

error: {
gulpNotFound:
'{TIMESTAMP}{ERROR: Local gulp not found in} {PATH: {1}}\n' +
'{TIMESTAMP}{ERROR: Try running: {IF:{2:has yarn}?yarn add}{IF:{3:has npm}?npm install} gulp}',

nodeModulesNotFound:
'{TIMESTAMP}{ERROR: Local modules not found in} {PATH: {1}}\n' +
'{TIMESTAMP}{ERROR: Try running: {IF:{2:has yarn}?yarn install}{IF:{3:has npm}?npm install}',

gulpfileNotFound:
'{TIMESTAMP}{ERROR: No gulpfile found}',

badGulpVersion:
'{TIMESTAMP}{ERROR: Unsupported gulp version {VERSION: {1}}}',

taskError:
'{TIMESTAMP}{ERROR: \'{1:task}\' errored after} ' +
'{DURATION: {2:duration}}' +
'{IF:{3:has cause}?\n{TIMESTAMP}{ERROR: {4:cause}}}',

taskNotFound:
'{TIMESTAMP}{ERROR: Task never defined: {1:task}}\n' +
'{TIMESTAMP}{ERROR: To list available tasks, try running: gulp --tasks}',

failToRun:
'{TIMESTAMP}{ERROR: {1:cause}}\n' +
'{TIMESTAMP}{ERROR: Please check the documentation for proper ' +
'gulpfile formatting}',

noCompletionType:
'Missing completion type',

unknownCompletionType:
'echo "gulp autocompletion rules for \'{1:type}\' not found"',
},
};
Loading

0 comments on commit be0955c

Please sign in to comment.