diff --git a/README.md b/README.md index d792f26..4fb897f 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,14 @@ This will check all commits and will fail if your commits do not meet the define $ sgc check --start 84a1abd ``` +### which-config + +This command shows which configs gets applied to `sgc` + +```sh +$ sgc which-config +``` + ## Config > Just create a `.sgcrc` in your project root or you can add everything in your `package.json` with the value `sgc` diff --git a/__tests__/Config.ts b/__tests__/Config.ts index 08a7524..e75d09f 100644 --- a/__tests__/Config.ts +++ b/__tests__/Config.ts @@ -69,24 +69,37 @@ it('read global config', () => { const sgcrc = json.readToObjSync(path.join(fixtures, '.sgcrc')); fs.writeFileSync(path.join(homedir, '.sgcrc'), JSON.stringify(sgcrc)); - expect(new Config().config).toEqual(sgcrc); + + const { config } = new Config(); + fs.removeSync(path.join(homedir, '.sgcrc')); + + expect(homedir).toBe('test'); + expect(config).toEqual(sgcrc); }); it('read local config from `sgc.config.js`', () => { const sgcrc = json.readToObjSync(path.join(fixtures, '.sgcrc')); fs.writeFileSync(path.join(cwd, 'sgc.config.js'), `module.exports = (${JSON.stringify(sgcrc)})`); - expect(new Config().config).toEqual(sgcrc); + + const { config } = new Config(); + fs.removeSync(path.join(cwd, 'sgc.config.js')); + + expect(config).toEqual(sgcrc); }); it('read global config from `sgc.config.js`', () => { const sgcrc = json.readToObjSync(path.join(fixtures, '.sgcrc')); fs.writeFileSync(path.join(homedir, 'sgc.config.js'), `module.exports = (${JSON.stringify(sgcrc)})`); - expect(new Config().config).toEqual(sgcrc); + + const { config } = new Config(); + fs.removeSync(path.join(homedir, 'sgc.config.js')); + + expect(config).toEqual(sgcrc); }); it('read a .sgcrc_default from a deep nested cwd', () => { @@ -95,3 +108,21 @@ it('read a .sgcrc_default from a deep nested cwd', () => { expect(new Config(deepCwd).config).toEqual(fixturesConfig); }); + +it('should get the right config path', () => { + const sgcrc = json.readToObjSync(path.join(fixtures, '.sgcrc')); + + fs.writeFileSync(path.join(homedir, 'sgc.config.js'), `module.exports = (${JSON.stringify(sgcrc)})`); + + const { configPath } = new Config(); + + fs.removeSync(path.join(homedir, 'sgc.config.js')); + + expect(path.basename(configPath)).toBe('sgc.config.js'); +}); + +it('should get the right config path', () => { + const { configPath } = new Config(); + + expect(path.basename(configPath)).toBe('package.json'); +}); diff --git a/lib/Config.ts b/lib/Config.ts index fcc1a3b..b9329a0 100644 --- a/lib/Config.ts +++ b/lib/Config.ts @@ -33,36 +33,43 @@ export interface SgcConfig { }; } -const safeRequire = (jsPath: string | null): SgcConfig | false => ( - // eslint-disable-next-line global-require, import/no-dynamic-require - jsPath && fs.existsSync(jsPath) && require(jsPath) -); - class Config { - altPath: string | null; + alternativeCwd: string | null; - fileName: string; + sgcConfigName: string; - constructor(altPath: string | null = null, fileName = '.sgcrc') { - this.altPath = altPath; - this.fileName = fileName; + constructor(alternativeCwd: string | null = null, sgcConfigName = '.sgcrc') { + this.alternativeCwd = alternativeCwd; + this.sgcConfigName = sgcConfigName; this.setConfig(); } - private setConfig(): SgcConfig { - const pathString = findup(this.fileName, { cwd: this.altPath || cwd }); - const localeConfigJS = safeRequire(findup('sgc.config.js', { cwd })); - const localeConfig = pathString ? json.readToObjSync(pathString) : false; - const globalConfigJS = safeRequire(path.join(homedir, 'sgc.config.js')); - const globalConfig = json.readToObjSync(path.join(homedir, '.sgcrc')); - const packageJson = findup('package.json', { cwd }); - const packageConfig = packageJson - ? (json.readToObjSync<{ sgc?: SgcConfig }>(packageJson) || {}).sgc - : false; - const sgcrcDefaultConfig = json.readToObjSync(path.join(__dirname, '..', '.sgcrc')) as SgcConfig; - const sgcrcTestDefaultConfig = json.readToObjSync(path.join(__dirname, '..', '.sgcrc_default')) as SgcConfig; - const sgcrcDefault = sgcrcDefaultConfig || sgcrcTestDefaultConfig; + static safeRequire = (jsPath: string | null): SgcConfig | false => ( + // eslint-disable-next-line global-require, import/no-dynamic-require + jsPath && require(jsPath) + ) + + static safeRead = (configPath: string | null): SgcConfig | false => ( + !!configPath && json.readToObjSync(configPath) + ) + + static getPath = (configPath: string | null): string | null => ( + !!configPath && fs.existsSync(configPath) ? configPath : null + ) + + private getConfigPath(): { path: string; defaultPath: string; type: 'rc' | 'js' | 'pkg' } { + // paths + const localPath = Config.getPath(( + findup(this.sgcConfigName, { cwd: this.alternativeCwd || cwd }) + )); + const localJsPath = Config.getPath(findup('sgc.config.js', { cwd })); + const globalPath = Config.getPath(path.join(homedir, this.sgcConfigName)); + const globalJsPath = Config.getPath(path.join(homedir, 'sgc.config.js')); + const packageJson = Config.getPath(findup('package.json', { cwd })); + const defaultPath = Config.getPath(path.join(__dirname, '..', '.sgcrc')) as string; + const testDefaultPath = Config.getPath(path.join(__dirname, '..', '.sgcrc_default')) as string; + const sgcrcDefault = defaultPath || testDefaultPath; // priority order (1. highest priority): // 1. local config @@ -73,13 +80,64 @@ class Config { // 3. default config // - 1. from ../.sgcrc // - 2. test case ../.sgcrc is renamed to ../.sgcrc_default - const config = localeConfigJS - || localeConfig - || packageConfig - || globalConfigJS - || globalConfig + const configPath = localJsPath + || localPath + || packageJson + || globalJsPath + || globalPath || sgcrcDefault; + let type: 'rc' | 'js' | 'pkg'; + + switch (path.extname(configPath)) { + case '.json': + type = 'pkg'; + break; + + case '.js': + type = 'js'; + break; + + default: + type = 'rc'; + break; + } + + return { + path: configPath, + defaultPath: sgcrcDefault, + type, + }; + } + + private setConfig(): SgcConfig { + const configPath = this.getConfigPath(); + const sgcrcDefault: SgcConfig = Config.safeRead(configPath.defaultPath) as SgcConfig; + + let config: SgcConfig = sgcrcDefault; + let readConfig: SgcConfig | false; + + switch (configPath.type) { + case 'js': + readConfig = Config.safeRequire(configPath.path); + break; + + case 'pkg': + readConfig = ( + json.readToObjSync<{ sgc: SgcConfig }>(configPath.path) + || { sgc: false as false } + ).sgc; + break; + + default: + case 'rc': + readConfig = Config.safeRead(configPath.path); + } + + if (readConfig) { + config = readConfig; + } + // set defaults which are necessary const modifiedConfig = merge({}, sgcrcDefault, config); @@ -99,6 +157,10 @@ class Config { public get config(): SgcConfig { return this.setConfig(); } + + public get configPath(): string { + return this.getConfigPath().path; + } } export default Config; diff --git a/lib/index.js b/lib/index.js index 353ae7f..28c357b 100755 --- a/lib/index.js +++ b/lib/index.js @@ -1,11 +1,13 @@ #!/usr/bin/env node import updateNotifier from 'update-notifier'; +import chalk from 'chalk'; import yargs from 'yargs'; import pkg from '../package.json'; import cli from './cli'; import check from './check'; +import Config from './Config'; const { argv } = yargs .usage('Usage: $0') @@ -31,6 +33,11 @@ const { argv } = yargs }, }, check, + ) + .command( + 'which-config', + 'Check which config got applied', + () => console.log('Following config gets used:\n', chalk.bold(new Config().configPath)), ); updateNotifier({ pkg }).notify(); diff --git a/package.json b/package.json index 3238a1f..2eb8c33 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,6 @@ ], "homepage": "https://github.com/JPeer264/node-semantic-git-commit-cli#readme", "devDependencies": { - "@types/chalk": "^2.2.0", "@types/findup-sync": "^2.0.2", "@types/jest": "^25.2.3", "@types/lodash.merge": "^4.6.6", diff --git a/tsconfig.json b/tsconfig.json index 7151dec..1145aed 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,12 +12,13 @@ "esModuleInterop": true, "skipLibCheck": true, "outDir": "dest", - "rootDir": "lib" + "rootDir": "lib", + "typeRoots": [ + "./node_modules/@types", + "./typings" + ] }, "include": [ "lib" - ], - "files": [ - "./global.d.ts" ] } diff --git a/typings/chalk/index.d.ts b/typings/chalk/index.d.ts new file mode 100644 index 0000000..5adfd6d --- /dev/null +++ b/typings/chalk/index.d.ts @@ -0,0 +1 @@ +declare module 'chalk'; diff --git a/global.d.ts b/typings/git-commit-range/index.d.ts similarity index 59% rename from global.d.ts rename to typings/git-commit-range/index.d.ts index f766110..ae3aeb8 100644 --- a/global.d.ts +++ b/typings/git-commit-range/index.d.ts @@ -1,2 +1 @@ declare module 'git-commit-range'; -declare module 'chalk';