public void GitWithEnvironmentVariables() { // The trace info is an error, so we can't use CheckGitCommand(). // We just want to make sure this doesn't throw an exception. ProcessResult result = GitHelpers.InvokeGitAgainstScalarRepo( this.Enlistment.RepoRoot, "branch", new Dictionary <string, string> { { "GIT_TRACE_PERFORMANCE", "1" }, { "git_trace", "1" }, }, removeWaitingMessages: false); result.Output.ShouldContain("* FunctionalTests"); result.Errors.ShouldNotContain(ignoreCase: true, unexpectedSubstrings: "exception"); result.Errors.ShouldContain("trace.c:", "git command:"); }
/* We are using the following method for these scenarios * 1. Some commands compute a new commit sha, which is dependent on time and therefore * won't match what is in the control repo. For those commands, we just ensure that * the errors match what we expect, but we skip comparing the output * 2. Using the sparse-checkout feature git will error out before checking the untracked files * so the control repo will show the untracked files as being overwritten while the GVFS * repo which is using the sparse-checkout will not. * 3. GVFS is returning not found for files that are outside the sparse-checkout and there * are cases when git will delete these files during a merge outputting that it removed them * which the GVFS repo did not have to remove so the message is missing that output. */ protected void RunGitCommand(string command, bool ignoreErrors = false, bool checkStatus = true) { string controlRepoRoot = this.ControlGitRepo.RootPath; string gvfsRepoRoot = this.Enlistment.RepoRoot; ProcessResult expectedResult = GitProcess.InvokeProcess(controlRepoRoot, command); ProcessResult actualResult = GitHelpers.InvokeGitAgainstGVFSRepo(gvfsRepoRoot, command); if (!ignoreErrors) { GitHelpers.ErrorsShouldMatch(command, expectedResult, actualResult); } if (command != "status" && checkStatus) { this.ValidateGitCommand("status"); } }
public void GitStatusAfterUnstage() { string existingFilename = "test.cs"; this.Enlistment.GetSourcePath(existingFilename).ShouldBeAFile(this.fileSystem); GitHelpers.CheckGitCommandAgainstScalarRepo( this.Enlistment.RepoRoot, "reset HEAD " + existingFilename, new string[] { }); GitHelpers.CheckGitCommandAgainstScalarRepo( this.Enlistment.RepoRoot, "status", "On branch " + Properties.Settings.Default.Commitish, "Untracked files:", existingFilename); }
public void ModifiedFileWillGetAddedToModifiedPathsFile() { string gitFileToTest = "GVFS/GVFS.Common/RetryWrapper.cs"; string fileToCreate = this.Enlistment.GetVirtualPathTo(gitFileToTest); this.VerifyWorktreeBit(gitFileToTest, LsFilesStatus.SkipWorktree); ManualResetEventSlim resetEvent = GitHelpers.AcquireGVFSLock(this.Enlistment, out _); this.fileSystem.WriteAllText(fileToCreate, "Anything can go here"); this.fileSystem.FileExists(fileToCreate).ShouldEqual(true); resetEvent.Set(); this.Enlistment.WaitForBackgroundOperations(); GVFSHelpers.ModifiedPathsShouldContain(this.Enlistment, this.fileSystem, gitFileToTest); this.VerifyWorktreeBit(gitFileToTest, LsFilesStatus.Cached); }
public void CanReadFileAfterHashObject() { this.ValidateGitCommand("status"); // Validate that Readme.md is not on disk at all string fileName = "Readme.md"; this.Enlistment.UnmountGVFS(); this.Enlistment.GetVirtualPathTo(fileName).ShouldNotExistOnDisk(this.FileSystem); this.Enlistment.MountGVFS(); // TODO 1087312: Fix 'git hash-oject' so that it works for files that aren't on disk yet GitHelpers.InvokeGitAgainstGVFSRepo( this.Enlistment.RepoRoot, "hash-object " + fileName); this.FileContentsShouldMatch(fileName); }
/* We are using the following method for these scenarios * 1. Some commands compute a new commit sha, which is dependent on time and therefore * won't match what is in the control repo. For those commands, we just ensure that * the errors match what we expect, but we skip comparing the output * 2. Using the sparse-checkout feature git will error out before checking the untracked files * so the control repo will show the untracked files as being overwritten while the Scalar * repo which is using the sparse-checkout will not. * 3. Scalar is returning not found for files that are outside the sparse-checkout and there * are cases when git will delete these files during a merge outputting that it removed them * which the Scalar repo did not have to remove so the message is missing that output. */ protected void RunGitCommand(string command, bool ignoreErrors = false, bool checkStatus = true, string standardInput = null) { string controlRepoRoot = this.ControlGitRepo.RootPath; string scalarRepoRoot = this.Enlistment.RepoRoot; ProcessResult expectedResult = GitProcess.InvokeProcess(controlRepoRoot, command, standardInput); ProcessResult actualResult = GitHelpers.InvokeGitAgainstScalarRepo(scalarRepoRoot, command, input: standardInput); if (!ignoreErrors) { GitHelpers.LinesShouldMatch(command, expectedResult.Errors, actualResult.Errors); } if (command != "status" && checkStatus) { this.ValidateGitCommand("status"); } }
public void CanReadFileAfterHashObject() { this.ValidateGitCommand("status"); // Validate that Scripts\RunUnitTests.bad is not on disk at all string filePath = Path.Combine("Scripts", "RunUnitTests.bat"); this.Enlistment.UnmountGVFS(); this.Enlistment.GetVirtualPathTo(filePath).ShouldNotExistOnDisk(this.FileSystem); this.Enlistment.MountGVFS(); // TODO 1087312: Fix 'git hash-oject' so that it works for files that aren't on disk yet GitHelpers.InvokeGitAgainstGVFSRepo( this.Enlistment.RepoRoot, "hash-object " + GitHelpers.ConvertPathToGitFormat(filePath)); this.FileContentsShouldMatch(filePath); }
public void GitStatusAfterFileRename() { string oldFilename = "New.cs"; this.EnsureTestFileExists(oldFilename); string newFilename = "test.cs"; string newFilePath = this.Enlistment.GetSourcePath(newFilename); this.fileSystem.MoveFile(this.Enlistment.GetSourcePath(oldFilename), newFilePath); GitHelpers.CheckGitCommandAgainstScalarRepo( this.Enlistment.RepoRoot, "status", "On branch " + Properties.Settings.Default.Commitish, "Untracked files:", newFilename); }
public void ModifiedFileWillGetSkipworktreeBitCleared() { string fileToTest = "GVFS\\GVFS.Common\\RetryWrapper.cs"; string fileToCreate = Path.Combine(this.Enlistment.RepoRoot, fileToTest); string gitFileToTest = fileToTest.Replace('\\', '/'); this.VerifyWorktreeBit(gitFileToTest, LsFilesStatus.SkipWorktree); ManualResetEventSlim resetEvent = GitHelpers.AcquireGVFSLock(this.Enlistment, out _); this.fileSystem.WriteAllText(fileToCreate, "Anything can go here"); this.fileSystem.FileExists(fileToCreate).ShouldEqual(true); resetEvent.Set(); this.Enlistment.WaitForBackgroundOperations().ShouldEqual(true, "Background operations did not complete."); GVFSHelpers.ModifiedPathsShouldContain(this.fileSystem, this.Enlistment.DotGVFSRoot, gitFileToTest + Environment.NewLine); this.VerifyWorktreeBit(gitFileToTest, LsFilesStatus.Cached); }
public void GitStatusAfterNewFile() { string filename = "new.cs"; string filePath = this.Enlistment.GetSourcePath(filename); filePath.ShouldNotExistOnDisk(this.fileSystem); this.fileSystem.WriteAllText(filePath, this.testFileContents); filePath.ShouldBeAFile(this.fileSystem).WithContents(this.testFileContents); GitHelpers.CheckGitCommandAgainstScalarRepo( this.Enlistment.RepoRoot, "status", "On branch " + Properties.Settings.Default.Commitish, "Untracked files:", filename); this.fileSystem.DeleteFile(filePath); }
public void MergeConflictEnsureStatusFailsDueToConfig() { // This is compared against the message emitted by GVFS.Hooks\Program.cs string expectedErrorMessagePart = "--no-renames"; this.ValidateGitCommand("checkout " + GitRepoTests.ConflictTargetBranch); this.RunGitCommand("merge " + GitRepoTests.ConflictSourceBranch, checkStatus: false); ProcessResult result1 = GitHelpers.InvokeGitAgainstGVFSRepo(this.Enlistment.RepoRoot, "status"); result1.Errors.Contains(expectedErrorMessagePart); ProcessResult result2 = GitHelpers.InvokeGitAgainstGVFSRepo(this.Enlistment.RepoRoot, "status --no-renames"); result2.Errors.Contains(expectedErrorMessagePart); // Complete setup to ensure teardown succeeds GitHelpers.InvokeGitAgainstGVFSRepo(this.Enlistment.RepoRoot, "config --local test.renames false"); }
/// <summary> /// Verify that a branch exists in the specified repo and contains a version details file. /// If it does not, optionally prompt the user to confirm that they wish to continue. /// </summary> /// <param name="remote">Remote</param> /// <param name="repo">Repository that the branch should be in</param> /// <param name="branch">Branch to check the existence of</param> /// <param name="prompt">Prompt the user to verify that they want to continue</param> /// <returns>True if the branch exists, prompting is not desired, or if the user confirms that they want to continue. False otherwise.</returns> public static async Task <bool> VerifyAndConfirmBranchExistsAsync(IRemote remote, string repo, string branch, bool prompt) { try { branch = GitHelpers.NormalizeBranchName(branch); await remote.GetDependenciesAsync(repo, branch); } catch (DependencyFileNotFoundException) { Console.WriteLine($"Warning: Could not find an eng/Version.Details.xml at '{repo}@{branch}'. Dependency updates may not happen as expected."); if (prompt) { return(PromptForYesNo("Continue?")); } } return(true); }
public void MountSetsCoreHooksPath() { this.Enlistment.UnmountGVFS(); GitProcess.Invoke(this.Enlistment.RepoRoot, "config --unset core.hookspath"); string.IsNullOrWhiteSpace( GitProcess.Invoke(this.Enlistment.RepoRoot, "config core.hookspath")) .ShouldBeTrue(); this.Enlistment.MountGVFS(); string expectedHooksPath = Path.Combine(this.Enlistment.RepoRoot, ".git", "hooks"); expectedHooksPath = GitHelpers.ConvertPathToGitFormat(expectedHooksPath); GitProcess.Invoke( this.Enlistment.RepoRoot, "config core.hookspath") .Trim('\n') .ShouldEqual(expectedHooksPath); }
private bool ReminderMessagingEnabled() { for (int count = 0; count < 50; count++) { ProcessResult result = GitHelpers.InvokeGitAgainstGSDRepo( this.Enlistment.RepoRoot, "status", removeWaitingMessages: true, removeUpgradeMessages: false); if (!string.IsNullOrEmpty(result.Errors) && result.Errors.Contains("A new version of GSD is available.")) { return(true); } } return(false); }
public void CheckoutBranchWhereSymLinksChangeContentsAndTransitionToFile() { GitHelpers.InvokeGitAgainstGVFSRepo(this.Enlistment.RepoRoot, "checkout FunctionalTests/20201014_SymLinksPart2"); GitHelpers.CheckGitCommandAgainstGVFSRepo( this.Enlistment.RepoRoot, "status", "On branch FunctionalTests/20201014_SymLinksPart2", "nothing to commit, working tree clean"); // testFilePath and testFile2Path are unchanged from FunctionalTests/20180925_SymLinksPart2 string testFilePath = this.Enlistment.GetVirtualPathTo(Path.Combine(TestFolderName, TestFileName)); testFilePath.ShouldBeAFile(this.bashRunner).WithContents(TestFileContents); this.bashRunner.IsSymbolicLink(testFilePath).ShouldBeFalse($"{testFilePath} should not be a symlink"); GVFSHelpers.ModifiedPathsShouldNotContain(this.Enlistment, this.bashRunner, TestFolderName + "/" + TestFileName); string testFile2Path = this.Enlistment.GetVirtualPathTo(Path.Combine(TestFolderName, TestFile2Name)); testFile2Path.ShouldBeAFile(this.bashRunner).WithContents(TestFile2Contents); this.bashRunner.IsSymbolicLink(testFile2Path).ShouldBeFalse($"{testFile2Path} should not be a symlink"); GVFSHelpers.ModifiedPathsShouldNotContain(this.Enlistment, this.bashRunner, TestFolderName + "/" + TestFile2Name); // In this branch childLinkPath has been changed to point to testFile2Path string childLinkPath = this.Enlistment.GetVirtualPathTo(Path.Combine(TestFolderName, ChildLinkName)); this.bashRunner.IsSymbolicLink(childLinkPath).ShouldBeTrue($"{childLinkPath} should be a symlink"); childLinkPath.ShouldBeAFile(this.bashRunner).WithContents(TestFile2Contents); GVFSHelpers.ModifiedPathsShouldContain(this.Enlistment, this.bashRunner, TestFolderName + "/" + ChildLinkName); // grandChildLinkPath should now be a file string grandChildLinkPath = this.Enlistment.GetVirtualPathTo(Path.Combine(TestFolderName, ChildFolderName, GrandChildLinkName)); this.bashRunner.IsSymbolicLink(grandChildLinkPath).ShouldBeFalse($"{grandChildLinkPath} should not be a symlink"); grandChildLinkPath.ShouldBeAFile(this.bashRunner).WithContents(GrandChildLinkNowAFileContents); // There should also be a new file in the child folder string newGrandChildFilePath = this.Enlistment.GetVirtualPathTo(Path.Combine(TestFolderName, ChildFolderName, GrandChildFileName)); newGrandChildFilePath.ShouldBeAFile(this.bashRunner).WithContents(GrandChildFileContents); this.bashRunner.IsSymbolicLink(newGrandChildFilePath).ShouldBeFalse($"{newGrandChildFilePath} should not be a symlink"); GVFSHelpers.ModifiedPathsShouldNotContain(this.Enlistment, this.bashRunner, TestFolderName + "/" + ChildFolderName + "/" + GrandChildFileName); }
public void SecondCloneSucceedsWithMissingTrees() { string newCachePath = Path.Combine(this.localCacheParentPath, ".customGvfsCache2"); GVFSFunctionalTestEnlistment enlistment1 = this.CreateNewEnlistment(localCacheRoot: newCachePath, skipPrefetch: true); File.ReadAllText(Path.Combine(enlistment1.RepoRoot, WellKnownFile)); this.AlternatesFileShouldHaveGitObjectsRoot(enlistment1); // This Git command loads the commit and root tree for WellKnownCommitSha, // but does not download any more reachable objects. string command = "cat-file -p origin/" + WellKnownBranch + "^{tree}"; ProcessResult result = GitHelpers.InvokeGitAgainstGVFSRepo(enlistment1.RepoRoot, command); result.ExitCode.ShouldEqual(0, $"git {command} failed with error: " + result.Errors); // If we did not properly check the failed checkout at this step, then clone will fail during checkout. GVFSFunctionalTestEnlistment enlistment2 = this.CreateNewEnlistment(localCacheRoot: newCachePath, branch: WellKnownBranch, skipPrefetch: true); File.ReadAllText(Path.Combine(enlistment2.RepoRoot, WellKnownFile)); }
public void GitWithEnvironmentVariables() { string previousPerf = Environment.GetEnvironmentVariable("GIT_TRACE_PERFORMANCE"); Environment.SetEnvironmentVariable("GIT_TRACE_PERFORMANCE", "1"); string previousTrace = Environment.GetEnvironmentVariable("git_trace"); Environment.SetEnvironmentVariable("git_trace", "1"); // The trace info is an error, so we can't use CheckGitCommand(). // We just want to make sure this doesn't throw an exception. ProcessResult result = GitHelpers.InvokeGitAgainstGVFSRepo(this.Enlistment.RepoRoot, "branch", cleanErrors: false); result.Output.ShouldContain("* FunctionalTests"); result.Errors.ShouldNotContain(ignoreCase: true, unexpectedSubstrings: "exception"); result.Errors.ShouldContain("trace.c:", "git command:"); Environment.SetEnvironmentVariable("GIT_TRACE_PERFORMANCE", previousPerf); Environment.SetEnvironmentVariable("git_trace", previousTrace); }
public void GitStatusAfterFileNameCaseChange() { string oldFilename = "new.cs"; this.EnsureTestFileExists(oldFilename); string newFilename = "New.cs"; string newFilePath = this.Enlistment.GetVirtualPathTo(newFilename); this.fileSystem.MoveFile(this.Enlistment.GetVirtualPathTo(oldFilename), newFilePath); GitHelpers.CheckGitCommandAgainstGVFSRepo( this.Enlistment.RepoRoot, "status", "On branch " + Properties.Settings.Default.Commitish, "Untracked files:", newFilename); this.fileSystem.DeleteFile(newFilePath); }
private bool ReminderMessagingEnabled() { Dictionary <string, string> environmentVariables = new Dictionary <string, string>(); environmentVariables["GVFS_UPGRADE_DETERMINISTIC"] = "true"; ProcessResult result = GitHelpers.InvokeGitAgainstGVFSRepo( this.Enlistment.RepoRoot, "status", environmentVariables, removeWaitingMessages: true, removeUpgradeMessages: false); if (!string.IsNullOrEmpty(result.Errors) && result.Errors.Contains("A new version of VFS for Git is available.")) { return(true); } return(false); }
public void CheckoutBranchWhereSymLinkTransistionsToFolderAndFolderTransitionsToSymlink() { GitHelpers.InvokeGitAgainstGVFSRepo(this.Enlistment.RepoRoot, "checkout FunctionalTests/20201014_SymLinksPart4"); GitHelpers.CheckGitCommandAgainstGVFSRepo( this.Enlistment.RepoRoot, "status", "On branch FunctionalTests/20201014_SymLinksPart4", "nothing to commit, working tree clean"); // In this branch ChildLinkName has been changed to a directory and ChildFolder2Name has been changed to a link to ChildFolderName string linkNowADirectoryPath = this.Enlistment.GetVirtualPathTo(Path.Combine(TestFolderName, ChildLinkName)); this.bashRunner.IsSymbolicLink(linkNowADirectoryPath).ShouldBeFalse($"{linkNowADirectoryPath} should not be a symlink"); linkNowADirectoryPath.ShouldBeADirectory(this.bashRunner); GVFSHelpers.ModifiedPathsShouldContain(this.Enlistment, this.bashRunner, TestFolderName + "/" + ChildLinkName); string directoryNowALinkPath = this.Enlistment.GetVirtualPathTo(Path.Combine(TestFolderName, ChildFolder2Name)); this.bashRunner.IsSymbolicLink(directoryNowALinkPath).ShouldBeTrue($"{directoryNowALinkPath} should be a symlink"); GVFSHelpers.ModifiedPathsShouldContain(this.Enlistment, this.bashRunner, TestFolderName + "/" + ChildFolder2Name); }
public void CreatedFileWillGetSkipworktreeBitCleared() { string fileToTest = "GVFS\\GVFS.Common\\RetryWrapper.cs"; string fileToCreate = Path.Combine(this.Enlistment.RepoRoot, fileToTest); string gitFileToTest = fileToTest.Replace('\\', '/'); this.VerifyWorktreeBit(gitFileToTest, LsFilesStatus.SkipWorktree); ManualResetEventSlim resetEvent = GitHelpers.AcquireGVFSLock(this.Enlistment); this.fileSystem.WriteAllText(fileToCreate, "Anything can go here"); this.fileSystem.FileExists(fileToCreate).ShouldEqual(true); resetEvent.Set(); this.Enlistment.WaitForBackgroundOperations().ShouldEqual(true, "Background operations did not complete."); string sparseCheckoutFile = Path.Combine(this.Enlistment.RepoRoot, TestConstants.DotGit.Info.SparseCheckout); sparseCheckoutFile.ShouldBeAFile(this.fileSystem).WithContents().ShouldContain(gitFileToTest); this.VerifyWorktreeBit(gitFileToTest, LsFilesStatus.Cached); }
public void UpdateIndexRemoveAddFileOpenForWrite() { // TODO 940287: Remove this test and re-enable UpdateIndexRemoveFileOnDisk this.ValidateGitCommand("checkout " + GitRepoTests.ConflictTargetBranch); // git-status will not match because update-index --remove does not check what is on disk if the skip-worktree bit is set, // meaning it will always remove the file from the index GitProcess.InvokeProcess(this.ControlGitRepo.RootPath, "update-index --remove Test_ConflictTests/AddedFiles/AddedByBothDifferentContent.txt"); GitHelpers.InvokeGitAgainstGVFSRepo(this.Enlistment.RepoRoot, "update-index --remove Test_ConflictTests/AddedFiles/AddedByBothDifferentContent.txt"); this.FilesShouldMatchCheckoutOfTargetBranch(); // Open Test_ConflictTests/AddedFiles/AddedByBothDifferentContent.txt for write so that it's added to the sparse-checkout using (FileStream stream = File.Open(Path.Combine(this.Enlistment.RepoRoot, @"Test_ConflictTests\AddedFiles\AddedByBothDifferentContent.txt"), FileMode.Open, FileAccess.Write)) { // TODO 940287: Remove this File.Open once update-index --add\--remove are working as expected } // Add the files back to the index so the git-status that is run during teardown matches GitProcess.InvokeProcess(this.ControlGitRepo.RootPath, "update-index --add Test_ConflictTests/AddedFiles/AddedByBothDifferentContent.txt"); GitHelpers.InvokeGitAgainstGVFSRepo(this.Enlistment.RepoRoot, "update-index --add Test_ConflictTests/AddedFiles/AddedByBothDifferentContent.txt"); }
public void CheckoutCleansUpTombstones() { const string folderToDelete = "Scripts"; // Delete directory to create the tombstone string directoryToDelete = this.Enlistment.GetVirtualPathTo(folderToDelete); this.fileSystem.DeleteDirectory(directoryToDelete); this.Enlistment.UnmountGVFS(); // Remove the directory entry from modified paths so git will not keep the folder up to date string modifiedPathsFile = Path.Combine(this.Enlistment.DotGVFSRoot, TestConstants.Databases.ModifiedPaths); string modifiedPathsContent = this.fileSystem.ReadAllText(modifiedPathsFile); modifiedPathsContent = string.Join(Delimiter, modifiedPathsContent.Split(new[] { Delimiter }, StringSplitOptions.RemoveEmptyEntries).Where(x => !x.StartsWith($"A {folderToDelete}/"))); this.fileSystem.WriteAllText(modifiedPathsFile, modifiedPathsContent + Delimiter); // Add tombstone folder entry to the placeholder file so the checkout will remove the tombstone // and start projecting the folder again string placeholderListFile = Path.Combine(this.Enlistment.DotGVFSRoot, TestConstants.Databases.PlaceholderList); string placeholderListContent = this.fileSystem.ReadAllText(placeholderListFile); placeholderListContent = string.Join(Delimiter, placeholderListContent.Split(new[] { Delimiter }, StringSplitOptions.RemoveEmptyEntries).Where(x => !x.StartsWith($"A {folderToDelete}"))); this.fileSystem.WriteAllText(placeholderListFile, placeholderListContent + Delimiter); string tombstoneEntry = $"A {folderToDelete}\0 POSSIBLE TOMBSTONE FOLDER{Delimiter}"; this.fileSystem.AppendAllText(placeholderListFile, tombstoneEntry); this.Enlistment.MountGVFS(); directoryToDelete.ShouldNotExistOnDisk(this.fileSystem); // checkout branch to remove tombstones and project the folder again GitHelpers.InvokeGitAgainstGVFSRepo(this.Enlistment.RepoRoot, "checkout -f HEAD"); directoryToDelete.ShouldBeADirectory(this.fileSystem); this.Enlistment.UnmountGVFS(); placeholderListContent = this.fileSystem.ReadAllText(placeholderListFile); placeholderListContent.ShouldNotContain(ignoreCase: false, unexpectedSubstrings: tombstoneEntry); }
public void GitStatusAfterRenameFileIntoRepo() { string filename = "GitStatusAfterRenameFileIntoRepo.cs"; // Create the test file in this.Enlistment.EnlistmentRoot as it's outside of src // and is cleaned up when the functional tests run string filePath = Path.Combine(this.Enlistment.EnlistmentRoot, filename); this.fileSystem.WriteAllText(filePath, this.testFileContents); filePath.ShouldBeAFile(this.fileSystem).WithContents(this.testFileContents); string renamedFileName = "GVFlt_MoveFileTest\\GitStatusAfterRenameFileIntoRepo.cs"; this.fileSystem.MoveFile(filePath, this.Enlistment.GetVirtualPathTo(renamedFileName)); this.Enlistment.GetVirtualPathTo(filePath).ShouldNotExistOnDisk(this.fileSystem); GitHelpers.CheckGitCommandAgainstGVFSRepo( this.Enlistment.RepoRoot, "status", "On branch " + Properties.Settings.Default.Commitish, "Untracked files:", renamedFileName.Replace('\\', '/')); }
public void CheckoutCleansUpTombstones() { const string folderToDelete = "Scripts"; // Delete directory to create the tombstone string directoryToDelete = this.Enlistment.GetVirtualPathTo(folderToDelete); this.fileSystem.DeleteDirectory(directoryToDelete); this.Enlistment.UnmountGSD(); // Remove the directory entry from modified paths so git will not keep the folder up to date string modifiedPathsFile = Path.Combine(this.Enlistment.DotGSDRoot, TestConstants.Databases.ModifiedPaths); string modifiedPathsContent = this.fileSystem.ReadAllText(modifiedPathsFile); modifiedPathsContent = string.Join(Delimiter, modifiedPathsContent.Split(new[] { Delimiter }, StringSplitOptions.RemoveEmptyEntries).Where(x => !x.StartsWith($"A {folderToDelete}/"))); this.fileSystem.WriteAllText(modifiedPathsFile, modifiedPathsContent + Delimiter); // Add tombstone folder entry to the placeholder database so the checkout will remove the tombstone // and start projecting the folder again string placeholderDatabasePath = Path.Combine(this.Enlistment.DotGSDRoot, TestConstants.Databases.GSD); GSDHelpers.AddPlaceholderFolder(placeholderDatabasePath, folderToDelete, TombstoneFolderPlaceholderType); this.Enlistment.MountGSD(); directoryToDelete.ShouldNotExistOnDisk(this.fileSystem); // checkout branch to remove tombstones and project the folder again GitHelpers.InvokeGitAgainstGSDRepo(this.Enlistment.RepoRoot, "checkout -f HEAD"); directoryToDelete.ShouldBeADirectory(this.fileSystem); this.Enlistment.UnmountGSD(); string placholders = GSDHelpers.GetAllSQLitePlaceholdersAsString(placeholderDatabasePath); placholders.ShouldNotContain(ignoreCase: false, unexpectedSubstrings: $"{folderToDelete}{GSDHelpers.PlaceholderFieldDelimiter}{TombstoneFolderPlaceholderType}{GSDHelpers.PlaceholderFieldDelimiter}"); }
public override async Task <int> ExecuteAsync() { try { IRemote remote = RemoteFactory.GetRemote(_options, _options.Repository, Logger); _options.Branch = GitHelpers.NormalizeBranchName(_options.Branch); if (!(await UxHelpers.VerifyAndConfirmBranchExistsAsync(remote, _options.Repository, _options.Branch, !_options.NoConfirmation))) { Console.WriteLine("Aborting default channel creation."); return(Constants.ErrorCode); } await remote.AddDefaultChannelAsync(_options.Repository, _options.Branch, _options.Channel); return(Constants.SuccessCode); } catch (Exception e) { Logger.LogError(e, "Error: Failed to add a new default channel association."); return(Constants.ErrorCode); } }
public void LockToPreventDelete_SingleFile() { string testFile1Contents = "TestContentsLockToPreventDelete \r\n"; string testFile1Name = "test.txt"; string testFile1Path = this.Enlistment.GetVirtualPathTo(Path.Combine(TestParentFolderName, "LockToPreventDelete", testFile1Name)); testFile1Path.ShouldBeAFile(this.fileSystem).WithContents(testFile1Contents); using (SafeFileHandle testFile1Handle = this.CreateFile(testFile1Path, FileShare.Read)) { testFile1Handle.IsInvalid.ShouldEqual(false); ProcessResult result = this.InvokeGitAgainstGVFSRepo("checkout " + OldCommitId); result.Errors.ShouldContain( "GVFS was unable to delete the following files. To recover, close all handles to the files and run these commands:", "git clean -f " + TestParentFolderName + "/LockToPreventDelete/" + testFile1Name); GitHelpers.CheckGitCommandAgainstGVFSRepo( this.Enlistment.RepoRoot, "status -u", "HEAD detached at " + OldCommitId, "Untracked files:", TestParentFolderName + "/LockToPreventDelete/" + testFile1Name); testFile1Path.ShouldBeAFile(this.fileSystem).WithContents(testFile1Contents); } this.GitCleanFile(TestParentFolderName + "/LockToPreventDelete/" + testFile1Name); this.GitStatusShouldBeClean(OldCommitId); GVFSHelpers.ModifiedPathsShouldContain(this.Enlistment, this.fileSystem, TestParentFolderName + "/LockToPreventDelete/" + testFile1Name); testFile1Path.ShouldNotExistOnDisk(this.fileSystem); this.GitCheckoutCommitId(NewFilesAndChangesCommitId); this.GitStatusShouldBeClean(NewFilesAndChangesCommitId); testFile1Path.ShouldBeAFile(this.fileSystem).WithContents(testFile1Contents); }
public void GitLog() { GitHelpers.CheckGitCommandAgainstGVFSRepo(this.Enlistment.RepoRoot, "log -n1", "commit", "Author:", "Date:"); }
/// <summary> /// Implements the 'add-subscription' operation /// </summary> /// <param name="options"></param> public override async Task <int> ExecuteAsync() { IRemote remote = RemoteFactory.GetBarOnlyRemote(_options, Logger); if (_options.IgnoreChecks.Count() > 0 && !_options.AllChecksSuccessfulMergePolicy) { Console.WriteLine($"--ignore-checks must be combined with --all-checks-passed"); return(Constants.ErrorCode); } // Parse the merge policies List <MergePolicy> mergePolicies = new List <MergePolicy>(); if (_options.NoExtraCommitsMergePolicy) { mergePolicies.Add( new MergePolicy { Name = MergePolicyConstants.NoExtraCommitsMergePolicyName }); } if (_options.AllChecksSuccessfulMergePolicy) { mergePolicies.Add( new MergePolicy { Name = MergePolicyConstants.AllCheckSuccessfulMergePolicyName, Properties = ImmutableDictionary.Create <string, JToken>() .Add(MergePolicyConstants.IgnoreChecksMergePolicyPropertyName, JToken.FromObject(_options.IgnoreChecks)) }); } if (_options.NoRequestedChangesMergePolicy) { mergePolicies.Add( new MergePolicy { Name = MergePolicyConstants.NoRequestedChangesMergePolicyName, Properties = ImmutableDictionary.Create <string, JToken>() }); } if (_options.StandardAutoMergePolicies) { mergePolicies.Add( new MergePolicy { Name = MergePolicyConstants.StandardMergePolicyName, Properties = ImmutableDictionary.Create <string, JToken>() }); } if (_options.Batchable && mergePolicies.Count > 0) { Console.WriteLine("Batchable subscriptions cannot be combined with merge policies. " + "Merge policies are specified at a repository+branch level."); return(Constants.ErrorCode); } string channel = _options.Channel; string sourceRepository = _options.SourceRepository; string targetRepository = _options.TargetRepository; string targetBranch = GitHelpers.NormalizeBranchName(_options.TargetBranch); string updateFrequency = _options.UpdateFrequency; bool batchable = _options.Batchable; // If in quiet (non-interactive mode), ensure that all options were passed, then // just call the remote API if (_options.Quiet && !_options.ReadStandardIn) { if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(sourceRepository) || string.IsNullOrEmpty(targetRepository) || string.IsNullOrEmpty(targetBranch) || string.IsNullOrEmpty(updateFrequency) || !Constants.AvailableFrequencies.Contains(updateFrequency, StringComparer.OrdinalIgnoreCase)) { Logger.LogError($"Missing input parameters for the subscription. Please see command help or remove --quiet/-q for interactive mode"); return(Constants.ErrorCode); } } else { // Grab existing subscriptions to get suggested values. // TODO: When this becomes paged, set a max number of results to avoid // pulling too much. var suggestedRepos = remote.GetSubscriptionsAsync(); var suggestedChannels = remote.GetChannelsAsync(); // Help the user along with a form. We'll use the API to gather suggested values // from existing subscriptions based on the input parameters. AddSubscriptionPopUp addSubscriptionPopup = new AddSubscriptionPopUp("add-subscription/add-subscription-todo", Logger, channel, sourceRepository, targetRepository, targetBranch, updateFrequency, batchable, mergePolicies, (await suggestedChannels).Select(suggestedChannel => suggestedChannel.Name), (await suggestedRepos).SelectMany(subscription => new List <string> { subscription.SourceRepository, subscription.TargetRepository }).ToHashSet(), Constants.AvailableFrequencies, Constants.AvailableMergePolicyYamlHelp); UxManager uxManager = new UxManager(_options.GitLocation, Logger); int exitCode = _options.ReadStandardIn ? uxManager.ReadFromStdIn(addSubscriptionPopup) : uxManager.PopUp(addSubscriptionPopup); if (exitCode != Constants.SuccessCode) { return(exitCode); } channel = addSubscriptionPopup.Channel; sourceRepository = addSubscriptionPopup.SourceRepository; targetRepository = addSubscriptionPopup.TargetRepository; targetBranch = addSubscriptionPopup.TargetBranch; updateFrequency = addSubscriptionPopup.UpdateFrequency; mergePolicies = addSubscriptionPopup.MergePolicies; batchable = addSubscriptionPopup.Batchable; } try { // If we are about to add a batchable subscription and the merge policies are empty for the // target repo/branch, warn the user. if (batchable) { var existingMergePolicies = await remote.GetRepositoryMergePoliciesAsync(targetRepository, targetBranch); if (!existingMergePolicies.Any()) { Console.WriteLine("Warning: Batchable subscription doesn't have any repository merge policies. " + "PRs will not be auto-merged."); Console.WriteLine($"Please use 'darc set-repository-policies --repo {targetRepository} --branch {targetBranch}' " + $"to set policies.{Environment.NewLine}"); } } // Verify the target IRemote targetVerifyRemote = RemoteFactory.GetRemote(_options, targetRepository, Logger); if (!(await UxHelpers.VerifyAndConfirmBranchExistsAsync(targetVerifyRemote, targetRepository, targetBranch, !_options.Quiet))) { Console.WriteLine("Aborting subscription creation."); return(Constants.ErrorCode); } // Verify the source. IRemote sourceVerifyRemote = RemoteFactory.GetRemote(_options, sourceRepository, Logger); if (!(await UxHelpers.VerifyAndConfirmRepositoryExistsAsync(sourceVerifyRemote, sourceRepository, !_options.Quiet))) { Console.WriteLine("Aborting subscription creation."); return(Constants.ErrorCode); } var newSubscription = await remote.CreateSubscriptionAsync(channel, sourceRepository, targetRepository, targetBranch, updateFrequency, batchable, mergePolicies); Console.WriteLine($"Successfully created new subscription with id '{newSubscription.Id}'."); // Prompt the user to trigger the subscription unless they have explicitly disallowed it if (!_options.NoTriggerOnCreate) { bool triggerAutomatically = _options.TriggerOnCreate || UxHelpers.PromptForYesNo("Trigger this subscription immediately?"); if (triggerAutomatically) { await remote.TriggerSubscriptionAsync(newSubscription.Id.ToString()); Console.WriteLine($"Subscription '{newSubscription.Id}' triggered."); } } return(Constants.SuccessCode); } catch (AuthenticationException e) { Console.WriteLine(e.Message); return(Constants.ErrorCode); } catch (RestApiException e) when(e.Response.Status == (int)System.Net.HttpStatusCode.BadRequest) { // Could have been some kind of validation error (e.g. channel doesn't exist) Logger.LogError($"Failed to create subscription: {e.Response.Content}"); return(Constants.ErrorCode); } catch (Exception e) { Logger.LogError(e, $"Failed to create subscription."); return(Constants.ErrorCode); } }
private void GitCheckoutToDiscardChanges(string gitPath) { GitHelpers.CheckGitCommandAgainstGVFSRepo(this.Enlistment.RepoRoot, "checkout -- " + gitPath); }