@interaktiv/dia-scripts
Version:
CLI toolbox with common scripts for most sort of projects at DIA
204 lines (164 loc) • 6.5 kB
JavaScript
"use strict";
const path = require('path');
const {
ensureString,
isArray
} = require('@interaktiv/types');
const spawn = require('cross-spawn');
const exit = require('exit');
const fs = require('fs-extra');
const mkdirp = require('mkdirp');
const yargsParser = require('yargs-parser');
const {
PMD_CACHE_FILE,
PMD_DIR,
PMD_IGNORE_FILE,
PMD_LOGFILE,
PMD_META_DATA_BUNDLE,
createFileIfNeeded,
createPmdMetaDataBundleFromDir,
createPmdMetaDataBundleFromFiles,
fromRoot,
hasFile,
isApexFile,
parseEnv,
resolveBin,
resolvePmdBin
} = require('../../utils');
const CMD_EXIT_CODE_SUCCESS = 0;
const PMD_EXIT_CODE_RULE_VIOLATION = 4;
const PMD_EXIT_CODE_SUCCESS = CMD_EXIT_CODE_SUCCESS;
const ON_PRE_COMMIT = parseEnv('SCRIPTS_PRE-COMMIT', false);
const here = p => path.join(__dirname, p);
const hereRelative = p => here(p).replace(process.cwd(), '.');
const getPmdPath = () => {
try {
return resolveBin('pmd');
} catch (_err) {
return `bash ${resolvePmdBin()}`;
}
};
const convertCmdToSpawnArgs = cmd => {
ensureString(cmd);
return cmd.split(' ');
};
const validatePmdInstallation = cmd => {
const [command, ...args] = convertCmdToSpawnArgs(cmd);
const result = spawn.sync(command, [...args, '-help']);
if (result.status === PMD_EXIT_CODE_SUCCESS) return;
process.exitCode = result.status;
throw new Error(result.stderr || result.error);
};
const printReport = reportFile => {
if (fs.existsSync(reportFile) === false) return;
const contents = fs.readFileSync(reportFile);
console.log('');
console.log('[***] PMD Logs');
console.log('');
console.log(contents.toString());
console.log('');
};
const printMetaDataConvertMessage = () => {
console.log('');
console.log('[***] Converting Metadata for PMD');
console.log('');
};
const createPmdMetaDataBundleInternal = args => {
const filesGiven = args._.length > 0;
let status = -1;
if (filesGiven) {
// We need to take all the flag-less arguments (the files that should be
// linted) and filter out the ones that aren't Apex files. Otherwise json
// or css files may be passed through, cause of pre-commit hook for example
const filesToConvert = args._.filter(isApexFile);
printMetaDataConvertMessage();
if (isArray(filesToConvert)) {
status = createPmdMetaDataBundleFromFiles(filesToConvert);
}
} else if (args.refreshMetaData || hasFile(PMD_META_DATA_BUNDLE) === false) {
printMetaDataConvertMessage();
status = createPmdMetaDataBundleFromDir(fromRoot('force-app'));
}
if (status !== CMD_EXIT_CODE_SUCCESS) exit(status);
};
const resolveConfig = argv => {
if (argv.includes('-rulesets')) return [];
const projectRulesetPath = path.join(PMD_DIR, 'ruleset.xml');
if (hasFile(projectRulesetPath)) {
return ['-rulesets', projectRulesetPath];
}
return ['-rulesets', hereRelative('../../config/pmd-ruleset.xml')];
};
/**
* Checks if JRE is there and has the needed version.
*
* @private
* @throws
*/
function validateJRE() {
// Check if JRE is 1.7 or higher
const javaResult = spawn.sync('java', ['-version']);
if (javaResult.status > 0) {
throw new Error('JRE is missing, you must use JRE 1.7 or higher');
}
const versionMatch = javaResult.output.toString('utf-8').match(/"([0-9._]*)"/);
if (versionMatch == null || versionMatch.length === 0 || versionMatch.length < 2) {
console.log('[***] Could not determine Java version, skipping JRE validation');
console.log('');
}
const version = versionMatch[1];
const versionParts = version.split('.');
const majorVersion = versionParts[0];
const minorVersion = versionParts[1];
if (majorVersion < 1 || minorVersion < 7) {
throw new Error('You must use JRE 1.7 or higher');
}
} // eslint-disable-next-line complexity
(function () {
let argv = process.argv.slice(2);
const args = yargsParser(argv);
const filesGiven = args._.length > 0; // We are running on `pre-commit` hook but no files passed from `lint-staged`,
// skip
if (ON_PRE_COMMIT && filesGiven === false) {
exit(0);
return;
}
if (argv.includes('--validate-jre')) validateJRE();
const config = resolveConfig(argv);
const printReportAfterRun = argv.includes('--no-print-report') === false;
const cache = argv.includes('-cache') ? [] : ['-cache', PMD_CACHE_FILE];
const useBuiltinLogFile = argv.includes('-reportfile') === false;
const logFile = useBuiltinLogFile ? ['-reportfile', PMD_LOGFILE] : [];
createFileIfNeeded(useBuiltinLogFile ? PMD_LOGFILE : args.reportFile);
const logFormat = argv.includes('-format') ? [] : ['-format', 'textcolor'];
const suppressMarker = argv.includes('-suppressmarker') ? [] : ['-suppressmarker', 'pmd-disable-line'];
const useBuiltinSourceDir = argv.includes('-dir') === false;
const sourceDir = useBuiltinSourceDir ? ['-dir', PMD_META_DATA_BUNDLE] : [];
mkdirp.sync(useBuiltinSourceDir ? path.dirname(PMD_META_DATA_BUNDLE) : args.dir);
const showSuppressed = argv.includes('--do-not-showsuppressed') ? [] : ['-showsuppressed'];
const ignoreFile = args.ignorelist || PMD_IGNORE_FILE;
let ignoreList = []; // Check if ignore file exists otherwise PMD raises an error.
// Please make sure the file is not empty, otherwise PMD also raises an error
if (hasFile(ignoreFile)) ignoreList = ['-ignorelist', ignoreFile];
const DEBUG_ENV = parseEnv('DEBUG');
const debugFlag = DEBUG_ENV === true || DEBUG_ENV === 1 ? ['-debug'] : [];
createPmdMetaDataBundleInternal(args);
argv = argv.filter(a => ['--no-print-report', '--refresh-meta-data', '--do-not-showsuppressed', '--validate-jre'].includes(a) === false).filter(a => args._.includes(a) === false);
const cmd = getPmdPath();
validatePmdInstallation(cmd);
const [command, ...cmdArgs] = convertCmdToSpawnArgs(cmd);
console.log('');
console.log('[***] Running PMD');
console.log('');
const result = spawn.sync(command, [...cmdArgs, ...config, ...cache, ...logFormat, ...logFile, ...suppressMarker, ...sourceDir, ...ignoreList, ...showSuppressed, ...debugFlag, ...argv].filter(Boolean), {
stdio: 'inherit'
});
if (printReportAfterRun) {
printReport(useBuiltinLogFile ? PMD_LOGFILE : args.reportFile);
} // If not success or rule violation, output error
if ([PMD_EXIT_CODE_SUCCESS, PMD_EXIT_CODE_RULE_VIOLATION].includes(result.status) === false) {
const err = result.stderr || result.error;
if (err) console.error(err);
}
exit(result.status);
})();