mirror of
				https://github.com/actions/checkout.git
				synced 2025-11-03 22:31:56 +02:00 
			
		
		
		
	Update logic for preserving local changes in the checkout action
This commit is contained in:
		
							parent
							
								
									f04b821901
								
							
						
					
					
						commit
						ebd82bae91
					
				
					 2 changed files with 190 additions and 6 deletions
				
			
		
							
								
								
									
										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…
	
	Add table
		Add a link
		
	
		Reference in a new issue