From 0f6c54dea37b55c565fe82d08f9a9e108985cd51 Mon Sep 17 00:00:00 2001
From: Matthew Endsley <mendsley@gmail.com>
Date: Fri, 28 Oct 2022 20:20:33 -0700
Subject: [PATCH] Add clean-exclude input

This allows clients to ignore specific paths from the clean phase of the
checkout.
---
 README.md                   |  4 ++++
 action.yml                  |  3 +++
 dist/index.js               | 17 ++++++++++++-----
 src/git-command-manager.ts  | 12 +++++++++---
 src/git-directory-helper.ts |  3 ++-
 src/git-source-provider.ts  |  1 +
 src/git-source-settings.ts  |  5 +++++
 src/input-helper.ts         |  2 ++
 8 files changed, 38 insertions(+), 9 deletions(-)

diff --git a/README.md b/README.md
index 66c2507..f6681ad 100644
--- a/README.md
+++ b/README.md
@@ -74,6 +74,10 @@ When Git 2.18 or higher is not in your PATH, falls back to the REST API to downl
     # Default: true
     clean: ''
 
+    # Comma separated paths to exclude when executing `git clean -ffdx`
+    # Default: 
+    clean-exclude: ''
+
     # Number of commits to fetch. 0 indicates all history for all branches and tags.
     # Default: 1
     fetch-depth: ''
diff --git a/action.yml b/action.yml
index 4500daf..8291861 100644
--- a/action.yml
+++ b/action.yml
@@ -53,6 +53,9 @@ inputs:
   clean:
     description: 'Whether to execute `git clean -ffdx && git reset --hard HEAD` before fetching'
     default: true
+  clean-exclude:
+    description: 'Comma separated paths to exclude when executing `git clean -ffdx`'
+    default: ''
   fetch-depth:
     description: 'Number of commits to fetch. 0 indicates all history for all branches and tags.'
     default: 1
diff --git a/dist/index.js b/dist/index.js
index c9c90dd..0bf5810 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -7608,9 +7608,14 @@ class GitCommandManager {
             return !!output.stdout.trim();
         });
     }
