mirror of
https://code.forgejo.org/actions/checkout.git
synced 2025-08-14 17:30:50 +00: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