mirror of
				https://github.com/actions/checkout.git
				synced 2025-10-31 20:33:36 +00:00 
			
		
		
		
	Update logic for preserving local changes in the checkout action
This commit is contained in:
		
							parent
							
								
									f04b821901
								
							
						
					
					
						commit
						ebd82bae91
					
				
							
								
								
									
										94
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										94
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							| @ -1339,9 +1339,97 @@ function getSource(settings) { | |||||||
|             core.startGroup('Checking out the ref'); |             core.startGroup('Checking out the ref'); | ||||||
|             if (settings.preserveLocalChanges) { |             if (settings.preserveLocalChanges) { | ||||||
|                 core.info('Attempting to preserve local changes during checkout'); |                 core.info('Attempting to preserve local changes during checkout'); | ||||||
|                 // Use --merge to preserve local changes if possible
 |                 // List and store local files before checkout
 | ||||||
|                 // This will fail if there are merge conflicts, but that's expected behavior
 |                 const fs = __nccwpck_require__(7147); | ||||||
|                 yield git.checkout(checkoutInfo.ref, checkoutInfo.startPoint, ['--merge']); |                 const path = __nccwpck_require__(1017); | ||||||
|  |                 const localFiles = new Map(); | ||||||
|  |                 try { | ||||||
|  |                     // Get all files in the workspace that aren't in the .git directory
 | ||||||
|  |                     const workspacePath = process.cwd(); | ||||||
|  |                     core.info(`Current workspace path: ${workspacePath}`); | ||||||
|  |                     // List all files in the current directory using fs
 | ||||||
|  |                     const listFilesRecursively = (dir) => { | ||||||
|  |                         let results = []; | ||||||
|  |                         const list = fs.readdirSync(dir); | ||||||
|  |                         list.forEach((file) => { | ||||||
|  |                             const fullPath = path.join(dir, file); | ||||||
|  |                             const relativePath = path.relative(workspacePath, fullPath); | ||||||
|  |                             // Skip .git directory
 | ||||||
|  |                             if (relativePath.startsWith('.git')) | ||||||
|  |                                 return; | ||||||
|  |                             const stat = fs.statSync(fullPath); | ||||||
|  |                             if (stat && stat.isDirectory()) { | ||||||
|  |                                 // Recursively explore subdirectories
 | ||||||
|  |                                 results = results.concat(listFilesRecursively(fullPath)); | ||||||
|  |                             } | ||||||
|  |                             else { | ||||||
|  |                                 // Store file content in memory
 | ||||||
|  |                                 try { | ||||||
|  |                                     const content = fs.readFileSync(fullPath); | ||||||
|  |                                     localFiles.set(relativePath, content); | ||||||
|  |                                     results.push(relativePath); | ||||||
|  |                                 } | ||||||
|  |                                 catch (readErr) { | ||||||
|  |                                     core.warning(`Failed to read file ${relativePath}: ${readErr}`); | ||||||
|  |                                 } | ||||||
|  |                             } | ||||||
|  |                         }); | ||||||
|  |                         return results; | ||||||
|  |                     }; | ||||||
|  |                     const localFilesList = listFilesRecursively(workspacePath); | ||||||
|  |                     core.info(`Found ${localFilesList.length} local files to preserve:`); | ||||||
|  |                     localFilesList.forEach(file => core.info(`  - ${file}`)); | ||||||
|  |                 } | ||||||
|  |                 catch (error) { | ||||||
|  |                     core.warning(`Failed to list local files: ${error}`); | ||||||
|  |                 } | ||||||
|  |                 // Perform normal checkout
 | ||||||
|  |                 yield git.checkout(checkoutInfo.ref, checkoutInfo.startPoint); | ||||||
|  |                 // Restore local files that were not tracked by git
 | ||||||
|  |                 core.info('Restoring local files after checkout'); | ||||||
|  |                 try { | ||||||
|  |                     let restoredCount = 0; | ||||||
|  |                     const execOptions = { | ||||||
|  |                         cwd: process.cwd(), | ||||||
|  |                         silent: true, | ||||||
|  |                         ignoreReturnCode: true | ||||||
|  |                     }; | ||||||
|  |                     for (const [filePath, content] of localFiles.entries()) { | ||||||
|  |                         // Check if file exists in git using a child process instead of git.execGit
 | ||||||
|  |                         const { exec } = __nccwpck_require__(1514); | ||||||
|  |                         let exitCode = 0; | ||||||
|  |                         const output = { | ||||||
|  |                             stdout: '', | ||||||
|  |                             stderr: '' | ||||||
|  |                         }; | ||||||
|  |                         // Capture output
 | ||||||
|  |                         const options = Object.assign(Object.assign({}, execOptions), { listeners: { | ||||||
|  |                                 stdout: (data) => { | ||||||
|  |                                     output.stdout += data.toString(); | ||||||
|  |                                 }, | ||||||
|  |                                 stderr: (data) => { | ||||||
|  |                                     output.stderr += data.toString(); | ||||||
|  |                                 } | ||||||
|  |                             } }); | ||||||
|  |                         exitCode = yield exec('git', ['ls-files', '--error-unmatch', filePath], options); | ||||||
|  |                         if (exitCode !== 0) { | ||||||
|  |                             // File is not tracked by git, safe to restore
 | ||||||
|  |                             const fullPath = path.join(process.cwd(), filePath); | ||||||
|  |                             // Ensure directory exists
 | ||||||
|  |                             fs.mkdirSync(path.dirname(fullPath), { recursive: true }); | ||||||
|  |                             fs.writeFileSync(fullPath, content); | ||||||
|  |                             core.info(`Restored local file: ${filePath}`); | ||||||
|  |                             restoredCount++; | ||||||
|  |                         } | ||||||
|  |                         else { | ||||||
|  |                             core.info(`Skipping ${filePath} as it's tracked by git`); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                     core.info(`Successfully restored ${restoredCount} local files`); | ||||||
|  |                 } | ||||||
|  |                 catch (error) { | ||||||
|  |                     core.warning(`Failed to restore local files: ${error}`); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|             else { |             else { | ||||||
|                 // Use the default behavior with --force
 |                 // Use the default behavior with --force
 | ||||||
|  | |||||||
| @ -231,9 +231,105 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> { | |||||||
|     core.startGroup('Checking out the ref') |     core.startGroup('Checking out the ref') | ||||||
|     if (settings.preserveLocalChanges) { |     if (settings.preserveLocalChanges) { | ||||||
|       core.info('Attempting to preserve local changes during checkout') |       core.info('Attempting to preserve local changes during checkout') | ||||||
|       // Use --merge to preserve local changes if possible
 |        | ||||||
|       // This will fail if there are merge conflicts, but that's expected behavior
 |       // List and store local files before checkout
 | ||||||
|       await git.checkout(checkoutInfo.ref, checkoutInfo.startPoint, ['--merge']) |       const fs = require('fs') | ||||||
|  |       const path = require('path') | ||||||
|  |       const localFiles = new Map() | ||||||
|  |        | ||||||
|  |       try { | ||||||
|  |         // Get all files in the workspace that aren't in the .git directory
 | ||||||
|  |         const workspacePath = process.cwd() | ||||||
|  |         core.info(`Current workspace path: ${workspacePath}`) | ||||||
|  |          | ||||||
|  |         // List all files in the current directory using fs
 | ||||||
|  |         const listFilesRecursively = (dir: string): string[] => { | ||||||
|  |           let results: string[] = [] | ||||||
|  |           const list = fs.readdirSync(dir) | ||||||
|  |           list.forEach((file: string) => { | ||||||
|  |             const fullPath = path.join(dir, file) | ||||||
|  |             const relativePath = path.relative(workspacePath, fullPath) | ||||||
|  |             // Skip .git directory
 | ||||||
|  |             if (relativePath.startsWith('.git')) return | ||||||
|  |              | ||||||
|  |             const stat = fs.statSync(fullPath) | ||||||
|  |             if (stat && stat.isDirectory()) { | ||||||
|  |               // Recursively explore subdirectories
 | ||||||
|  |               results = results.concat(listFilesRecursively(fullPath)) | ||||||
|  |             } else { | ||||||
|  |               // Store file content in memory
 | ||||||
|  |               try { | ||||||
|  |                 const content = fs.readFileSync(fullPath) | ||||||
|  |                 localFiles.set(relativePath, content) | ||||||
|  |                 results.push(relativePath) | ||||||
|  |               } catch (readErr) { | ||||||
|  |                 core.warning(`Failed to read file ${relativePath}: ${readErr}`) | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |           }) | ||||||
|  |           return results | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         const localFilesList = listFilesRecursively(workspacePath) | ||||||
|  |         core.info(`Found ${localFilesList.length} local files to preserve:`) | ||||||
|  |         localFilesList.forEach(file => core.info(`  - ${file}`)) | ||||||
|  |       } catch (error) { | ||||||
|  |         core.warning(`Failed to list local files: ${error}`) | ||||||
|  |       } | ||||||
|  |        | ||||||
|  |       // Perform normal checkout
 | ||||||
|  |       await git.checkout(checkoutInfo.ref, checkoutInfo.startPoint) | ||||||
|  |        | ||||||
|  |       // Restore local files that were not tracked by git
 | ||||||
|  |       core.info('Restoring local files after checkout') | ||||||
|  |       try { | ||||||
|  |         let restoredCount = 0 | ||||||
|  |         const execOptions = { | ||||||
|  |           cwd: process.cwd(), | ||||||
|  |           silent: true, | ||||||
|  |           ignoreReturnCode: true | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         for (const [filePath, content] of localFiles.entries()) { | ||||||
|  |           // Check if file exists in git using a child process instead of git.execGit
 | ||||||
|  |           const { exec } = require('@actions/exec') | ||||||
|  |           let exitCode = 0 | ||||||
|  |           const output = { | ||||||
|  |             stdout: '', | ||||||
|  |             stderr: '' | ||||||
|  |           } | ||||||
|  |            | ||||||
|  |           // Capture output
 | ||||||
|  |           const options = { | ||||||
|  |             ...execOptions, | ||||||
|  |             listeners: { | ||||||
|  |               stdout: (data: Buffer) => { | ||||||
|  |                 output.stdout += data.toString() | ||||||
|  |               }, | ||||||
|  |               stderr: (data: Buffer) => { | ||||||
|  |                 output.stderr += data.toString() | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |            | ||||||
|  |           exitCode = await exec('git', ['ls-files', '--error-unmatch', filePath], options) | ||||||
|  |            | ||||||
|  |           if (exitCode !== 0) { | ||||||
|  |             // File is not tracked by git, safe to restore
 | ||||||
|  |             const fullPath = path.join(process.cwd(), filePath) | ||||||
|  |             // Ensure directory exists
 | ||||||
|  |             fs.mkdirSync(path.dirname(fullPath), { recursive: true }) | ||||||
|  |             fs.writeFileSync(fullPath, content) | ||||||
|  |             core.info(`Restored local file: ${filePath}`) | ||||||
|  |             restoredCount++ | ||||||
|  |           } else { | ||||||
|  |             core.info(`Skipping ${filePath} as it's tracked by git`) | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |         core.info(`Successfully restored ${restoredCount} local files`) | ||||||
|  |       } catch (error) { | ||||||
|  |         core.warning(`Failed to restore local files: ${error}`) | ||||||
|  |       } | ||||||
|     } else { |     } else { | ||||||
|       // Use the default behavior with --force
 |       // Use the default behavior with --force
 | ||||||
|       await git.checkout(checkoutInfo.ref, checkoutInfo.startPoint) |       await git.checkout(checkoutInfo.ref, checkoutInfo.startPoint) | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user