From ccf5cf24ea8f6c1481e783ce8842ec77c84a435c Mon Sep 17 00:00:00 2001
From: Nabeel Saabna <48175656+nabeelsaabna@users.noreply.github.com>
Date: Wed, 21 Jun 2023 17:00:13 +0300
Subject: [PATCH] feat(config): add docker cli config (#22684)

Co-authored-by: Rhys Arkins <rhys@arkins.net>
Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com>
Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
---
 docs/usage/self-hosted-configuration.md |  8 ++++++++
 lib/config/global.ts                    |  1 +
 lib/config/options/index.ts             |  7 +++++++
 lib/config/types.ts                     |  2 ++
 lib/util/exec/docker/index.spec.ts      | 15 ++++++++++++++-
 lib/util/exec/docker/index.ts           |  4 ++++
 6 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/docs/usage/self-hosted-configuration.md b/docs/usage/self-hosted-configuration.md
index df2ac655a2..85f4dd4507 100644
--- a/docs/usage/self-hosted-configuration.md
+++ b/docs/usage/self-hosted-configuration.md
@@ -333,6 +333,14 @@ For example, if you set `dockerChildPrefix=myprefix_` then the final container c
 !!! note
     Dangling containers are only removed when Renovate runs again with the same prefix.
 
+## dockerCliOptions
+
+You can use `dockerCliOptions` to pass Docker CLI options to Renovate's sidecar Docker containers.
+
+For example, `{"dockerCliOptions": "--memory=4g"}` will add a CLI flag to the `docker run` command that limits the amount of memory Renovate's sidecar Docker container can use to 4 gigabytes.
+
+Read the [Docker Docs, configure runtime resource contraints](https://docs.docker.com/config/containers/resource_constraints/) to learn more.
+
 ## dockerImagePrefix
 
 By default Renovate pulls the sidecar Docker containers from `docker.io/containerbase`.
diff --git a/lib/config/global.ts b/lib/config/global.ts
index c1b4e92455..666645f448 100644
--- a/lib/config/global.ts
+++ b/lib/config/global.ts
@@ -14,6 +14,7 @@ export class GlobalConfig {
     'containerbaseDir',
     'customEnvVariables',
     'dockerChildPrefix',
+    'dockerCliOptions',
     'dockerImagePrefix',
     'dockerUser',
     'dryRun',
diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts
index 95761e5f55..b2ea0a5813 100644
--- a/lib/config/options/index.ts
+++ b/lib/config/options/index.ts
@@ -343,6 +343,13 @@ const options: RenovateOptions[] = [
     globalOnly: true,
     default: 'renovate_',
   },
+  {
+    name: 'dockerCliOptions',
+    description:
+      'Pass CLI flags to `docker run` command when `binarySource=docker`.',
+    type: 'string',
+    globalOnly: true,
+  },
   {
     name: 'dockerImagePrefix',
     description:
diff --git a/lib/config/types.ts b/lib/config/types.ts
index 488ef1d8ad..148fc57e4c 100644
--- a/lib/config/types.ts
+++ b/lib/config/types.ts
@@ -99,6 +99,7 @@ export interface GlobalOnlyConfig {
   cacheDir?: string;
   containerbaseDir?: string;
   detectHostRulesFromEnv?: boolean;
+  dockerCliOptions?: string;
   forceCli?: boolean;
   gitNoVerify?: GitNoVerifyOption[];
   gitPrivateKey?: string;
@@ -126,6 +127,7 @@ export interface RepoGlobalConfig {
   cacheHardTtlMinutes?: number;
   customEnvVariables?: Record<string, string>;
   dockerChildPrefix?: string;
+  dockerCliOptions?: string;
   dockerImagePrefix?: string;
   dockerUser?: string;
   dryRun?: DryRunConfig;
diff --git a/lib/util/exec/docker/index.spec.ts b/lib/util/exec/docker/index.spec.ts
index 3542031c09..b0a2904ab6 100644
--- a/lib/util/exec/docker/index.spec.ts
+++ b/lib/util/exec/docker/index.spec.ts
@@ -217,12 +217,13 @@ describe('util/exec/docker/index', () => {
       cwd: '/tmp/foobar',
       envVars,
     };
-    const command = (img: string, vol?: string): string =>
+    const command = (img: string, vol?: string, opts?: string): string =>
       `docker run --rm ` +
       `--name=renovate_${img} ` +
       `--label=renovate_child ` +
       `--user=some-user ` +
       (vol ? `${vol} ` : '') +
+      (opts ? `${opts} ` : '') +
       `-e FOO -e BAR ` +
       `-w "/tmp/foobar" ` +
       `containerbase/${img} ` +
@@ -298,6 +299,18 @@ describe('util/exec/docker/index', () => {
       );
     });
 
+    it('add multiple docker cli option', async () => {
+      mockExecAll();
+      GlobalConfig.set({
+        dockerUser: 'some-user',
+        dockerCliOptions: '--memory=4g --cpus=".5"',
+      });
+      const res = await generateDockerCommand(commands, preCommands, {
+        ...dockerOptions,
+      });
+      expect(res).toBe(command(image, undefined, `--memory=4g --cpus=".5"`));
+    });
+
     // TODO: it('handles tag constraint', async () => {
     //   mockExecAll();
     // jest
diff --git a/lib/util/exec/docker/index.ts b/lib/util/exec/docker/index.ts
index 9d192db590..bab2610a56 100644
--- a/lib/util/exec/docker/index.ts
+++ b/lib/util/exec/docker/index.ts
@@ -222,6 +222,7 @@ export async function generateDockerCommand(
     containerbaseDir,
     dockerUser,
     dockerChildPrefix,
+    dockerCliOptions,
     dockerImagePrefix,
   } = GlobalConfig.get();
   const result = ['docker run --rm'];
@@ -232,6 +233,9 @@ export async function generateDockerCommand(
   if (dockerUser) {
     result.push(`--user=${dockerUser}`);
   }
+  if (dockerCliOptions) {
+    result.push(dockerCliOptions);
+  }
 
   const volumeDirs: VolumeOption[] = [localDir, cacheDir];
   if (containerbaseDir) {
-- 
GitLab