From bc8e06e1d074ae6d51761e510343277fa2b91a93 Mon Sep 17 00:00:00 2001
From: Sergei Zharinov <zharinov@users.noreply.github.com>
Date: Fri, 16 Jun 2023 22:05:18 +0300
Subject: [PATCH] refactor(rubygems): Decouple metadata fetching from versions
 fetching (#22808)

Co-authored-by: lluiscab <lluiscab@gmail.com>
Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com>
Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
Co-authored-by: Rhys Arkins <rhys@arkins.net>
Co-authored-by: t-kulmburg <89128736+t-kulmburg@users.noreply.github.com>
Co-authored-by: Victor Engmark <victor@engmark.name>
---
 lib/modules/datasource/rubygems/index.ts  | 92 +++++++++++++----------
 lib/modules/datasource/rubygems/schema.ts |  6 +-
 2 files changed, 54 insertions(+), 44 deletions(-)

diff --git a/lib/modules/datasource/rubygems/index.ts b/lib/modules/datasource/rubygems/index.ts
index 2e343608c0..fa39a49e91 100644
--- a/lib/modules/datasource/rubygems/index.ts
+++ b/lib/modules/datasource/rubygems/index.ts
@@ -6,7 +6,7 @@ import { getQueryString, joinUrlParts, parseUrl } from '../../../util/url';
 import * as rubyVersioning from '../../versioning/ruby';
 import { Datasource } from '../datasource';
 import type { GetReleasesConfig, Release, ReleaseResult } from '../types';
-import { GemVersions, GemsInfo, MarshalledVersionInfo } from './schema';
+import { GemMetadata, GemVersions, MarshalledVersionInfo } from './schema';
 import { VersionsEndpointCache } from './versions-endpoint-cache';
 
 export class RubyGemsDatasource extends Datasource {
@@ -57,39 +57,42 @@ export class RubyGemsDatasource extends Datasource {
         cachedVersions.type === 'not-supported' &&
         registryHostname !== 'rubygems.org'
       ) {
-        const hostname = registryHostname;
-        return hostname === 'rubygems.pkg.github.com' ||
-          hostname === 'gitlab.com'
-          ? await this.getDependencyFallback(registryUrl, packageName)
-          : await this.getDependency(registryUrl, packageName);
+        if (
+          registryHostname === 'rubygems.pkg.github.com' ||
+          registryHostname === 'gitlab.com'
+        ) {
+          return await this.getReleasesViaFallbackAPI(registryUrl, packageName);
+        }
+
+        const gemMetadata = await this.fetchGemMetadata(
+          registryUrl,
+          packageName
+        );
+        if (!gemMetadata) {
+          return await this.getReleasesViaFallbackAPI(registryUrl, packageName);
+        }
+
+        return await this.getReleasesViaAPI(
+          registryUrl,
+          packageName,
+          gemMetadata
+        );
       }
+
+      return null;
     } catch (error) {
       this.handleGenericErrors(error);
     }
-
-    return null;
   }
 
-  async getDependencyFallback(
+  async fetchGemMetadata(
     registryUrl: string,
     packageName: string
-  ): Promise<ReleaseResult | null> {
-    const path = joinUrlParts(registryUrl, `/api/v1/dependencies`);
-    const query = getQueryString({ gems: packageName });
-    const url = `${path}?${query}`;
-    const { body: buffer } = await this.http.getBuffer(url);
-    const data = Marshal.parse(buffer);
-    return MarshalledVersionInfo.parse(data);
-  }
-
-  async fetchGemsInfo(
-    registryUrl: string,
-    packageName: string
-  ): Promise<GemsInfo | null> {
+  ): Promise<GemMetadata | null> {
     try {
       const { body } = await this.http.getJson(
         joinUrlParts(registryUrl, '/api/v1/gems', `${packageName}.json`),
-        GemsInfo
+        GemMetadata
       );
       return body;
     } catch (err) {
@@ -124,41 +127,48 @@ export class RubyGemsDatasource extends Datasource {
     }
   }
 
-  async getDependency(
+  async getReleasesViaAPI(
     registryUrl: string,
-    packageName: string
+    packageName: string,
+    gemMetadata: GemMetadata
   ): Promise<ReleaseResult | null> {
-    const info = await this.fetchGemsInfo(registryUrl, packageName);
-    if (!info) {
-      return await this.getDependencyFallback(registryUrl, packageName);
-    }
+    const gemVersions = await this.fetchGemVersions(registryUrl, packageName);
 
     let releases: Release[] | null = null;
-    const gemVersions = await this.fetchGemVersions(registryUrl, packageName);
     if (gemVersions?.length) {
       releases = gemVersions;
-    } else if (info.version) {
-      releases = [{ version: info.version }];
-    }
-
-    if (!releases) {
+    } else if (gemMetadata.latestVersion) {
+      releases = [{ version: gemMetadata.latestVersion }];
+    } else {
       return null;
     }
 
     const result: ReleaseResult = { releases };
 
-    if (info.changelogUrl) {
-      result.changelogUrl = info.changelogUrl;
+    if (gemMetadata.changelogUrl) {
+      result.changelogUrl = gemMetadata.changelogUrl;
     }
 
-    if (info.homepage) {
-      result.homepage = info.homepage;
+    if (gemMetadata.homepage) {
+      result.homepage = gemMetadata.homepage;
     }
 
-    if (info.sourceUrl) {
-      result.sourceUrl = info.sourceUrl;
+    if (gemMetadata.sourceUrl) {
+      result.sourceUrl = gemMetadata.sourceUrl;
     }
 
     return result;
   }
+
+  async getReleasesViaFallbackAPI(
+    registryUrl: string,
+    packageName: string
+  ): Promise<ReleaseResult | null> {
+    const path = joinUrlParts(registryUrl, `/api/v1/dependencies`);
+    const query = getQueryString({ gems: packageName });
+    const url = `${path}?${query}`;
+    const { body: buffer } = await this.http.getBuffer(url);
+    const data = Marshal.parse(buffer);
+    return MarshalledVersionInfo.parse(data);
+  }
 }
diff --git a/lib/modules/datasource/rubygems/schema.ts b/lib/modules/datasource/rubygems/schema.ts
index 3931a40c0c..e0109f885c 100644
--- a/lib/modules/datasource/rubygems/schema.ts
+++ b/lib/modules/datasource/rubygems/schema.ts
@@ -14,7 +14,7 @@ export const MarshalledVersionInfo = LooseArray(
   .nullable()
   .catch(null);
 
-export const GemsInfo = z
+export const GemMetadata = z
   .object({
     name: z.string().transform((x) => x.toLowerCase()),
     version: z.string().nullish().catch(null),
@@ -31,13 +31,13 @@ export const GemsInfo = z
       source_code_uri: sourceUrl,
     }) => ({
       packageName,
-      version,
+      latestVersion: version,
       changelogUrl,
       homepage,
       sourceUrl,
     })
   );
-export type GemsInfo = z.infer<typeof GemsInfo>;
+export type GemMetadata = z.infer<typeof GemMetadata>;
 
 export const GemVersions = LooseArray(
   z
-- 
GitLab