-    tryClean() {
+    tryClean(exclude) {
         return __awaiter(this, void 0, void 0, function* () {
-            const output = yield this.execGit(['clean', '-ffdx'], true);
+            var cleanArgs = [];
+            for (const pattern of exclude) {
+                cleanArgs.push('-e');
+                cleanArgs.push(pattern);
+            }
+            const output = yield this.execGit(['clean', '-ffdx', ...cleanArgs], true);
             return output.exitCode === 0;
         });
     }
@@ -9290,7 +9295,7 @@ const fs = __importStar(__webpack_require__(747));
 const fsHelper = __importStar(__webpack_require__(618));
 const io = __importStar(__webpack_require__(1));
 const path = __importStar(__webpack_require__(622));
-function prepareExistingDirectory(git, repositoryPath, repositoryUrl, clean, ref) {
+function prepareExistingDirectory(git, repositoryPath, repositoryUrl, clean, cleanExclude, ref) {
     var _a, _b;
     return __awaiter(this, void 0, void 0, function* () {
         assert.ok(repositoryPath, 'Expected repositoryPath to be defined');
@@ -9354,7 +9359,7 @@ function prepareExistingDirectory(git, repositoryPath, repositoryUrl, clean, ref
                 // Clean
                 if (clean) {
                     core.startGroup('Cleaning the repository');
-                    if (!(yield git.tryClean())) {
+                    if (!(yield git.tryClean(cleanExclude))) {
                         core.debug(`The clean command failed. This might be caused by: 1) path too long, 2) permission issue, or 3) file in use. For futher investigation, manually run 'git clean -ffdx' on the directory '${repositoryPath}'.`);
                         remove = true;
                     }
@@ -18447,6 +18452,8 @@ function getInputs() {
         // Clean
         result.clean = (core.getInput('clean') || 'true').toUpperCase() === 'TRUE';
         core.debug(`clean = ${result.clean}`);
+        result.cleanExclude = (core.getInput('clean-exclude') || '').split(',');
+        core.debug(`cleanExclude = ${JSON.stringify(result.cleanExclude)}`);
         // Fetch depth
         result.fetchDepth = Math.floor(Number(core.getInput('fetch-depth') || '1'));
         if (isNaN(result.fetchDepth) || result.fetchDepth < 0) {
@@ -31850,7 +31857,7 @@ function getSource(settings) {
             }
             // Prepare existing directory, otherwise recreate
             if (isExisting) {
-                yield gitDirectoryHelper.prepareExistingDirectory(git, settings.repositoryPath, repositoryUrl, settings.clean, settings.ref);
+                yield gitDirectoryHelper.prepareExistingDirectory(git, settings.repositoryPath, repositoryUrl, settings.clean, settings.cleanExclude, settings.ref);
             }
             if (!git) {
                 // Downloading using REST API
diff --git a/src/git-command-manager.ts b/src/git-command-manager.ts
index 699a963..46c571e 100644
--- a/src/git-command-manager.ts
+++ b/src/git-command-manager.ts
@@ -42,7 +42,7 @@ export interface IGitCommandManager {
   submoduleSync(recursive: boolean): Promise<void>
   submoduleUpdate(fetchDepth: number, recursive: boolean): Promise<void>
   tagExists(pattern: string): Promise<boolean>
-  tryClean(): Promise<boolean>
+  tryClean(exclude: string[]): Promise<boolean>
   tryConfigUnset(configKey: string, globalConfig?: boolean): Promise<boolean>
   tryDisableAutomaticGarbageCollection(): Promise<boolean>
   tryGetFetchUrl(): Promise<string>
@@ -331,8 +331,14 @@ class GitCommandManager {
     return !!output.stdout.trim()
   }
 
-  async tryClean(): Promise<boolean> {
-    const output = await this.execGit(['clean', '-ffdx'], true)
+  async tryClean(exclude: string[]): Promise<boolean> {
+    var cleanArgs: string[] = []
+    for (const pattern of exclude) {
+      cleanArgs.push('-e')
+      cleanArgs.push(pattern)
+    }
+
+    const output = await this.execGit(['clean', '-ffdx', ...cleanArgs], true)
     return output.exitCode === 0
   }
 
diff --git a/src/git-directory-helper.ts b/src/git-directory-helper.ts
index 2979e97..7723789 100644
--- a/src/git-directory-helper.ts
+++ b/src/git-directory-helper.ts
@@ -11,6 +11,7 @@ export async function prepareExistingDirectory(
   repositoryPath: string,
   repositoryUrl: string,
   clean: boolean,
+  cleanExclude: string[],
   ref: string
 ): Promise<void> {
   assert.ok(repositoryPath, 'Expected repositoryPath to be defined')
@@ -84,7 +85,7 @@ export async function prepareExistingDirectory(
       // Clean
       if (clean) {
         core.startGroup('Cleaning the repository')
-        if (!(await git.tryClean())) {
+        if (!(await git.tryClean(cleanExclude))) {
           core.debug(
             `The clean command failed. This might be caused by: 1) path too long, 2) permission issue, or 3) file in use. For futher investigation, manually run 'git clean -ffdx' on the directory '${repositoryPath}'.`
           )
diff --git a/src/git-source-provider.ts b/src/git-source-provider.ts
index c4a913d..9c109ac 100644
--- a/src/git-source-provider.ts
+++ b/src/git-source-provider.ts
@@ -68,6 +68,7 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
         settings.repositoryPath,
         repositoryUrl,
         settings.clean,
+        settings.cleanExclude,
         settings.ref
       )
     }
diff --git a/src/git-source-settings.ts b/src/git-source-settings.ts
index bde96e8..1c3a980 100644
--- a/src/git-source-settings.ts
+++ b/src/git-source-settings.ts
@@ -29,6 +29,11 @@ export interface IGitSourceSettings {
    */
   clean: boolean
 
+  /**
+   * Paths to ignore when cleaning the repository
+   */
+  cleanExclude: string[]
+
   /**
    * The depth when fetching
    */
diff --git a/src/input-helper.ts b/src/input-helper.ts
index c0c0b2c..dd558e0 100644
--- a/src/input-helper.ts
+++ b/src/input-helper.ts
@@ -81,6 +81,8 @@ export async function getInputs(): Promise<IGitSourceSettings> {
   // Clean
   result.clean = (core.getInput('clean') || 'true').toUpperCase() === 'TRUE'
   core.debug(`clean = ${result.clean}`)
+  result.cleanExclude = (core.getInput('clean-exclude') || '').split(',')
+  core.debug(`cleanExclude = ${JSON.stringify(result.cleanExclude)}`)
 
   // Fetch depth
   result.fetchDepth = Math.floor(Number(core.getInput('fetch-depth') || '1'))