Skip to content

Commit

Permalink
Add --init option to the CLI to allow users generate an initial confi…
Browse files Browse the repository at this point in the history
…guration easily

Fix #195
  • Loading branch information
sarvaje authored and molant committed May 11, 2017
1 parent 7d3748e commit 42dc706
Show file tree
Hide file tree
Showing 18 changed files with 283 additions and 0 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"file-url": "^2.0.2",
"globby": "^6.1.0",
"iconv-lite": "^0.4.17",
"inquirer": "^3.0.6",
"is-my-json-valid": "^2.15.0",
"is-resolvable": "^1.0.0",
"jsdom": "^10.1.0",
Expand Down
6 changes: 6 additions & 0 deletions src/lib/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ export const cli = {
return 0;
}

if (currentOptions.init) {
await Config.generate();

return 0;
}

if (currentOptions.help || !targets.length) {
logger.log(options.generateHelp());

Expand Down
97 changes: 97 additions & 0 deletions src/lib/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,18 @@
// Requirements
// ------------------------------------------------------------------------------

import * as fs from 'fs';
import * as path from 'path';

import * as inquirer from 'inquirer';
import * as pify from 'pify';
import * as shell from 'shelljs';

import { debug as d } from './utils/debug';
import { IConfig } from './types'; //eslint-disable-line no-unused-vars
import * as logger from './utils/logging';
import { loadJSFile, loadJSONFile } from './utils/file-loader';
import * as resourceLoader from './utils/resource-loader';

const debug = d(__filename);

Expand Down Expand Up @@ -153,3 +158,95 @@ export const getFilenameForDirectory = (directory: string): string | null => {
return null;

};

export const generate = async () => {
const collectorKeys = [...resourceLoader.getCollectors().keys()];
const formattersKeys = [...resourceLoader.getFormatters().keys()];
const rules = resourceLoader.getRules();
const rulesKeys = [];
const sonarConfig = {
browserslist: '',
collector: {
name: '',
options: {}
},
formatter: 'json',
ignoredUrls: {},
rules: {}
};

for (const [key, rule] of rules) {
rulesKeys.push({
name: `${key} - ${rule.meta.docs.description}`,
value: key
});
}

logger.log('Welcome to Sonar configuration generator');

const questions = [
{
choices: collectorKeys,
message: 'What collector do you want to use?',
name: 'collector',
type: 'list'
},
{
choices: formattersKeys,
message: 'What formatter do you want to use?',
name: 'formatter',
type: 'list'
},
{
choices: [{
name: 'Yes',
value: true
},
{
name: 'No',
value: false
}],
message: 'Do you want to use the recommended rules configuration?',
name: 'default',
type: 'list'
},
{
choices: rulesKeys,
message: 'Choose the rules you want to add to your configuration',
name: 'rules',
pageSize: 15,
type: 'checkbox',
when: (answers) => {
return !answers.default;
}
}
];

const results = await inquirer.prompt(questions);

sonarConfig.collector.name = results.collector;
sonarConfig.formatter = results.formatter;

if (results.default) {
logger.log('Using recommended rules');
rules.forEach((rule, key) => {
if (rule.meta.recommended) {
sonarConfig.rules[key] = 'error';
} else {
sonarConfig.rules[key] = 'off';
}
});
} else {
rules.forEach((rule, key) => {
if (results.rules.includes(key)) {
sonarConfig.rules[key] = 'error';
} else {
sonarConfig.rules[key] = 'off';
}
});
}

const filePath = path.join(process.cwd(), '.sonarrc');

return pify(fs.writeFile)(filePath, JSON.stringify(sonarConfig, null, 4), 'utf8');
};
1 change: 1 addition & 0 deletions src/lib/rules/axe/axe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ const rule: IRuleBuilder = {
recommended: true
},
fixable: 'code',
recommended: true,
schema: [{
additionalProperties: false,
properties: {
Expand Down
1 change: 1 addition & 0 deletions src/lib/rules/disallowed-headers/disallowed-headers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const rule: IRuleBuilder = {
recommended: true
},
fixable: 'code',
recommended: true,
schema: [{
additionalProperties: false,
definitions: {
Expand Down
1 change: 1 addition & 0 deletions src/lib/rules/disown-opener/disown-opener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ const rule: IRuleBuilder = {
recommended: true
},
fixable: 'code',
recommended: true,
schema: [{
additionalProperties: false,
properties: { includeSameOriginURLs: { type: 'boolean' } },
Expand Down
1 change: 1 addition & 0 deletions src/lib/rules/manifest-exists/manifest-exists.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ const rule: IRuleBuilder = {
recommended: true
},
fixable: 'code',
recommended: true,
schema: [],
worksWithLocalFiles: true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const rule: IRuleBuilder = {
recommended: true
},
fixable: 'code',
recommended: true,
schema: [],
worksWithLocalFiles: true
}
Expand Down
1 change: 1 addition & 0 deletions src/lib/rules/manifest-is-valid/manifest-is-valid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const rule: IRuleBuilder = {
recommended: true
},
fixable: 'code',
recommended: true,
schema: [],
worksWithLocalFiles: true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ const rule: IRuleBuilder = {
recommended: true
},
fixable: 'code',
recommended: true,
schema: [],
worksWithLocalFiles: true
}
Expand Down
1 change: 1 addition & 0 deletions src/lib/rules/no-html-only-headers/no-html-only-headers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ const rule: IRuleBuilder = {
recommended: true
},
fixable: 'code',
recommended: true,
schema: [{
additionalProperties: false,
definitions: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ const rule: IRuleBuilder = {
recommended: true
},
fixable: 'code',
recommended: true,
schema: [],
worksWithLocalFiles: true
}
Expand Down
1 change: 1 addition & 0 deletions src/lib/rules/ssllabs/ssllabs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ There might be something wrong with SSL Labs servers.`;
recommended: true
},
fixable: 'none',
recommended: true,
schema: [{
additionalProperties: false,
properties: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const rule: IRuleBuilder = {
recommended: true
},
fixable: 'code',
recommended: true,
schema: [],
worksWithLocalFiles: false
}
Expand Down
2 changes: 2 additions & 0 deletions src/lib/types/rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export interface IRuleBuilder {
docs?: any;
/** If this rule can autofix the issue or not */
fixable?: string;
/** Use this rule to autogenerate the configuration file */
recommended?: boolean;
/** The schema the rule configuration must follow in order to be valid */
schema: Array<any>; // TODO: this shouldn't be an Array of any
/** If the rule works with local resources (file://...) */
Expand Down
6 changes: 6 additions & 0 deletions src/lib/ui/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ export const options = optionator({
option: 'config',
type: 'path::String'
},
{
alias: 'i',
description: 'Generate a configuration file',
option: 'init',
type: 'Boolean'
},
// {
// option: 'env',
// type: '[String]',
Expand Down
10 changes: 10 additions & 0 deletions tests/lib/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const logger = {
};
const validator = { validateConfig() { } };
const config = {
generate() { },
getFilenameForDirectory() { },
load() { }
};
Expand All @@ -45,6 +46,7 @@ test.beforeEach((t) => {
sinon.spy(logger, 'error');
sinon.spy(config, 'getFilenameForDirectory');
sinon.spy(config, 'load');
sinon.stub(config, 'generate').resolves();

t.context.logger = logger;
t.context.config = config;
Expand All @@ -55,6 +57,7 @@ test.afterEach((t) => {
t.context.logger.error.restore();
t.context.config.getFilenameForDirectory.restore();
t.context.config.load.restore();
t.context.config.generate.restore();
});

test.serial('if version option is defined, it should print the current version and return with exit code 0', async (t) => {
Expand All @@ -73,6 +76,13 @@ test.serial('if help option is defined, it should print the help and return with
t.is(exitCode, 0);
});

test.serial('if init option is defined, it should generate the configuration file and return with exit code 0', async (t) => {
const exitCode = await cli.execute('--init');

t.true(t.context.config.generate.calledOnce);
t.is(exitCode, 0);
});

test.serial('if config is not defined, it should get the config file from the directory process.cwd()', async (t) => {
// We just want to test `config.getFilenameForDirectory`. To avoid unneeded stub, we return `false` in `validateConfig`
sinon.stub(validator, 'validateConfig').returns(false);
Expand Down
Loading

0 comments on commit 42dc706

Please sign in to comment.