From 0cef0e9f94acab1c1615a4d7e190c1a57f9e0ea0 Mon Sep 17 00:00:00 2001
From: Cedric van Putten <me@bycedric.com>
Date: Sun, 7 Oct 2018 16:41:01 +0200
Subject: [PATCH 1/3] fix(cli): improve format module resolving

---
 .../custom-formatter/formatters/custom.js     |  3 +++
 @commitlint/cli/package.json                  |  4 +++-
 @commitlint/cli/src/cli.js                    | 20 +++++++++++++------
 @commitlint/cli/src/cli.test.js               | 17 ++++++++++++++++
 4 files changed, 37 insertions(+), 7 deletions(-)
 create mode 100644 @commitlint/cli/fixtures/custom-formatter/formatters/custom.js

diff --git a/@commitlint/cli/fixtures/custom-formatter/formatters/custom.js b/@commitlint/cli/fixtures/custom-formatter/formatters/custom.js
new file mode 100644
index 0000000000..96b56d55e4
--- /dev/null
+++ b/@commitlint/cli/fixtures/custom-formatter/formatters/custom.js
@@ -0,0 +1,3 @@
+module.exports = function (report) {
+	return 'custom-formatter-ok';
+}
diff --git a/@commitlint/cli/package.json b/@commitlint/cli/package.json
index a14eadc457..6a5ad310c9 100644
--- a/@commitlint/cli/package.json
+++ b/@commitlint/cli/package.json
@@ -84,6 +84,8 @@
     "get-stdin": "5.0.1",
     "lodash.merge": "4.6.1",
     "lodash.pick": "4.4.0",
-    "meow": "5.0.0"
+    "meow": "5.0.0",
+    "resolve-from": "^4.0.0",
+    "resolve-global": "^0.1.0"
   }
 }
diff --git a/@commitlint/cli/src/cli.js b/@commitlint/cli/src/cli.js
index 55607fc82b..9afdeb69d8 100755
--- a/@commitlint/cli/src/cli.js
+++ b/@commitlint/cli/src/cli.js
@@ -8,6 +8,8 @@ const meow = require('meow');
 const merge = require('lodash.merge');
 const pick = require('lodash.pick');
 const stdin = require('get-stdin');
+const resolveFrom = require('resolve-from');
+const resolveGlobal = require('resolve-global');
 
 const pkg = require('../package');
 const help = require('./help');
@@ -260,17 +262,23 @@ function selectParserOpts(parserPreset) {
 	return parserPreset.parserOpts;
 }
 
