From ede1a59527a911d3f0b8b492f08b0c563ad192eb Mon Sep 17 00:00:00 2001
From: Rhys Arkins <rhys@keylocation.sg>
Date: Fri, 10 Nov 2017 14:10:16 +0100
Subject: [PATCH] feat: support .renovaterc json configuration file (#1142)

Renovate will now check for `renovate.json`, `.renovaterc`, and `.renovaterc.json` in that order. JSON-only supported (no YAML).

Closes #969
---
 lib/workers/repository/init/config.js         | 31 ++++++++++++-------
 lib/workers/repository/init/index.js          |  4 +--
 .../repository/onboarding/branch/check.js     |  3 +-
 .../init/__snapshots__/config.spec.js.snap    |  6 ++--
 test/workers/repository/init/config.spec.js   | 21 ++++++++++---
 5 files changed, 43 insertions(+), 22 deletions(-)

diff --git a/lib/workers/repository/init/config.js b/lib/workers/repository/init/config.js
index de05174697..9b2db0a2e6 100644
--- a/lib/workers/repository/init/config.js
+++ b/lib/workers/repository/init/config.js
@@ -6,22 +6,31 @@ const { decryptConfig } = require('../../../config/decrypt');
 const presets = require('../../../config/presets');
 
 // Check for config in `renovate.json`
-async function mergeRenovateJson(config) {
+async function mergeRenovateConfig(config) {
   let returnConfig = { ...config };
-  const renovateJsonContent = await platform.getFile('renovate.json');
-  if (!renovateJsonContent) {
-    logger.debug('No renovate.json found');
+  const fileList = await platform.getFileList();
+  let configFile;
+  if (fileList.includes('renovate.json')) {
+    configFile = 'renovate.json';
+  } else if (fileList.includes('.renovaterc')) {
+    configFile = '.renovaterc';
+  } else if (fileList.includes('.renovaterc.json')) {
+    configFile = '.renovaterc.json';
+  }
+  if (!configFile) {
+    logger.debug('No renovate config file found');
     return returnConfig;
   }
-  logger.debug('Found renovate.json file');
+  logger.debug(`Found ${configFile} config file`);
+  const renovateConfig = await platform.getFile(configFile);
   let allowDuplicateKeys = true;
   let jsonValidationError = jsonValidator.validate(
-    renovateJsonContent,
+    renovateConfig,
     allowDuplicateKeys
   );
   if (jsonValidationError) {
     const error = {
-      depName: 'renovate.json',
+      depName: configFile,
       message: jsonValidationError,
     };
     logger.warn(error.message);
@@ -31,19 +40,19 @@ async function mergeRenovateJson(config) {
   }
   allowDuplicateKeys = false;
   jsonValidationError = jsonValidator.validate(
-    renovateJsonContent,
+    renovateConfig,
     allowDuplicateKeys
   );
   if (jsonValidationError) {
     const error = {
-      depName: 'renovate.json',
+      depName: configFile,
       message: jsonValidationError,
     };
     logger.warn(error.message);
     returnConfig.errors.push(error);
     // Return unless error can be ignored
   }
-  const renovateJson = JSON.parse(renovateJsonContent);
+  const renovateJson = JSON.parse(renovateConfig);
   logger.debug({ config: renovateJson }, 'renovate.json config');
   const migratedConfig = migrateAndValidate(config, renovateJson);
   logger.debug({ config: migratedConfig }, 'renovate.json migrated config');
@@ -56,5 +65,5 @@ async function mergeRenovateJson(config) {
 }
 
 module.exports = {
-  mergeRenovateJson,
+  mergeRenovateConfig,
 };
diff --git a/lib/workers/repository/init/index.js b/lib/workers/repository/init/index.js
index d2fa4c196a..4fd2c2e5ad 100644
--- a/lib/workers/repository/init/index.js
+++ b/lib/workers/repository/init/index.js
@@ -2,12 +2,12 @@ const { checkOnboardingBranch } = require('../onboarding/branch');
 const { checkIfConfigured } = require('../configured');
 
 const { checkBaseBranch } = require('./base');
-const { mergeRenovateJson } = require('./config');
+const { mergeRenovateConfig } = require('./config');
 
 async function initRepo(input) {
   let config = { ...input, errors: [], warnings: [] };
   config = await checkOnboardingBranch(config);
-  config = await mergeRenovateJson(config);
+  config = await mergeRenovateConfig(config);
   checkIfConfigured(config);
   await checkBaseBranch(config);
   return config;
diff --git a/lib/workers/repository/onboarding/branch/check.js b/lib/workers/repository/onboarding/branch/check.js
index 48ef51e846..d345e8e1d9 100644
--- a/lib/workers/repository/onboarding/branch/check.js
+++ b/lib/workers/repository/onboarding/branch/check.js
@@ -5,7 +5,8 @@ const findFile = async (config, fileName) => {
   return fileList.includes(fileName);
 };
 
-const renovateJsonExists = config => findFile(config, 'renovate.json');
+const renovateJsonExists = async config =>
+  (await findFile(config, 'renovate.json')) || findFile(config, '.renovaterc');
 
 const closedPrExists = config =>
   platform.findPr(
diff --git a/test/workers/repository/init/__snapshots__/config.spec.js.snap b/test/workers/repository/init/__snapshots__/config.spec.js.snap
index 17c4c467fa..612e2d5005 100644
--- a/test/workers/repository/init/__snapshots__/config.spec.js.snap
+++ b/test/workers/repository/init/__snapshots__/config.spec.js.snap
@@ -1,15 +1,15 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`workers/repository/init/config mergeRenovateJson() returns error if cannot parse 1`] = `
+exports[`workers/repository/init/config mergeRenovateConfig() returns error if cannot parse 1`] = `
 Object {
   "depName": "renovate.json",
   "message": "Syntax error near cannot par",
 }
 `;
 
-exports[`workers/repository/init/config mergeRenovateJson() returns error if duplicate keys 1`] = `
+exports[`workers/repository/init/config mergeRenovateConfig() returns error if duplicate keys 1`] = `
 Object {
-  "depName": "renovate.json",
+  "depName": ".renovaterc",
   "message": "Syntax error: duplicated keys \\"enabled\\" near \\": false }",
 }
 `;
diff --git a/test/workers/repository/init/config.spec.js b/test/workers/repository/init/config.spec.js
index 8edf2a1d1a..90d9f97917 100644
--- a/test/workers/repository/init/config.spec.js
+++ b/test/workers/repository/init/config.spec.js
@@ -7,26 +7,37 @@ beforeEach(() => {
 });
 
 const {
-  mergeRenovateJson,
+  mergeRenovateConfig,
 } = require('../../../../lib/workers/repository/init/config');
 
 describe('workers/repository/init/config', () => {
-  describe('mergeRenovateJson()', () => {
+  describe('mergeRenovateConfig()', () => {
     it('returns config if not found', async () => {
-      const res = await mergeRenovateJson(config);
+      platform.getFileList.mockReturnValue(['package.json']);
+      const res = await mergeRenovateConfig(config);
       expect(res).toMatchObject(config);
     });
     it('returns error if cannot parse', async () => {
+      platform.getFileList.mockReturnValue(['package.json', 'renovate.json']);
       platform.getFile.mockReturnValue('cannot parse');
-      const res = await mergeRenovateJson(config);
+      const res = await mergeRenovateConfig(config);
       expect(res.errors).toHaveLength(1);
       expect(res.errors[0]).toMatchSnapshot();
     });
     it('returns error if duplicate keys', async () => {
+      platform.getFileList.mockReturnValue(['package.json', '.renovaterc']);
       platform.getFile.mockReturnValue('{ "enabled": true, "enabled": false }');
-      const res = await mergeRenovateJson(config);
+      const res = await mergeRenovateConfig(config);
       expect(res.errors).toHaveLength(1);
       expect(res.errors[0]).toMatchSnapshot();
     });
+    it('finds .renovaterc.json', async () => {
+      platform.getFileList.mockReturnValue([
+        'package.json',
+        '.renovaterc.json',
+      ]);
+      platform.getFile.mockReturnValue('{}');
+      await mergeRenovateConfig(config);
+    });
   });
 });
-- 
GitLab