From e792268cbba0f17de902b44a46aa22f9be9047cf Mon Sep 17 00:00:00 2001
From: Jamie Magee <JamieMagee@users.noreply.github.com>
Date: Wed, 25 Sep 2019 11:58:52 +0200
Subject: [PATCH] feat(git): initialise submodules when cloning repos (#4353)

See https://git-scm.com/docs/git-clone#Documentation/git-clone.txt---recurse-submodulesltpathspec

Fixes #1356
---
 lib/platform/git/storage.ts                   | 26 ++++++++++++++++---
 .../git/__snapshots__/storage.spec.ts.snap    |  9 +++++++
 test/platform/git/storage.spec.ts             | 12 +++++++++
 3 files changed, 44 insertions(+), 3 deletions(-)

diff --git a/lib/platform/git/storage.ts b/lib/platform/git/storage.ts
index 07b9cda6f0..822f4c103f 100644
--- a/lib/platform/git/storage.ts
+++ b/lib/platform/git/storage.ts
@@ -110,7 +110,10 @@ export class Storage {
       const cloneStart = process.hrtime();
       try {
         // clone only the default branch
-        await this._git.clone(config.url, '.', ['--depth=2']);
+        await this._git.clone(config.url, '.', [
+          '--depth=2',
+          '--recurse-submodules',
+        ]);
       } catch (err) /* istanbul ignore next */ {
         logger.debug({ err }, 'git clone error');
         throw new Error('platform-failure');
@@ -241,7 +244,19 @@ export class Storage {
     if (!exists) {
       return [];
     }
-    const files = await this._git!.raw([
+    const submodules: string[] = (
+      (await this._git!.raw([
+        'config',
+        '--file',
+        '.gitmodules',
+        '--get-regexp',
+        'path',
+      ])) || ''
+    )
+      .trim()
+      .split(/[\n\s]/)
+      .filter((_e: string, i: number) => i % 2);
+    const files: string = await this._git!.raw([
       'ls-tree',
       '-r',
       '--name-only',
@@ -251,7 +266,12 @@ export class Storage {
     if (!files) {
       return [];
     }
-    return files.split('\n').filter(Boolean);
+    return files
+      .split('\n')
+      .filter(Boolean)
+      .filter((file: string) =>
+        submodules.every((submodule: string) => !file.startsWith(submodule))
+      );
   }
 
   async branchExists(branchName: string) {
diff --git a/test/platform/git/__snapshots__/storage.spec.ts.snap b/test/platform/git/__snapshots__/storage.spec.ts.snap
index 0e86ff4242..bc7b2e88b0 100644
--- a/test/platform/git/__snapshots__/storage.spec.ts.snap
+++ b/test/platform/git/__snapshots__/storage.spec.ts.snap
@@ -11,6 +11,15 @@ Array [
 
 exports[`platform/git/storage getFile(filePath, branchName) returns null for 404 1`] = `[Error: repository-changed]`;
 
+exports[`platform/git/storage getFileList() should exclude submodules 1`] = `
+Array [
+  ".gitmodules",
+  "file_to_delete",
+  "master_file",
+  "past_file",
+]
+`;
+
 exports[`platform/git/storage getFileList() should return the correct files 1`] = `
 Array [
   "file_to_delete",
diff --git a/test/platform/git/storage.spec.ts b/test/platform/git/storage.spec.ts
index b9a8d184bc..ffc0574a8d 100644
--- a/test/platform/git/storage.spec.ts
+++ b/test/platform/git/storage.spec.ts
@@ -84,6 +84,18 @@ describe('platform/git/storage', () => {
       expect(await git.getFileList('renovate/future_branch')).toMatchSnapshot();
       expect(await git.getFileList()).toMatchSnapshot();
     });
+    it('should exclude submodules', async () => {
+      const repo = await Git(base.path).silent(true);
+      await repo.submoduleAdd(base.path, 'submodule');
+      await repo.commit('Add submodule');
+      await git.initRepo({
+        localDir: tmpDir.path,
+        url: base.path,
+      });
+      expect(await fs.exists(tmpDir.path + '/.gitmodules')).toBeTruthy();
+      expect(await git.getFileList()).toMatchSnapshot();
+      repo.reset(['--hard', 'HEAD^']);
+    });
   });
   describe('branchExists(branchName)', () => {
     it('should return true if found', async () => {
-- 
GitLab