From 9acd66399a1121b5d5c8dd8a279f2b4eb401b09a Mon Sep 17 00:00:00 2001
From: Sergei Zharinov <zharinov@users.noreply.github.com>
Date: Wed, 29 Jan 2025 14:29:31 -0300
Subject: [PATCH] feat(gradle): Single-version ranges (#33923)

---
 lib/modules/versioning/gradle/compare.ts    | 27 ++++++++++++-
 lib/modules/versioning/gradle/index.spec.ts | 44 +++++++++++----------
 lib/modules/versioning/gradle/index.ts      |  7 ++++
 lib/modules/versioning/maven/index.spec.ts  |  3 ++
 4 files changed, 60 insertions(+), 21 deletions(-)

diff --git a/lib/modules/versioning/gradle/compare.ts b/lib/modules/versioning/gradle/compare.ts
index afc808ef4e..922ba50ff8 100644
--- a/lib/modules/versioning/gradle/compare.ts
+++ b/lib/modules/versioning/gradle/compare.ts
@@ -308,12 +308,37 @@ export function parseMavenBasedRange(input: string): MavenBasedRange | null {
   return null;
 }
 
+interface SingleVersionRange {
+  val: string;
+}
+
+const singleVersionRangeRegex = regEx(/^\[\s*(?<val>[-._+a-zA-Z0-9]*?)\s*\]$/);
+
+export function parseSingleVersionRange(
+  input: string,
+): SingleVersionRange | null {
+  const matchGroups = singleVersionRangeRegex.exec(input)?.groups;
+  if (!matchGroups) {
+    return null;
+  }
+
+  const { val } = matchGroups;
+  if (!isVersion(val)) {
+    return null;
+  }
+
+  return { val };
+}
+
 export function isValid(str: string): boolean {
   if (!str) {
     return false;
   }
 
   return (
-    isVersion(str) || !!parsePrefixRange(str) || !!parseMavenBasedRange(str)
+    isVersion(str) ||
+    !!parsePrefixRange(str) ||
+    !!parseMavenBasedRange(str) ||
+    !!parseSingleVersionRange(str)
   );
 }
diff --git a/lib/modules/versioning/gradle/index.spec.ts b/lib/modules/versioning/gradle/index.spec.ts
index 04be6d5f48..bd42d7fbf1 100644
--- a/lib/modules/versioning/gradle/index.spec.ts
+++ b/lib/modules/versioning/gradle/index.spec.ts
@@ -126,6 +126,8 @@ describe('modules/versioning/gradle/index', () => {
     it.each`
       input                | expected
       ${'1.0.0'}           | ${true}
+      ${'[1.0.0]'}         | ${true}
+      ${'[1..2]'}          | ${false}
       ${'[1.12.6,1.18.6]'} | ${true}
       ${undefined}         | ${false}
     `('isValid("$input") === $expected', ({ input, expected }) => {
@@ -234,26 +236,28 @@ describe('modules/versioning/gradle/index', () => {
 
   describe('matches', () => {
     it.each`
-      version          | range      | expected
-      ${'1'}           | ${'[[]]'}  | ${false}
-      ${'0'}           | ${'[0,1]'} | ${true}
-      ${'1'}           | ${'[0,1]'} | ${true}
-      ${'0'}           | ${'(0,1)'} | ${false}
-      ${'1'}           | ${'(0,1)'} | ${false}
-      ${'1'}           | ${'(0,2)'} | ${true}
-      ${'1'}           | ${'[0,2]'} | ${true}
-      ${'1'}           | ${'(,1]'}  | ${true}
-      ${'1'}           | ${'(,1)'}  | ${false}
-      ${'1'}           | ${'[1,)'}  | ${true}
-      ${'1'}           | ${'(1,)'}  | ${false}
-      ${'0'}           | ${''}      | ${false}
-      ${'1'}           | ${'1'}     | ${true}
-      ${'1.2.3'}       | ${'1.2.+'} | ${true}
-      ${'1.2.3.4'}     | ${'1.2.+'} | ${true}
-      ${'1.3.0'}       | ${'1.2.+'} | ${false}
-      ${'foo'}         | ${'+'}     | ${true}
-      ${'1'}           | ${'+'}     | ${true}
-      ${'99999999999'} | ${'+'}     | ${true}
+      version          | range        | expected
+      ${'1'}           | ${'[[]]'}    | ${false}
+      ${'0'}           | ${'[0,1]'}   | ${true}
+      ${'1'}           | ${'[0,1]'}   | ${true}
+      ${'0'}           | ${'(0,1)'}   | ${false}
+      ${'1'}           | ${'(0,1)'}   | ${false}
+      ${'1'}           | ${'(0,2)'}   | ${true}
+      ${'1'}           | ${'[0,2]'}   | ${true}
+      ${'1'}           | ${'(,1]'}    | ${true}
+      ${'1'}           | ${'(,1)'}    | ${false}
+      ${'1'}           | ${'[1,)'}    | ${true}
+      ${'1'}           | ${'(1,)'}    | ${false}
+      ${'0'}           | ${''}        | ${false}
+      ${'1'}           | ${'1'}       | ${true}
+      ${'1.2.3'}       | ${'1.2.+'}   | ${true}
+      ${'1.2.3.4'}     | ${'1.2.+'}   | ${true}
+      ${'1.3.0'}       | ${'1.2.+'}   | ${false}
+      ${'foo'}         | ${'+'}       | ${true}
+      ${'1'}           | ${'+'}       | ${true}
+      ${'99999999999'} | ${'+'}       | ${true}
+      ${'1.2.3'}       | ${'[1.2.3]'} | ${true}
+      ${'1.2.3'}       | ${'[1.2.4]'} | ${false}
     `(
       'matches("$version", "$range") === $expected',
       ({ version, range, expected }) => {
diff --git a/lib/modules/versioning/gradle/index.ts b/lib/modules/versioning/gradle/index.ts
index b6ef922c4a..6b17ca2a3a 100644
--- a/lib/modules/versioning/gradle/index.ts
+++ b/lib/modules/versioning/gradle/index.ts
@@ -10,6 +10,7 @@ import {
   parse,
   parseMavenBasedRange,
   parsePrefixRange,
+  parseSingleVersionRange,
 } from './compare';
 
 export const id = 'gradle';
@@ -114,6 +115,12 @@ const matches = (a: string, b: string): boolean => {
     return equals(a, b);
   }
 
+  const singleVersionRange = parseSingleVersionRange(b);
+  if (singleVersionRange) {
+    const { val } = singleVersionRange;
+    return equals(a, val);
+  }
+
   const prefixRange = parsePrefixRange(b);
   if (prefixRange) {
     const tokens = prefixRange.tokens;
diff --git a/lib/modules/versioning/maven/index.spec.ts b/lib/modules/versioning/maven/index.spec.ts
index f23b1ce9ab..3507199d9a 100644
--- a/lib/modules/versioning/maven/index.spec.ts
+++ b/lib/modules/versioning/maven/index.spec.ts
@@ -11,6 +11,7 @@ describe('modules/versioning/maven/index', () => {
   it.each`
     version              | expected
     ${'1.0.0'}           | ${true}
+    ${'[1.0.0]'}         | ${true}
     ${'17.0.5+8'}        | ${true}
     ${'[1.12.6,1.18.6]'} | ${true}
     ${undefined}         | ${false}
@@ -119,6 +120,8 @@ describe('modules/versioning/maven/index', () => {
     ${'2.4.2'}       | ${'2.4.2'}                         | ${true}
     ${'2.4.2'}       | ${'= 2.4.2'}                       | ${false}
     ${'1.2.3'}       | ${'[1,2],[3,4]'}                   | ${true}
+    ${'1.2.3'}       | ${'[1.2.3]'}                       | ${true}
+    ${'1.2.3'}       | ${'[1.2.4]'}                       | ${false}
   `(
     'matches("$version", "$range") === $expected',
     ({ version, range, expected }) => {
-- 
GitLab