From 8dfb34bf4f085a7cedb704d16ce8a5dbb6b681eb Mon Sep 17 00:00:00 2001
From: Andreas Fehn <fehnomenal@fehn.systems>
Date: Sat, 20 Jul 2024 13:27:12 +0200
Subject: [PATCH] feat(npm): handle github dependencies with semver versions
 (#28261)

---
 .../extract/__snapshots__/index.spec.ts.snap  | 26 +++++++++++++++++++
 .../manager/npm/extract/common/dependency.ts  | 18 +++++++++++--
 lib/modules/manager/npm/extract/index.spec.ts | 14 ++++++++++
 3 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap b/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap
index 9100d9c208..9e051b4110 100644
--- a/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap
@@ -312,6 +312,32 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() extracts non-np
       "sourceUrl": "https://github.com/Owner/P",
       "versioning": "npm",
     },
+    {
+      "currentRawValue": "github:owner/q#semver:1.1.0",
+      "currentValue": "1.1.0",
+      "datasource": "github-tags",
+      "depName": "q",
+      "depType": "dependencies",
+      "gitRef": true,
+      "packageName": "owner/q",
+      "pinDigests": false,
+      "prettyDepType": "dependency",
+      "sourceUrl": "https://github.com/owner/q",
+      "versioning": "npm",
+    },
+    {
+      "currentRawValue": "github:owner/r#semver:^1.0.0",
+      "currentValue": "^1.0.0",
+      "datasource": "github-tags",
+      "depName": "r",
+      "depType": "dependencies",
+      "gitRef": true,
+      "packageName": "owner/r",
+      "pinDigests": false,
+      "prettyDepType": "dependency",
+      "sourceUrl": "https://github.com/owner/r",
+      "versioning": "npm",
+    },
   ],
   "extractedConstraints": {},
   "managerData": {
diff --git a/lib/modules/manager/npm/extract/common/dependency.ts b/lib/modules/manager/npm/extract/common/dependency.ts
index 7ee3740330..04ce25d038 100644
--- a/lib/modules/manager/npm/extract/common/dependency.ts
+++ b/lib/modules/manager/npm/extract/common/dependency.ts
@@ -181,8 +181,22 @@ export function extractDependency(
     dep.versioning = npmVersioningId;
     dep.packageName = githubOwnerRepo;
   } else {
-    dep.skipReason = 'unversioned-reference';
-    return dep;
+    // <protocol>://[<user>[:<password>]@]<hostname>[:<port>][:][/]<path>[#<commit-ish> | #semver:<semver>]
+    // https://docs.npmjs.com/cli/v10/configuring-npm/package-json#git-urls-as-dependencies
+    const len = 7; // length of 'semver:'
+    const maybeVersion = depRefPart.substring(len);
+
+    if (depRefPart.startsWith('semver:') && isValid(maybeVersion)) {
+      dep.currentRawValue = dep.currentValue;
+      dep.currentValue = maybeVersion;
+      dep.datasource = GithubTagsDatasource.id;
+      dep.versioning = npmVersioningId;
+      dep.packageName = githubOwnerRepo;
+      dep.pinDigests = false;
+    } else {
+      dep.skipReason = 'unversioned-reference';
+      return dep;
+    }
   }
   dep.sourceUrl = `https://github.com/${githubOwnerRepo}`;
   dep.gitRef = true;
diff --git a/lib/modules/manager/npm/extract/index.spec.ts b/lib/modules/manager/npm/extract/index.spec.ts
index 032faf0a18..cd9de9df44 100644
--- a/lib/modules/manager/npm/extract/index.spec.ts
+++ b/lib/modules/manager/npm/extract/index.spec.ts
@@ -594,6 +594,8 @@ describe('modules/manager/npm/extract/index', () => {
           n: 'git+https://github.com/owner/n#v2.0.0',
           o: 'git@github.com:owner/o.git#v2.0.0',
           p: 'Owner/P.git#v2.0.0',
+          q: 'github:owner/q#semver:1.1.0',
+          r: 'github:owner/r#semver:^1.0.0',
         },
       };
       const pJsonStr = JSON.stringify(pJson);
@@ -691,6 +693,18 @@ describe('modules/manager/npm/extract/index', () => {
             datasource: 'github-tags',
             sourceUrl: 'https://github.com/Owner/P',
           },
+          {
+            depName: 'q',
+            currentValue: '1.1.0',
+            datasource: 'github-tags',
+            sourceUrl: 'https://github.com/owner/q',
+          },
+          {
+            depName: 'r',
+            currentValue: '^1.0.0',
+            datasource: 'github-tags',
+            sourceUrl: 'https://github.com/owner/r',
+          },
         ],
       });
     });
-- 
GitLab