Skip to content

Commit

Permalink
Fix: Infinite loop when running the --init command
Browse files Browse the repository at this point in the history
Fix #908
Close #910
  • Loading branch information
sarvaje authored and alrra committed Mar 22, 2018
1 parent f884572 commit f679ad4
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 138 deletions.
46 changes: 22 additions & 24 deletions packages/sonarwhal/src/lib/cli/analyze.ts
@@ -1,5 +1,6 @@
import { promisify } from 'util';
import { URL } from 'url';
import * as path from 'path';

import * as async from 'async';
import * as inquirer from 'inquirer';
Expand All @@ -8,7 +9,7 @@ import * as pluralize from 'pluralize';

import { SonarwhalConfig } from '../config';
import { Sonarwhal } from '../sonarwhal';
import { CLIOptions, ORA, Problem, Severity } from '../types';
import { CLIOptions, ORA, Problem, Severity, UserConfig } from '../types';
import { debug as d } from '../utils/debug';
import { getAsUris } from '../utils/get-as-uri';
import * as logger from '../utils/logging';
Expand Down Expand Up @@ -64,34 +65,22 @@ const askUserToInstallDependencies = async (dependencies: Array<string>): Promis
return answer.confirm;
};

const tryToLoadConfig = async (actions: CLIOptions): Promise<SonarwhalConfig> => {
let config: SonarwhalConfig;
const getUserConfig = (actions: CLIOptions): UserConfig => {
let config: UserConfig;
const configPath: string = actions.config || SonarwhalConfig.getFilenameForDirectory(process.cwd());

if (!configPath) {
logger.error(`Couldn't find a valid path to load the configuration file.`);

const created = await askUserToCreateConfig();

if (created) {
config = await tryToLoadConfig(actions);
}

return config;
return null;
}

debug(`Loading configuration file from ${configPath}.`);
try {
config = SonarwhalConfig.fromFilePath(configPath, actions);
const resolvedPath: string = path.resolve(process.cwd(), configPath);

config = SonarwhalConfig.loadConfigFile(resolvedPath);
} catch (e) {
logger.error(e);

logger.log(`Couldn't load a valid configuration file in ${configPath}.`);
const created = await askUserToCreateConfig();

if (created) {
config = await tryToLoadConfig(actions);
}
config = null;
}

return config;
Expand Down Expand Up @@ -150,14 +139,23 @@ export const analyze = async (actions: CLIOptions): Promise<boolean> => {
return false;
}

const config: SonarwhalConfig = await tryToLoadConfig(actions);
let userConfig: UserConfig = await getUserConfig(actions);

if (!userConfig) {
logger.error(`Couldn't find a valid path to load the configuration file.`);

if (!config) {
logger.error(`Unable to find a valid configuration file. Please add a .sonarwhalrc file by running 'sonarwhal --init'. `);
const created = await askUserToCreateConfig();

return false;
if (created) {
userConfig = await getUserConfig(actions);
} else {
logger.error(`Unable to find a valid configuration file. Please add a .sonarwhalrc file by running 'sonarwhal --init'. `);

return false;
}
}

const config = SonarwhalConfig.fromConfig(userConfig, actions);
const resources = resourceLoader.loadResources(config);

if (resources.missing.length > 0 || resources.incompatible.length > 0) {
Expand Down
41 changes: 24 additions & 17 deletions packages/sonarwhal/src/lib/cli/init.ts
Expand Up @@ -26,6 +26,11 @@ import { NpmPackage } from '../types';
const debug: debug.IDebugger = d(__filename);
const defaultFormatter = 'summary';

type InitUserConfig = {
config: UserConfig;
packages?: Array<string>;
};

/** Validates if the given array is not empty and if so, prints an error message. */
const anyResources = (resources: Array<any>, type: string) => {
if (resources.length > 0) {
Expand All @@ -44,7 +49,7 @@ const getConfigurationName = (pkgName: string): string => {
};

/** Shwos the user a list of official configuration packages available in npm to install. */
const extendConfig = async (): Promise<UserConfig> => {
const extendConfig = async (): Promise<InitUserConfig> => {
const configPackages: Array<NpmPackage> = await getOfficialPackages(ResourceType.configuration);

if (!anyResources(configPackages, ResourceType.configuration)) {
Expand All @@ -68,18 +73,15 @@ const extendConfig = async (): Promise<UserConfig> => {

const answers: inquirer.Answers = await inquirer.prompt(questions);
const sonarwhalConfig = { extends: [getConfigurationName(answers.configuration)] };
const installed = await installPackages([answers.configuration]);

// Maybe there was an error during the installation, the error and message output is handled in the npm package
if (!installed) {
return null;
}

return sonarwhalConfig;
return {
config: sonarwhalConfig,
packages: [answers.configuration]
};
};

/** Prompts a series of questions to create a new configuration object based on the installed packages. */
const customConfig = async (): Promise<UserConfig> => {
const customConfig = async (): Promise<InitUserConfig> => {
const connectorKeys: Array<inquirer.ChoiceType> = getInstalledResources(ResourceType.connector).concat(getCoreResources(ResourceType.connector));
const formattersKeys: Array<inquirer.ChoiceType> = getInstalledResources(ResourceType.formatter).concat(getCoreResources(ResourceType.formatter));
const parsersKeys: Array<inquirer.ChoiceType> = getInstalledResources(ResourceType.parser).concat(getCoreResources(ResourceType.parser));
Expand Down Expand Up @@ -153,7 +155,7 @@ const customConfig = async (): Promise<UserConfig> => {

sonarwhalConfig.browserslist = await generateBrowserslistConfig();

return sonarwhalConfig;
return { config: sonarwhalConfig };
};

/**
Expand All @@ -180,18 +182,23 @@ export const initSonarwhalrc = async (options: CLIOptions): Promise<boolean> =>

const initialAnswer: inquirer.Answers = await inquirer.prompt(initialQuestion);

const sonarwhalConfig = initialAnswer.configType === 'predefined' ?
const result = initialAnswer.configType === 'predefined' ?
await extendConfig() :
await customConfig();

// No resources installed or no configuration packages available, we have to quit
if (!sonarwhalConfig) {
return true;
}

const filePath: string = path.join(process.cwd(), '.sonarwhalrc');

await promisify(fs.writeFile)(filePath, JSON.stringify(sonarwhalConfig, null, 4), 'utf8');
await promisify(fs.writeFile)(filePath, JSON.stringify(result.config, null, 4), 'utf8');

if (Array.isArray(result.packages) && result.packages.length > 0) {
const isInstalled = getInstalledResources(ResourceType.configuration).includes(getConfigurationName(result.packages[0]));

if (isInstalled) {
return true;
}

await installPackages(result.packages);
}

return true;
};
144 changes: 72 additions & 72 deletions packages/sonarwhal/src/lib/config.ts
Expand Up @@ -57,76 +57,6 @@ const loadPackageJSONConfigFile = (filePath: string): UserConfig => {
}
};

/**
* Loads a configuration file regardless of the source. Inspects the file path
* to determine the correctly way to load the config file.
*/
const loadConfigFile = (filePath: string): UserConfig => {

let config: UserConfig;

switch (path.extname(filePath)) {
case '':
case '.json':
if (path.basename(filePath) === 'package.json') {
config = loadPackageJSONConfigFile(filePath);
} else {
config = loadJSONFile(filePath);
}
break;

case '.js':
config = loadJSFile(filePath);
break;

default:
config = null;
}

return config;
};

/**
* Generates the list of browsers to target using the `browserslist` property
* of the `sonarwhal` configuration or `package.json` or uses the default one
*/
const loadBrowsersList = (config: UserConfig) => {
const directory: string = process.cwd();
const files: Array<string> = CONFIG_FILES.reduce((total, configFile) => {
const filename: string = path.join(directory, configFile);

if (shell.test('-f', filename)) {
total.push(filename);
}

return total;
}, []);

if (!config.browserslist) {
for (let i = 0; i < files.length; i++) {
const file: string = files[i];
const tmpConfig: UserConfig = loadConfigFile(file);

if (tmpConfig && tmpConfig.browserslist) {
config.browserslist = tmpConfig.browserslist;
break;
}

if (file.endsWith('package.json')) {
const packagejson = loadJSONFile(file);

config.browserslist = packagejson.browserslist;
}
}
}

if (!config.browserslist || config.browserslist.length === 0) {
return browserslist();
}

return browserslist(config.browserslist);
};

// ------------------------------------------------------------------------

/**
Expand Down Expand Up @@ -218,6 +148,76 @@ export class SonarwhalConfig {
}
}

/**
* Generates the list of browsers to target using the `browserslist` property
* of the `sonarwhal` configuration or `package.json` or uses the default one
*/
public static loadBrowsersList(config: UserConfig) {
const directory: string = process.cwd();
const files: Array<string> = CONFIG_FILES.reduce((total, configFile) => {
const filename: string = path.join(directory, configFile);

if (shell.test('-f', filename)) {
total.push(filename);
}

return total;
}, []);

if (!config.browserslist) {
for (let i = 0; i < files.length; i++) {
const file: string = files[i];
const tmpConfig: UserConfig = SonarwhalConfig.loadConfigFile(file);

if (tmpConfig && tmpConfig.browserslist) {
config.browserslist = tmpConfig.browserslist;
break;
}

if (file.endsWith('package.json')) {
const packagejson = loadJSONFile(file);

config.browserslist = packagejson.browserslist;
}
}
}

if (!config.browserslist || config.browserslist.length === 0) {
return browserslist();
}

return browserslist(config.browserslist);
}


/**
* Loads a configuration file regardless of the source. Inspects the file path
* to determine the correctly way to load the config file.
*/
public static loadConfigFile(filePath: string): UserConfig {
let config: UserConfig;

switch (path.extname(filePath)) {
case '':
case '.json':
if (path.basename(filePath) === 'package.json') {
config = loadPackageJSONConfigFile(filePath);
} else {
config = loadJSONFile(filePath);
}
break;

case '.js':
config = loadJSFile(filePath);
break;

default:
config = null;
}

return config;
}

public static fromConfig(config: UserConfig, actions?: CLIOptions): SonarwhalConfig {

if (!config) {
Expand Down Expand Up @@ -291,10 +291,10 @@ export class SonarwhalConfig {

// 1
const resolvedPath: string = path.resolve(process.cwd(), filePath);
const userConfig = loadConfigFile(resolvedPath);
const userConfig = SonarwhalConfig.loadConfigFile(resolvedPath);
const config = this.fromConfig(userConfig, actions);

userConfig.browserslist = userConfig.browserslist || loadBrowsersList(userConfig);
userConfig.browserslist = userConfig.browserslist || SonarwhalConfig.loadBrowsersList(userConfig);

return config;
}
Expand Down
5 changes: 4 additions & 1 deletion packages/sonarwhal/src/lib/utils/npm.ts
Expand Up @@ -20,6 +20,9 @@ export const installPackages = (packages: Array<string>): boolean => {
let packagePath: string;
/** Current working directory. */
const currentWorkingDir = process.cwd();
/** Wheter or not the process is running in windows */
const isWindows = process.platform === 'win32';

/** Command to install the packages. */
let command: string = `npm install ${packages.join(' ')}`;

Expand Down Expand Up @@ -73,7 +76,7 @@ export const installPackages = (packages: Array<string>): boolean => {
* Show message to install packages manually (maybe permissions error?).
*/
logger.error(`Try executing:
${process.platform !== 'win32' ? 'sudo ' : ''}${command}
${!isWindows && global ? 'sudo ' : ''}${command}
manually to install all the packages.`);
}

Expand Down

0 comments on commit f679ad4

Please sign in to comment.