+function resolveModulePath(name, cwd) {
+	try {
+		return require.resolve(name);
+	} catch (error) {
+		return resolveFrom.silent(cwd, name) || resolveGlobal.silent(name);
+	}
+}
+
 function loadFormatter(config, flags) {
 	const moduleName = flags.format || config.formatter;
-	let modulePath;
+	const modulePath = moduleName && resolveModulePath(moduleName, flags.cwd);
 
-	try {
-		modulePath = require.resolve(`${moduleName}`);
-	} catch (error) {
-		throw new Error(`Using format ${moduleName}, but cannot find the module.`);
+	if (modulePath) {
+		return require(modulePath);
 	}
 
-	return require(modulePath);
+	throw new Error(`Using format ${moduleName}, but cannot find the module.`);
 }
 
 // Catch unhandled rejections globally
diff --git a/@commitlint/cli/src/cli.test.js b/@commitlint/cli/src/cli.test.js
index 3c5eb36cbb..94de3faf65 100644
--- a/@commitlint/cli/src/cli.test.js
+++ b/@commitlint/cli/src/cli.test.js
@@ -263,6 +263,23 @@ test('should fail for invalid formatters from flags', async t => {
 	t.is(actual.code, 1);
 });
 
+test('should work with absolute formatter path', async t => {
+	const formatterPath = path.resolve(__dirname, '../fixtures/custom-formatter/formatters/custom.js');
+	const cwd = await git.bootstrap('fixtures/custom-formatter');
+	const actual = await cli(['--format', formatterPath], {cwd})('test: this should work');
+
+	t.true(actual.stdout.includes('custom-formatter-ok'));
+	t.is(actual.code, 0);
+});
+
+test('should work with relative formatter path', async t => {
+	const cwd = path.resolve(await git.bootstrap('fixtures/custom-formatter'), './formatters');
+	const actual = await cli(['--format', './custom.js'], {cwd})('test: this should work');
+
+	t.true(actual.stdout.includes('custom-formatter-ok'));
+	t.is(actual.code, 0);
+});
+
 async function writePkg(payload, options) {
 	const pkgPath = path.join(options.cwd, 'package.json');
 	const pkg = JSON.parse(await sander.readFile(pkgPath));

From 2a2e6b518333598bd93966c76630f7345cd7e462 Mon Sep 17 00:00:00 2001
From: Cedric van Putten <me@bycedric.com>
Date: Mon, 8 Oct 2018 17:36:16 +0200
Subject: [PATCH 2/3] fix(load): resolve formatter module from config dir if
 available

---
 .../commitlint.config.js                      |  3 +++
 .../formatters/custom.js                      |  3 +++
 @commitlint/load/src/index.js                 |  5 ++++
 @commitlint/load/src/index.test.js            | 23 +++++++++++++++++++
 4 files changed, 34 insertions(+)
 create mode 100644 @commitlint/load/fixtures/formatter-local-module/commitlint.config.js
 create mode 100644 @commitlint/load/fixtures/formatter-local-module/formatters/custom.js

diff --git a/@commitlint/load/fixtures/formatter-local-module/commitlint.config.js b/@commitlint/load/fixtures/formatter-local-module/commitlint.config.js
new file mode 100644
index 0000000000..1d62bb6ee7
--- /dev/null
+++ b/@commitlint/load/fixtures/formatter-local-module/commitlint.config.js
@@ -0,0 +1,3 @@
+module.exports = {
+	formatter: './formatters/custom.js'
+};
diff --git a/@commitlint/load/fixtures/formatter-local-module/formatters/custom.js b/@commitlint/load/fixtures/formatter-local-module/formatters/custom.js
new file mode 100644
index 0000000000..7fb04a7d0c
--- /dev/null
+++ b/@commitlint/load/fixtures/formatter-local-module/formatters/custom.js
@@ -0,0 +1,3 @@
+module.exports = function (report) {
+	return 'ok';
+}
diff --git a/@commitlint/load/src/index.js b/@commitlint/load/src/index.js
index 2f13f54d51..f7b900f9ca 100644
--- a/@commitlint/load/src/index.js
+++ b/@commitlint/load/src/index.js
@@ -52,6 +52,11 @@ export default async (seed = {}, options = {cwd: process.cwd()}) => {
 			.parserOpts).parserOpts;
 	}
 
+	// Resolve config-relative formatter module
+	if (typeof config.formatter === 'string') {
+		preset.formatter = resolveFrom.silent(base, config.formatter) || config.formatter;
+	}
+
 	// Execute rule config functions if needed
 	const executed = await Promise.all(
 		['rules']
diff --git a/@commitlint/load/src/index.test.js b/@commitlint/load/src/index.test.js
index 052d42a2e1..854fa0f3b2 100644
--- a/@commitlint/load/src/index.test.js
+++ b/@commitlint/load/src/index.test.js
@@ -1,6 +1,7 @@
 import path from 'path';
 import {fix, git} from '@commitlint/test';
 import test from 'ava';
+import resolveFrom from 'resolve-from';
 
 import load from '.';
 
@@ -233,3 +234,25 @@ test('respects formatter option', async t => {
 		rules: {}
 	});
 });
+
+test('resolves formatter relative from config directory', async t => {
+	const cwd = await git.bootstrap('fixtures/formatter-local-module');
+	const actual = await load({}, {cwd});
+
+	t.deepEqual(actual, {
+		formatter: resolveFrom(cwd, './formatters/custom.js'),
+		extends: [],
+		rules: {}
+	});
+});
+
+test('returns formatter name when unable to resolve from config directory', async t => {
+	const cwd = await git.bootstrap('fixtures/formatter-local-module');
+	const actual = await load({formatter: './doesnt/exists.js'}, {cwd});
+
+	t.deepEqual(actual, {
+		formatter: './doesnt/exists.js',
+		extends: [],
+		rules: {}
+	});
+});

From b05ef68fe4f53041c131b783d7a1d16131fc7edd Mon Sep 17 00:00:00 2001
From: Cedric van Putten <me@bycedric.com>
Date: Tue, 9 Oct 2018 20:43:10 +0200
Subject: [PATCH 3/3] fix(cli): replace try catch resolve with silent resolve
 from

---
 @commitlint/cli/src/cli.js | 13 ++++---------
 1 file changed, 4 insertions(+), 9 deletions(-)

diff --git a/@commitlint/cli/src/cli.js b/@commitlint/cli/src/cli.js
index 9afdeb69d8..a82724f2b3 100755
--- a/@commitlint/cli/src/cli.js
+++ b/@commitlint/cli/src/cli.js
@@ -262,17 +262,12 @@ function selectParserOpts(parserPreset) {
 	return parserPreset.parserOpts;
 }
 
-function resolveModulePath(name, cwd) {
-	try {
-		return require.resolve(name);
-	} catch (error) {
-		return resolveFrom.silent(cwd, name) || resolveGlobal.silent(name);
-	}
-}
-
 function loadFormatter(config, flags) {
 	const moduleName = flags.format || config.formatter;
-	const modulePath = moduleName && resolveModulePath(moduleName, flags.cwd);
+	const modulePath =
+		resolveFrom.silent(__dirname, moduleName) ||
+		resolveFrom.silent(flags.cwd, moduleName) ||
+		resolveGlobal.silent(moduleName);
 
 	if (modulePath) {
 		return require(modulePath);