From ee1c796c21edc9f8841b7b7002bb797a3f48387b Mon Sep 17 00:00:00 2001
From: Rhys Arkins <rhys@arkins.net>
Date: Wed, 8 Apr 2020 12:37:21 +0200
Subject: [PATCH] refactor(terraform): use autoReplace

---
 lib/manager/common.ts                         |   2 -
 .../__snapshots__/extract.spec.ts.snap        | 126 +-------------
 lib/manager/terraform/extract.spec.ts         |  14 --
 lib/manager/terraform/extract.ts              |  31 ++--
 lib/manager/terraform/index.ts                |   3 +-
 lib/manager/terraform/update.spec.ts          | 163 ------------------
 lib/manager/terraform/update.ts               |  42 -----
 7 files changed, 18 insertions(+), 363 deletions(-)
 delete mode 100644 lib/manager/terraform/update.spec.ts
 delete mode 100644 lib/manager/terraform/update.ts

diff --git a/lib/manager/common.ts b/lib/manager/common.ts
index 749bc36624..eba78df889 100644
--- a/lib/manager/common.ts
+++ b/lib/manager/common.ts
@@ -146,12 +146,10 @@ export interface PackageDependency<T = Record<string, any>> extends Package<T> {
   displayTo?: string;
   fromVersion?: string;
   lockedVersion?: string;
-  moduleName?: string;
   propSource?: string;
   registryUrls?: string[];
   rangeStrategy?: RangeStrategy;
   skipReason?: SkipReason;
-  source?: string;
   sourceLine?: number;
   toVersion?: string;
   updates?: PackageUpdateResult[];
diff --git a/lib/manager/terraform/__snapshots__/extract.spec.ts.snap b/lib/manager/terraform/__snapshots__/extract.spec.ts.snap
index 0f2af52ae1..d1cdedfa31 100644
--- a/lib/manager/terraform/__snapshots__/extract.spec.ts.snap
+++ b/lib/manager/terraform/__snapshots__/extract.spec.ts.snap
@@ -10,12 +10,6 @@ Object {
       "depNameShort": "hashicorp/example",
       "depType": "github",
       "lookupName": "hashicorp/example",
-      "managerData": Object {
-        "lineNumber": 1,
-        "terraformDependencyType": "module",
-      },
-      "moduleName": "foo",
-      "source": "github.com/hashicorp/example?ref=v1.0.0",
     },
     Object {
       "currentValue": "next",
@@ -24,13 +18,7 @@ Object {
       "depNameShort": "hashicorp/example",
       "depType": "github",
       "lookupName": "hashicorp/example",
-      "managerData": Object {
-        "lineNumber": 5,
-        "terraformDependencyType": "module",
-      },
-      "moduleName": "bar",
       "skipReason": "unsupported-version",
-      "source": "github.com/hashicorp/example?ref=next",
     },
     Object {
       "currentValue": "0.1.0",
@@ -38,12 +26,6 @@ Object {
       "depName": "hashicorp/consul/aws",
       "depNameShort": "hashicorp/consul/aws",
       "depType": "terraform",
-      "managerData": Object {
-        "lineNumber": 10,
-        "terraformDependencyType": "module",
-      },
-      "moduleName": "consul",
-      "source": "hashicorp/consul/aws",
     },
     Object {
       "currentValue": "v0.1.0",
@@ -52,12 +34,6 @@ Object {
       "depNameShort": "tieto-cem/terraform-aws-ecs-task-definition",
       "depType": "github",
       "lookupName": "tieto-cem/terraform-aws-ecs-task-definition",
-      "managerData": Object {
-        "lineNumber": 14,
-        "terraformDependencyType": "module",
-      },
-      "moduleName": "container_definition",
-      "source": "github.com/tieto-cem/terraform-aws-ecs-task-definition//modules/container-definition?ref=v0.1.0",
     },
     Object {
       "currentValue": "v0.1.0",
@@ -66,12 +42,6 @@ Object {
       "depNameShort": "tieto-cem/terraform-aws-ecs-task-definition",
       "depType": "github",
       "lookupName": "tieto-cem/terraform-aws-ecs-task-definition",
-      "managerData": Object {
-        "lineNumber": 25,
-        "terraformDependencyType": "module",
-      },
-      "moduleName": "task_definition",
-      "source": "github.com/tieto-cem/terraform-aws-ecs-task-definition?ref=v0.1.0",
     },
     Object {
       "currentValue": "v2.0.0",
@@ -80,24 +50,12 @@ Object {
       "depNameShort": "hashicorp/example",
       "depType": "github",
       "lookupName": "hashicorp/example",
-      "managerData": Object {
-        "lineNumber": 31,
-        "terraformDependencyType": "module",
-      },
-      "moduleName": "consul",
-      "source": "git@github.com:hashicorp/example.git?ref=v2.0.0",
     },
     Object {
       "datasource": "terraform-module",
       "depName": "terraform-aws-modules/security-group/aws",
       "depNameShort": "terraform-aws-modules/security-group/aws",
       "depType": "terraform",
-      "managerData": Object {
-        "lineNumber": undefined,
-        "terraformDependencyType": "module",
-      },
-      "moduleName": "web_server_sg",
-      "source": "terraform-aws-modules/security-group/aws//modules/http-80",
     },
     Object {
       "currentValue": "<= 2.4.0",
@@ -105,12 +63,6 @@ Object {
       "depName": "terraform-aws-modules/security-group/aws",
       "depNameShort": "terraform-aws-modules/security-group/aws",
       "depType": "terraform",
-      "managerData": Object {
-        "lineNumber": 46,
-        "terraformDependencyType": "module",
-      },
-      "moduleName": "vote_service_sg",
-      "source": "terraform-aws-modules/security-group/aws",
     },
     Object {
       "currentValue": "~> 1.1.0",
@@ -118,12 +70,6 @@ Object {
       "depName": "app.terraform.io/example-corp/k8s-cluster/azurerm",
       "depNameShort": "app.terraform.io/example-corp/k8s-cluster/azurerm",
       "depType": "terraform",
-      "managerData": Object {
-        "lineNumber": 71,
-        "terraformDependencyType": "module",
-      },
-      "moduleName": "consul",
-      "source": "app.terraform.io/example-corp/k8s-cluster/azurerm",
     },
     Object {
       "currentValue": "~> 1.1",
@@ -131,12 +77,6 @@ Object {
       "depName": "app.terraform.io/example-corp/k8s-cluster/azurerm",
       "depNameShort": "app.terraform.io/example-corp/k8s-cluster/azurerm",
       "depType": "terraform",
-      "managerData": Object {
-        "lineNumber": 76,
-        "terraformDependencyType": "module",
-      },
-      "moduleName": "consul2",
-      "source": "app.terraform.io/example-corp/k8s-cluster/azurerm",
     },
     Object {
       "currentValue": "~~ 1.1",
@@ -144,12 +84,6 @@ Object {
       "depName": "app.terraform.io/example-corp/k8s-cluster/azurerm",
       "depNameShort": "app.terraform.io/example-corp/k8s-cluster/azurerm",
       "depType": "terraform",
-      "managerData": Object {
-        "lineNumber": 81,
-        "terraformDependencyType": "module",
-      },
-      "moduleName": "consul3",
-      "source": "app.terraform.io/example-corp/k8s-cluster/azurerm",
     },
     Object {
       "currentValue": ">= 1.0.0, <= 2.0.0",
@@ -157,26 +91,11 @@ Object {
       "depName": "hashicorp/consul/aws",
       "depNameShort": "hashicorp/consul/aws",
       "depType": "terraform",
-      "managerData": Object {
-        "lineNumber": 86,
-        "terraformDependencyType": "module",
-      },
-      "moduleName": "consul3",
-      "source": "hashicorp/consul/aws",
     },
     Object {
-      "managerData": Object {
-        "terraformDependencyType": "module",
-      },
-      "moduleName": "relative",
       "skipReason": "local",
-      "source": "../../modules/fe",
     },
     Object {
-      "managerData": Object {
-        "terraformDependencyType": "module",
-      },
-      "moduleName": "nosauce",
       "skipReason": "no-source",
     },
     Object {
@@ -185,11 +104,6 @@ Object {
       "depName": "azurerm",
       "depNameShort": "azurerm",
       "depType": "terraform",
-      "managerData": Object {
-        "lineNumber": 99,
-        "terraformDependencyType": "provider",
-      },
-      "moduleName": "azurerm",
     },
     Object {
       "currentValue": "=2.4",
@@ -197,11 +111,6 @@ Object {
       "depName": "gitlab",
       "depNameShort": "gitlab",
       "depType": "terraform",
-      "managerData": Object {
-        "lineNumber": 104,
-        "terraformDependencyType": "provider",
-      },
-      "moduleName": "gitlab",
     },
     Object {
       "currentValue": "=1.3",
@@ -209,22 +118,12 @@ Object {
       "depName": "gitlab",
       "depNameShort": "gitlab",
       "depType": "terraform",
-      "managerData": Object {
-        "lineNumber": 109,
-        "terraformDependencyType": "provider",
-      },
-      "moduleName": "gitlab",
     },
     Object {
       "datasource": "terraform-provider",
       "depName": "helm",
       "depNameShort": "helm",
       "depType": "terraform",
-      "managerData": Object {
-        "lineNumber": undefined,
-        "terraformDependencyType": "provider",
-      },
-      "moduleName": "helm",
       "skipReason": "no-version",
     },
     Object {
@@ -233,20 +132,9 @@ Object {
       "depName": "newrelic",
       "depNameShort": "newrelic",
       "depType": "terraform",
-      "managerData": Object {
-        "lineNumber": 125,
-        "terraformDependencyType": "provider",
-      },
-      "moduleName": "newrelic",
       "skipReason": "unsupported-version",
     },
-    Object {
-      "managerData": Object {
-        "terraformDependencyType": "module",
-      },
-      "moduleName": "foobar",
-      "source": "https://bitbucket.com/hashicorp/example?ref=v1.0.0",
-    },
+    Object {},
     Object {
       "currentValue": "v1.0.0",
       "datasource": "git-tags",
@@ -254,12 +142,6 @@ Object {
       "depNameShort": "hashicorp/example",
       "depType": "gitTags",
       "lookupName": "https://bitbucket.com/hashicorp/example",
-      "managerData": Object {
-        "lineNumber": 135,
-        "terraformDependencyType": "module",
-      },
-      "moduleName": "gittags",
-      "source": "git::https://bitbucket.com/hashicorp/example?ref=v1.0.0",
     },
     Object {
       "currentValue": "next",
@@ -268,13 +150,7 @@ Object {
       "depNameShort": "hashicorp/example",
       "depType": "gitTags",
       "lookupName": "https://bitbucket.com/hashicorp/example",
-      "managerData": Object {
-        "lineNumber": 139,
-        "terraformDependencyType": "module",
-      },
-      "moduleName": "gittags_badversion",
       "skipReason": "unsupported-version",
-      "source": "git::https://bitbucket.com/hashicorp/example?ref=next",
     },
   ],
 }
diff --git a/lib/manager/terraform/extract.spec.ts b/lib/manager/terraform/extract.spec.ts
index 5814c51dcd..8e795f2802 100644
--- a/lib/manager/terraform/extract.spec.ts
+++ b/lib/manager/terraform/extract.spec.ts
@@ -21,20 +21,6 @@ describe('lib/manager/terraform/extract', () => {
       expect(res).toMatchSnapshot();
       expect(res.deps).toHaveLength(22);
       expect(res.deps.filter(dep => dep.skipReason)).toHaveLength(6);
-      expect(
-        res.deps.filter(
-          dep =>
-            dep.managerData.terraformDependencyType ===
-            TerraformDependencyTypes.module
-        )
-      ).toHaveLength(17);
-      expect(
-        res.deps.filter(
-          dep =>
-            dep.managerData.terraformDependencyType ===
-            TerraformDependencyTypes.provider
-        )
-      ).toHaveLength(5);
     });
     it('returns null if only local deps', () => {
       expect(extractPackageFile(tf2)).toBeNull();
diff --git a/lib/manager/terraform/extract.ts b/lib/manager/terraform/extract.ts
index adaa6cf62f..943ed94459 100644
--- a/lib/manager/terraform/extract.ts
+++ b/lib/manager/terraform/extract.ts
@@ -48,8 +48,8 @@ export function extractPackageFile(content: string): PackageFile | null {
           terraformDependency[1]
         );
         const dep: PackageDependency = {
-          moduleName: terraformDependency[2],
           managerData: {
+            moduleName: terraformDependency[2],
             terraformDependencyType: tfDepType,
           },
         };
@@ -66,10 +66,10 @@ export function extractPackageFile(content: string): PackageFile | null {
               const [, key, value] = kvMatch;
               if (key === 'version') {
                 dep.currentValue = value;
-                dep.versionLine = lineNumber;
+                dep.managerData.versionLine = lineNumber;
               } else if (key === 'source') {
-                dep.source = value;
-                dep.sourceLine = lineNumber;
+                dep.managerData.source = value;
+                dep.managerData.sourceLine = lineNumber;
               }
             }
           } while (line.trim() !== '}');
@@ -86,11 +86,11 @@ export function extractPackageFile(content: string): PackageFile | null {
       TerraformDependencyTypes.module
     ) {
       const githubRefMatch = /github.com(\/|:)([^/]+\/[a-z0-9-]+).*\?ref=(.*)$/.exec(
-        dep.source
+        dep.managerData.source
       );
       // Regex would need to be updated to support ssh://
       const gitTagsRefMatch = /git::(http|https:\/\/(.*.*\/(.*\/.*)))(?:|\/\/.*)\?ref=(.*)$/.exec(
-        dep.source
+        dep.managerData.source
       );
       /* eslint-disable no-param-reassign */
       if (githubRefMatch) {
@@ -100,7 +100,7 @@ export function extractPackageFile(content: string): PackageFile | null {
         dep.currentValue = githubRefMatch[3];
         dep.datasource = datasourceGithubTags.id;
         dep.lookupName = githubRefMatch[2];
-        dep.managerData.lineNumber = dep.sourceLine;
+        dep.managerData.lineNumber = dep.managerData.sourceLine;
         if (!isVersion(dep.currentValue)) {
           dep.skipReason = SkipReason.UnsupportedVersion;
         }
@@ -111,19 +111,19 @@ export function extractPackageFile(content: string): PackageFile | null {
         dep.currentValue = gitTagsRefMatch[4];
         dep.datasource = datasourceGitTags.id;
         dep.lookupName = gitTagsRefMatch[1];
-        dep.managerData.lineNumber = dep.sourceLine;
+        dep.managerData.lineNumber = dep.managerData.sourceLine;
         if (!isVersion(dep.currentValue)) {
           dep.skipReason = SkipReason.UnsupportedVersion;
         }
-      } else if (dep.source) {
-        const moduleParts = dep.source.split('//')[0].split('/');
+      } else if (dep.managerData.source) {
+        const moduleParts = dep.managerData.source.split('//')[0].split('/');
         if (moduleParts[0] === '..') {
           dep.skipReason = SkipReason.Local;
         } else if (moduleParts.length >= 3) {
           dep.depType = 'terraform';
           dep.depName = moduleParts.join('/');
           dep.depNameShort = dep.depName;
-          dep.managerData.lineNumber = dep.versionLine;
+          dep.managerData.lineNumber = dep.managerData.versionLine;
           dep.datasource = datasourceTerraformModule.id;
         }
       } else {
@@ -135,9 +135,9 @@ export function extractPackageFile(content: string): PackageFile | null {
       TerraformDependencyTypes.provider
     ) {
       dep.depType = 'terraform';
-      dep.depName = dep.moduleName;
-      dep.depNameShort = dep.moduleName;
-      dep.managerData.lineNumber = dep.versionLine;
+      dep.depName = dep.managerData.moduleName;
+      dep.depNameShort = dep.managerData.moduleName;
+      dep.managerData.lineNumber = dep.managerData.versionLine;
       dep.datasource = datasourceTerraformProvider.id;
       if (dep.managerData.lineNumber) {
         if (!isValid(dep.currentValue)) {
@@ -147,8 +147,7 @@ export function extractPackageFile(content: string): PackageFile | null {
         dep.skipReason = SkipReason.NoVersion;
       }
     }
-    delete dep.sourceLine;
-    delete dep.versionLine;
+    delete dep.managerData;
     /* eslint-enable no-param-reassign */
   });
   if (deps.some(dep => dep.skipReason !== 'local')) {
diff --git a/lib/manager/terraform/index.ts b/lib/manager/terraform/index.ts
index 76e4cbde6b..1fc4cbb4a2 100644
--- a/lib/manager/terraform/index.ts
+++ b/lib/manager/terraform/index.ts
@@ -1,7 +1,8 @@
 import * as hashicorpVersioning from '../../versioning/hashicorp';
 
 export { extractPackageFile } from './extract';
-export { updateDependency } from './update';
+
+export const autoReplace = true;
 
 export const defaultConfig = {
   commitMessageTopic:
diff --git a/lib/manager/terraform/update.spec.ts b/lib/manager/terraform/update.spec.ts
deleted file mode 100644
index 2afde0d4ed..0000000000
--- a/lib/manager/terraform/update.spec.ts
+++ /dev/null
@@ -1,163 +0,0 @@
-import { readFileSync } from 'fs';
-import { updateDependency } from './update';
-
-const tf1 = readFileSync('lib/manager/terraform/__fixtures__/1.tf', 'utf8');
-
-describe('manager/terraform/update', () => {
-  describe('updateDependency', () => {
-    describe('github', () => {
-      it('replaces existing value', () => {
-        const upgrade = {
-          depType: 'github',
-          depName: 'foo',
-          managerData: { lineNumber: 1 },
-          depNameShort: 'hashicorp/example',
-          newValue: 'v1.0.1',
-        };
-        const res = updateDependency({ fileContent: tf1, upgrade });
-        expect(res).not.toEqual(tf1);
-        expect(res.includes(upgrade.newValue)).toBe(true);
-      });
-      it('returns same', () => {
-        const upgrade = {
-          depType: 'github',
-          depName: 'foo',
-          managerData: { lineNumber: 1 },
-          depNameShort: 'hashicorp/example',
-          newValue: 'v1.0.0',
-        };
-        const res = updateDependency({ fileContent: tf1, upgrade });
-        expect(res).toEqual(tf1);
-      });
-      it('returns null if wrong line', () => {
-        const upgrade = {
-          depType: 'github',
-          depName: 'foo',
-          managerData: { lineNumber: 2 },
-          depNameShort: 'hashicorp/example',
-          newValue: 'v1.0.0',
-        };
-        const res = updateDependency({ fileContent: tf1, upgrade });
-        expect(res).toBeNull();
-      });
-      it('updates github versions', () => {
-        const upgrade = {
-          depType: 'github',
-          currentValue: 'v0.1.0',
-          newValue: 'v0.1.3',
-          depName: 'github.com/tieto-cem/terraform-aws-ecs-task-definition',
-          depNameShort: 'tieto-cem/terraform-aws-ecs-task-definition',
-          managerData: { lineNumber: 14 },
-          moduleName: 'container_definition',
-          source:
-            'github.com/tieto-cem/terraform-aws-ecs-task-definition//modules/container-definition?ref=v0.1.0',
-        };
-        const res = updateDependency({ fileContent: tf1, upgrade });
-        expect(res).not.toEqual(tf1);
-        expect(res.includes(upgrade.newValue)).toBe(true);
-      });
-    });
-    describe('gitTags', () => {
-      it('replaces existing value', () => {
-        const upgrade = {
-          depType: 'gitTags',
-          depName: 'bitbucket.com/hashicorp/example',
-          managerData: { lineNumber: 131 },
-          depNameShort: 'hashicorp/example',
-          newValue: 'v1.0.1',
-        };
-        const res = updateDependency({ fileContent: tf1, upgrade });
-        expect(res).not.toEqual(tf1);
-        expect(res.includes(upgrade.newValue)).toBe(true);
-      });
-      it('returns same', () => {
-        const upgrade = {
-          depType: 'gitTags',
-          depName: 'foobar',
-          managerData: { lineNumber: 131 },
-          depNameShort: 'hashicorp/example',
-          newValue: 'v1.0.0',
-        };
-        const res = updateDependency({ fileContent: tf1, upgrade });
-        expect(res).toEqual(tf1);
-      });
-      it('returns null if wrong line', () => {
-        const upgrade = {
-          depType: 'gitTags',
-          depName: 'foobar',
-          managerData: { lineNumber: 2 },
-          depNameShort: 'hashicorp/example',
-          newValue: 'v1.0.0',
-        };
-        const res = updateDependency({ fileContent: tf1, upgrade });
-        expect(res).toBeNull();
-      });
-    });
-    it('skips terraform versions wrong line', () => {
-      const upgrade = {
-        currentValue: '0.1.0',
-        depName: 'hashicorp/consul/aws',
-        depNameShort: 'hashicorp/consul/aws',
-        depType: 'terraform',
-        managerData: { lineNumber: 11 },
-        moduleName: 'consul',
-        source: 'hashicorp/consul/aws',
-        newValue: '0.4.0',
-      };
-      const res = updateDependency({ fileContent: tf1, upgrade });
-      expect(res).toBeNull();
-    });
-    it('updates terraform versions', () => {
-      const upgrade = {
-        currentValue: '0.1.0',
-        depName: 'hashicorp/consul/aws',
-        depNameShort: 'hashicorp/consul/aws',
-        depType: 'terraform',
-        managerData: { lineNumber: 10 },
-        moduleName: 'consul',
-        source: 'hashicorp/consul/aws',
-        newValue: '0.4.0',
-      };
-      const res = updateDependency({ fileContent: tf1, upgrade });
-      expect(res).not.toEqual(tf1);
-      expect(res.includes(upgrade.newValue)).toBe(true);
-    });
-    it('updates terraform versions with terraformDependencyType `module` ', () => {
-      const upgrade = {
-        currentValue: '0.1.0',
-        depName: 'hashicorp/consul/aws',
-        depNameShort: 'hashicorp/consul/aws',
-        depType: 'terraform',
-        managerData: {
-          lineNumber: 10,
-          terraformDependencyType: 'module',
-        },
-        moduleName: 'consul',
-        source: 'hashicorp/consul/aws',
-        newValue: '0.4.0',
-      };
-      const res = updateDependency({ fileContent: tf1, upgrade });
-      expect(res).not.toEqual(tf1);
-      expect(res.includes(upgrade.newValue)).toBe(true);
-    });
-    it('updates terraform versions with terraformDependencyType `provider` ', () => {
-      const upgrade = {
-        currentValue: '1.36.1',
-        depName: 'azurerm',
-        depNameShort: 'azurerm',
-        depType: 'terraform',
-        managerData: {
-          lineNumber: 99,
-          terraformDependencyType: 'provider',
-        },
-        moduleName: 'azurerm',
-        source:
-          'https://github.com/terraform-providers/terraform-provider-azurerm',
-        newValue: '1.38.0',
-      };
-      const res = updateDependency({ fileContent: tf1, upgrade });
-      expect(res).not.toEqual(tf1);
-      expect(res.includes(upgrade.newValue)).toBe(true);
-    });
-  });
-});
diff --git a/lib/manager/terraform/update.ts b/lib/manager/terraform/update.ts
deleted file mode 100644
index 2db0076949..0000000000
--- a/lib/manager/terraform/update.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import { logger } from '../../logger';
-import { UpdateDependencyConfig } from '../common';
-
-export function updateDependency({
-  fileContent,
-  upgrade,
-}: UpdateDependencyConfig): string | null {
-  try {
-    logger.debug(`terraform.updateDependency: ${upgrade.newValue}`);
-    const lines = fileContent.split('\n');
-    const lineToChange = lines[upgrade.managerData.lineNumber];
-    let newLine = lineToChange;
-    if (upgrade.depType === 'github') {
-      if (!lineToChange.includes(upgrade.depNameShort)) {
-        return null;
-      }
-      newLine = lineToChange.replace(/\?ref=.*"/, `?ref=${upgrade.newValue}"`);
-    } else if (upgrade.depType === 'gitTags') {
-      if (!lineToChange.includes(upgrade.depNameShort)) {
-        return null;
-      }
-      newLine = lineToChange.replace(/\?ref=.*"/, `?ref=${upgrade.newValue}"`);
-    } else if (upgrade.depType === 'terraform') {
-      if (!/version\s*=\s*"/.test(lineToChange)) {
-        return null;
-      }
-      newLine = lineToChange.replace(
-        /(version\s*=\s*)"[^"]*"/,
-        `$1"${upgrade.newValue}"`
-      );
-    }
-    if (newLine === lineToChange) {
-      logger.debug('No changes necessary');
-      return fileContent;
-    }
-    lines[upgrade.managerData.lineNumber] = newLine;
-    return lines.join('\n');
-  } catch (err) /* istanbul ignore next */ {
-    logger.debug({ err }, 'Error setting new terraform module version');
-    return null;
-  }
-}
-- 
GitLab