From 45abae3e9f3df5893d661cb11371ae3124e5bfe1 Mon Sep 17 00:00:00 2001 From: Salman Muin Kayser Chishti Date: Mon, 11 Aug 2025 14:10:22 +0100 Subject: [PATCH] feat: Honor preserve-local-changes flag when repository URL changes Makes preserve-local-changes option work consistently in all scenarios, including when repository URL changes. Updates warning message to correctly reflect this behavior. --- __test__/git-directory-helper.test.ts | 89 +++++++++++++++++++++++++++ src/git-directory-helper.ts | 14 +++++ 2 files changed, 103 insertions(+) diff --git a/__test__/git-directory-helper.test.ts b/__test__/git-directory-helper.test.ts index e7ad155..5d3fb4f 100644 --- a/__test__/git-directory-helper.test.ts +++ b/__test__/git-directory-helper.test.ts @@ -154,6 +154,34 @@ describe('git-directory-helper tests', () => { expect(core.warning).toHaveBeenCalled() expect(git.tryReset).not.toHaveBeenCalled() }) + + const preservesContentsWhenCleanFailsAndPreserveLocalChanges = 'preserves contents when clean fails and preserve-local-changes is true' + it(preservesContentsWhenCleanFailsAndPreserveLocalChanges, async () => { + // Arrange + await setup(preservesContentsWhenCleanFailsAndPreserveLocalChanges) + await fs.promises.writeFile(path.join(repositoryPath, 'my-file'), '') + let mockTryClean = git.tryClean as jest.Mock + mockTryClean.mockImplementation(async () => { + return false + }) + + // Act + await gitDirectoryHelper.prepareExistingDirectory( + git, + repositoryPath, + repositoryUrl, + clean, + ref, + true // preserveLocalChanges = true + ) + + // Assert + const files = await fs.promises.readdir(repositoryPath) + expect(files.sort()).toEqual(['.git', 'my-file']) // Expect both .git and user files to remain + expect(git.tryClean).toHaveBeenCalled() + expect(core.warning).toHaveBeenCalled() + expect(git.tryReset).not.toHaveBeenCalled() + }) const removesContentsWhenDifferentRepositoryUrl = 'removes contents when different repository url' @@ -182,6 +210,39 @@ describe('git-directory-helper tests', () => { expect(git.isDetached).not.toHaveBeenCalled() }) + const keepsContentsWhenDifferentRepositoryUrlAndPreserveLocalChanges = + 'keeps contents when different repository url and preserve-local-changes is true' + it(keepsContentsWhenDifferentRepositoryUrlAndPreserveLocalChanges, async () => { + // Arrange + await setup(keepsContentsWhenDifferentRepositoryUrlAndPreserveLocalChanges) + clean = false + + // Create a file that we expect to be preserved + await fs.promises.writeFile(path.join(repositoryPath, 'my-file'), '') + + // Simulate a different repository by simply removing the .git directory + await io.rmRF(path.join(repositoryPath, '.git')) + await fs.promises.mkdir(path.join(repositoryPath, '.git')) + + const differentRepositoryUrl = 'https://github.com/my-different-org/my-different-repo' + + // Act + await gitDirectoryHelper.prepareExistingDirectory( + git, + repositoryPath, + differentRepositoryUrl, // Use a different URL + clean, + ref, + true // preserveLocalChanges = true + ) + + // Assert + const files = await fs.promises.readdir(repositoryPath) + console.log('Files after operation:', files) + // When preserveLocalChanges is true, files should be preserved even with different repo URL + expect(files.sort()).toEqual(['.git', 'my-file'].sort()) + }) + const removesContentsWhenNoGitDirectory = 'removes contents when no git directory' it(removesContentsWhenNoGitDirectory, async () => { @@ -235,6 +296,34 @@ describe('git-directory-helper tests', () => { expect(core.warning).toHaveBeenCalled() }) + const preservesContentsWhenResetFailsAndPreserveLocalChanges = 'preserves contents when reset fails and preserve-local-changes is true' + it(preservesContentsWhenResetFailsAndPreserveLocalChanges, async () => { + // Arrange + await setup(preservesContentsWhenResetFailsAndPreserveLocalChanges) + await fs.promises.writeFile(path.join(repositoryPath, 'my-file'), '') + let mockTryReset = git.tryReset as jest.Mock + mockTryReset.mockImplementation(async () => { + return false + }) + + // Act + await gitDirectoryHelper.prepareExistingDirectory( + git, + repositoryPath, + repositoryUrl, + clean, + ref, + true // preserveLocalChanges = true + ) + + // Assert + const files = await fs.promises.readdir(repositoryPath) + expect(files.sort()).toEqual(['.git', 'my-file']) // Expect both .git and user files to remain + expect(git.tryClean).toHaveBeenCalled() + expect(git.tryReset).toHaveBeenCalled() + expect(core.warning).toHaveBeenCalled() + }) + const removesContentsWhenUndefinedGitCommandManager = 'removes contents when undefined git command manager' it(removesContentsWhenUndefinedGitCommandManager, async () => { diff --git a/src/git-directory-helper.ts b/src/git-directory-helper.ts index 2d255b2..6d57bcf 100644 --- a/src/git-directory-helper.ts +++ b/src/git-directory-helper.ts @@ -122,6 +122,20 @@ export async function prepareExistingDirectory( } } + // Check repository conditions + let isLocalGitRepo = git && fsHelper.directoryExistsSync(path.join(repositoryPath, '.git')); + let repoUrl = isLocalGitRepo ? await git?.tryGetFetchUrl() : ''; + let isSameRepository = repositoryUrl === repoUrl; + let differentRepoUrl = !isSameRepository; + + // Repository URL has changed + if (differentRepoUrl) { + if (preserveLocalChanges) { + core.warning(`Repository URL has changed from '${repoUrl}' to '${repositoryUrl}'. Local changes will be preserved as requested.`); + } + remove = true; // Mark for removal, but actual removal will respect preserveLocalChanges + } + if (remove && !preserveLocalChanges) { // Delete the contents of the directory. Don't delete the directory itself // since it might be the current working directory.