From c2eb51df544aed22011eca2771beaa3715f3db35 Mon Sep 17 00:00:00 2001
From: Rhys Arkins <rhys@arkins.net>
Date: Mon, 17 Sep 2018 10:55:27 +0200
Subject: [PATCH] feat(npm): support long git references

Part of #415
---
 lib/manager/npm/extract/index.js              | 11 +++---
 .../npm/__snapshots__/update.spec.js.snap     |  2 ++
 .../extract/__snapshots__/index.spec.js.snap  | 34 +++++++++++++++++++
 test/manager/npm/extract/index.spec.js        |  4 +++
 test/manager/npm/update.spec.js               | 17 ++++++++++
 5 files changed, 62 insertions(+), 6 deletions(-)

diff --git a/lib/manager/npm/extract/index.js b/lib/manager/npm/extract/index.js
index 9922890cc5..639fdabc31 100644
--- a/lib/manager/npm/extract/index.js
+++ b/lib/manager/npm/extract/index.js
@@ -153,12 +153,11 @@ async function extractDependencies(content, fileName, config) {
       return dep;
     }
     const [depNamePart, depRefPart] = hashSplit;
-    const depNamePartSplit = depNamePart.split(':');
-    if (depNamePartSplit.length === 2 && depNamePartSplit[0] !== 'github') {
-      dep.skipReason = 'unknown-version';
-      return dep;
-    }
-    const githubOwnerRepo = depNamePart.replace('github:', '');
+    const githubOwnerRepo = depNamePart
+      .replace(/^github:/, '')
+      .replace(/^git\+/, '')
+      .replace(/^https:\/\/github\.com\//, '')
+      .replace(/\.git$/, '');
     const githubRepoSplit = githubOwnerRepo.split('/');
     if (githubRepoSplit.length !== 2) {
       dep.skipReason = 'unknown-version';
diff --git a/test/manager/npm/__snapshots__/update.spec.js.snap b/test/manager/npm/__snapshots__/update.spec.js.snap
index f7cdd98658..62a8a6473e 100644
--- a/test/manager/npm/__snapshots__/update.spec.js.snap
+++ b/test/manager/npm/__snapshots__/update.spec.js.snap
@@ -5,3 +5,5 @@ exports[`workers/branch/package-json .bumpPackageVersion() increments 1`] = `"{\
 exports[`workers/branch/package-json .bumpPackageVersion() updates 1`] = `"{\\"name\\":\\"some-package\\",\\"version\\":\\"0.1.0\\"}"`;
 
 exports[`workers/branch/package-json .updateDependency(fileContent, depType, depName, newValue) replaces a github dependency value 1`] = `"{\\"dependencies\\":{\\"gulp\\":\\"gulpjs/gulp#v4.0.0\\"}}"`;
+
+exports[`workers/branch/package-json .updateDependency(fileContent, depType, depName, newValue) replaces a github fully specified version 1`] = `"{\\"dependencies\\":{\\"n\\":\\"git+https://github.com/owner/n#v1.1.0\\"}}"`;
diff --git a/test/manager/npm/extract/__snapshots__/index.spec.js.snap b/test/manager/npm/extract/__snapshots__/index.spec.js.snap
index 9d96c34eb2..f08a8bf20f 100644
--- a/test/manager/npm/extract/__snapshots__/index.spec.js.snap
+++ b/test/manager/npm/extract/__snapshots__/index.spec.js.snap
@@ -194,6 +194,40 @@ Object {
       "skipReason": "unknown-version",
       "versionScheme": "semver",
     },
+    Object {
+      "currentValue": "github:owner/k#49b5aca",
+      "depName": "k",
+      "depType": "dependencies",
+      "prettyDepType": "dependency",
+      "skipReason": "unversioned-reference",
+      "versionScheme": "semver",
+    },
+    Object {
+      "currentValue": "github:owner/l.git#abcdef0",
+      "depName": "l",
+      "depType": "dependencies",
+      "prettyDepType": "dependency",
+      "skipReason": "unversioned-reference",
+      "versionScheme": "semver",
+    },
+    Object {
+      "currentRawValue": "https://github.com/owner/m.git#v1.0.0",
+      "currentValue": "v1.0.0",
+      "depName": "m",
+      "depType": "dependencies",
+      "prettyDepType": "dependency",
+      "purl": "pkg:github/owner/m?ref=tags",
+      "versionScheme": "semver",
+    },
+    Object {
+      "currentRawValue": "git+https://github.com/owner/n#v2.0.0",
+      "currentValue": "v2.0.0",
+      "depName": "n",
+      "depType": "dependencies",
+      "prettyDepType": "dependency",
+      "purl": "pkg:github/owner/n?ref=tags",
+      "versionScheme": "semver",
+    },
   ],
   "lernaClient": undefined,
   "lernaDir": undefined,
diff --git a/test/manager/npm/extract/index.spec.js b/test/manager/npm/extract/index.spec.js
index 669959b1a5..dc667d165c 100644
--- a/test/manager/npm/extract/index.spec.js
+++ b/test/manager/npm/extract/index.spec.js
@@ -183,6 +183,10 @@ describe('manager/npm/extract', () => {
           h: 'github:-hello/world#v1.0.0',
           i: '@foo/bar#v2.0.0',
           j: 'github:frank#v0.0.1',
+          k: 'github:owner/k#49b5aca',
+          l: 'github:owner/l.git#abcdef0',
+          m: 'https://github.com/owner/m.git#v1.0.0',
+          n: 'git+https://github.com/owner/n#v2.0.0',
         },
       };
       const pJsonStr = JSON.stringify(pJson);
diff --git a/test/manager/npm/update.spec.js b/test/manager/npm/update.spec.js
index da950ef844..93fc10fe28 100644
--- a/test/manager/npm/update.spec.js
+++ b/test/manager/npm/update.spec.js
@@ -40,6 +40,23 @@ describe('workers/branch/package-json', () => {
       const res = npmUpdater.updateDependency(input, upgrade);
       expect(res).toMatchSnapshot();
     });
+    it('replaces a github fully specified version', () => {
+      const upgrade = {
+        depType: 'dependencies',
+        depName: 'n',
+        currentValue: 'v1.0.0',
+        currentRawValue: 'git+https://github.com/owner/n#v1.0.0',
+        newValue: 'v1.1.0',
+      };
+      const input = JSON.stringify({
+        dependencies: {
+          n: 'git+https://github.com/owner/n#v1.0.0',
+        },
+      });
+      const res = npmUpdater.updateDependency(input, upgrade);
+      expect(res).toMatchSnapshot();
+      expect(res.includes('v1.1.0')).toBe(true);
+    });
     it('updates resolutions too', () => {
       const upgrade = {
         depType: 'dependencies',
-- 
GitLab