From 8c2cad0647ffa588bb95413ef63f70e4f4978517 Mon Sep 17 00:00:00 2001
From: Rhys Arkins <rhys@arkins.net>
Date: Tue, 11 Dec 2018 12:55:12 +0100
Subject: [PATCH] feat: packageRules>languages
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Adds new filter option “languages” to packageRules to filter on language time.
---
 lib/config/definitions.js                     | 12 ++++++
 lib/config/validation.js                      |  1 +
 lib/util/package-rules.js                     |  8 ++++
 .../__snapshots__/validation.spec.js.snap     |  2 +-
 test/util/package-rules.spec.js               | 38 +++++++++++++++++++
 website/docs/configuration-options.md         | 12 ++++++
 6 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/lib/config/definitions.js b/lib/config/definitions.js
index df9e7bf6c7..7bab0bc3a0 100644
--- a/lib/config/definitions.js
+++ b/lib/config/definitions.js
@@ -372,6 +372,18 @@ const options = [
     cli: false,
     env: false,
   },
+  {
+    name: 'languages',
+    description:
+      'List of languages to match (e.g. ["pipenv"]). Valid only within `packageRules` object',
+    type: 'list',
+    allowString: true,
+    parent: 'packageRules',
+    stage: 'package',
+    mergeable: true,
+    cli: false,
+    env: false,
+  },
   {
     name: 'managers',
     description:
diff --git a/lib/config/validation.js b/lib/config/validation.js
index a460f7927a..fe52a24ba7 100644
--- a/lib/config/validation.js
+++ b/lib/config/validation.js
@@ -133,6 +133,7 @@ async function validateConfig(config, isPreset, parentPath) {
 
             const selectors = [
               'paths',
+              'languages',
               'managers',
               'depTypeList',
               'packageNames',
diff --git a/lib/util/package-rules.js b/lib/util/package-rules.js
index 6776d3a48c..c373647e1b 100644
--- a/lib/util/package-rules.js
+++ b/lib/util/package-rules.js
@@ -19,6 +19,7 @@ function applyPackageRules(inputConfig) {
     updateType,
     isBump,
     sourceUrl,
+    language,
     manager,
   } = config;
   const packageRules = config.packageRules || [];
@@ -29,6 +30,7 @@ function applyPackageRules(inputConfig) {
   packageRules.forEach(packageRule => {
     let {
       paths,
+      languages,
       managers,
       depTypeList,
       packageNames,
@@ -41,6 +43,7 @@ function applyPackageRules(inputConfig) {
     } = packageRule;
     // Setting empty arrays simplifies our logic later
     paths = paths || [];
+    languages = languages || [];
     managers = managers || [];
     depTypeList = depTypeList || [];
     packageNames = packageNames || [];
@@ -72,6 +75,11 @@ function applyPackageRules(inputConfig) {
       positiveMatch = positiveMatch || isMatch;
       negativeMatch = negativeMatch || !isMatch;
     }
+    if (languages.length) {
+      const isMatch = languages.includes(language);
+      positiveMatch = positiveMatch || isMatch;
+      negativeMatch = negativeMatch || !isMatch;
+    }
     if (managers.length) {
       const isMatch = managers.includes(manager);
       positiveMatch = positiveMatch || isMatch;
diff --git a/test/config/__snapshots__/validation.spec.js.snap b/test/config/__snapshots__/validation.spec.js.snap
index 4067efa7f9..b7240fe9ac 100644
--- a/test/config/__snapshots__/validation.spec.js.snap
+++ b/test/config/__snapshots__/validation.spec.js.snap
@@ -44,7 +44,7 @@ Array [
   },
   Object {
     "depName": "Configuration Error",
-    "message": "packageRules: Each packageRule must contain at least one selector (paths, depTypeList, packageNames, packagePatterns, excludePackageNames, excludePackagePatterns, sourceUrlPrefixes, updateTypes). If you wish for configuration to apply to all packages, it is not necessary to place it inside a packageRule at all.",
+    "message": "packageRules: Each packageRule must contain at least one selector (paths, languages, managers, depTypeList, packageNames, packagePatterns, excludePackageNames, excludePackagePatterns, sourceUrlPrefixes, updateTypes). If you wish for configuration to apply to all packages, it is not necessary to place it inside a packageRule at all.",
   },
   Object {
     "depName": "Configuration Error",
diff --git a/test/util/package-rules.spec.js b/test/util/package-rules.spec.js
index 7b00dd2e08..0f195024c9 100644
--- a/test/util/package-rules.spec.js
+++ b/test/util/package-rules.spec.js
@@ -158,6 +158,44 @@ describe('applyPackageRules()', () => {
     const res = applyPackageRules({ ...config, ...dep });
     expect(res.x).toBeUndefined();
   });
+  it('filters languages with matching language', () => {
+    const config = {
+      packageRules: [
+        {
+          languages: ['js', 'node'],
+          packageNames: ['node'],
+          x: 1,
+        },
+      ],
+    };
+    const dep = {
+      depType: 'dependencies',
+      language: 'js',
+      manager: 'meteor',
+      depName: 'node',
+    };
+    const res = applyPackageRules({ ...config, ...dep });
+    expect(res.x).toBe(1);
+  });
+  it('filters languages with non-matching language', () => {
+    const config = {
+      packageRules: [
+        {
+          languages: ['docker'],
+          packageNames: ['node'],
+          x: 1,
+        },
+      ],
+    };
+    const dep = {
+      depType: 'dependencies',
+      language: 'python',
+      manager: 'pipenv',
+      depName: 'node',
+    };
+    const res = applyPackageRules({ ...config, ...dep });
+    expect(res.x).toBeUndefined();
+  });
   it('filters updateType', () => {
     const config = {
       packageRules: [
diff --git a/website/docs/configuration-options.md b/website/docs/configuration-options.md
index ce70d758ce..1d77018466 100644
--- a/website/docs/configuration-options.md
+++ b/website/docs/configuration-options.md
@@ -509,6 +509,18 @@ Use this field if you want to have one or more package name patterns excluded in
 
 The above will match all package names starting with `eslint` but exclude ones starting with `eslint-foo`.
 
+### languages
+
+Use this field to restrict rules to a particular language. e.g.
+
+```
+  "packageRules": [{
+    "packageNames": ["request"],
+    "managers": ["python"],
+    "enabled": false
+  }]
+```
+
 ### managers
 
 Use this field to restrict rules to a particular package manager. e.g.
-- 
GitLab