From 2daf10e4e84cda90c82b0916082f133a711f3b93 Mon Sep 17 00:00:00 2001
From: Michael Kriese <michael.kriese@visualon.de>
Date: Fri, 4 Aug 2023 09:46:22 +0200
Subject: [PATCH] feat(datasource/docker): allow override max pages
 (experimental /self-hosted) (#23700)

---
 docs/usage/self-hosted-experimental.md      |  5 +++
 lib/modules/datasource/docker/index.spec.ts | 36 +++++++++++++++++++++
 lib/modules/datasource/docker/index.ts      |  5 ++-
 3 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/docs/usage/self-hosted-experimental.md b/docs/usage/self-hosted-experimental.md
index 5679da5915..cfed99f956 100644
--- a/docs/usage/self-hosted-experimental.md
+++ b/docs/usage/self-hosted-experimental.md
@@ -35,6 +35,11 @@ If set to "false" (string), Renovate will remove any existing `package-lock.json
 
 If set to any string, Renovate will use this as the `user-agent` it sends with HTTP requests.
 
+## `RENOVATE_X_DOCKER_MAX_PAGES`
+
+If set to an integer, Renovate will use this as max page number for docker tags lookup on docker registries, instead of the default 20 pages.
+This is useful for registries which ignores the `n` parameter in the query string and only return 50 tags per page.
+
 ## `RENOVATE_X_HARD_EXIT`
 
 If set to any value, Renovate will use a "hard" `process.exit()` once all work is done, even if a sub-process is otherwise delaying Node.js from exiting.
diff --git a/lib/modules/datasource/docker/index.spec.ts b/lib/modules/datasource/docker/index.spec.ts
index 15ed77dbad..5b4fa32cd7 100644
--- a/lib/modules/datasource/docker/index.spec.ts
+++ b/lib/modules/datasource/docker/index.spec.ts
@@ -40,6 +40,7 @@ describe('modules/datasource/docker/index', () => {
       password: 'some-password',
     });
     hostRules.hosts.mockReturnValue([]);
+    delete process.env.RENOVATE_X_DOCKER_MAX_PAGES;
   });
 
   describe('getDigest', () => {
@@ -1039,6 +1040,41 @@ describe('modules/datasource/docker/index', () => {
       expect(res?.releases).toHaveLength(1);
     });
 
+    it('uses custom max pages', async () => {
+      process.env.RENOVATE_X_DOCKER_MAX_PAGES = '2';
+      httpMock
+        .scope(baseUrl)
+        .get('/library/node/tags/list?n=10000')
+        .reply(200, '', {})
+        .get('/library/node/tags/list?n=10000')
+        .reply(
+          200,
+          { tags: ['1.0.0'] },
+          {
+            link: `<${baseUrl}/library/node/tags/list?n=1&page=1>; rel="next", `,
+          }
+        )
+        .get('/library/node/tags/list?n=1&page=1')
+        .reply(
+          200,
+          { tags: ['1.0.1'] },
+          {
+            link: `<${baseUrl}/library/node/tags/list?n=1&page=2>; rel="next", `,
+          }
+        )
+        .get('/')
+        .reply(200)
+        .get('/library/node/manifests/1.0.1')
+        .reply(200);
+
+      const config = {
+        datasource: DockerDatasource.id,
+        packageName: 'node',
+      };
+      const res = await getPkgReleases(config);
+      expect(res?.releases).toHaveLength(2);
+    });
+
     it('uses custom registry in packageName', async () => {
       const tags = ['1.0.0'];
       httpMock
diff --git a/lib/modules/datasource/docker/index.ts b/lib/modules/datasource/docker/index.ts
index 6fd32709ed..a349ce3ac6 100644
--- a/lib/modules/datasource/docker/index.ts
+++ b/lib/modules/datasource/docker/index.ts
@@ -560,6 +560,9 @@ export class DockerDatasource extends Datasource {
       return null;
     }
     let page = 0;
+    const pages = process.env.RENOVATE_X_DOCKER_MAX_PAGES
+      ? parseInt(process.env.RENOVATE_X_DOCKER_MAX_PAGES, 10)
+      : 20;
     let foundMaxResultsError = false;
     do {
       let res: HttpResponse<{ tags: string[] }>;
@@ -594,7 +597,7 @@ export class DockerDatasource extends Datasource {
         url = linkHeader?.next ? new URL(linkHeader.next.url, url).href : null;
       }
       page += 1;
-    } while (url && page < 20);
+    } while (url && page < pages);
     return tags;
   }
 
-- 
GitLab