Skip to content

Commit

Permalink
[File Explorer Integration] Git submodule status and commit log insid…
Browse files Browse the repository at this point in the history
…e submodule (#3745)
  • Loading branch information
DefaultRyan committed Sep 7, 2024
1 parent 23d5a14 commit 229084a
Show file tree
Hide file tree
Showing 244 changed files with 974 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,13 @@
<ItemGroup>
<ProjectReference Include="..\FileExplorerGitIntegration\FileExplorerGitIntegration.csproj" />
</ItemGroup>
<ItemGroup>
<Content Include="resources\**\*.*" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<ItemGroup>
<None Remove="resources\resources_readme.txt" />
</ItemGroup>
<ItemGroup>
<Content Include="SandboxHelper.cs" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using FileExplorerGitIntegration.Models;

namespace FileExplorerGitIntegration.UnitTest;

[TestClass]
public class GitSubmoduleUnitTests
{
private const string FolderStatusProp = "System.VersionControl.CurrentFolderStatus";
private const string StatusProp = "System.VersionControl.Status";
private const string ShaProp = "System.VersionControl.LastChangeID";

private static SandboxHelper? _sandbox;
private static GitLocalRepository? _repo;

[ClassInitialize]
public static void ClassInitialize(TestContext testContext)
{
_sandbox = new();
var repoPath = _sandbox.CreateSandbox("submodules");
_sandbox.CreateSandbox("submodules_target");
_repo = new GitLocalRepository(repoPath);
}

[ClassCleanup]
public static void ClassCleanup()
{
if (_sandbox is not null)
{
_sandbox.Cleanup();
_sandbox = null;
}

_repo = null;
}

[TestMethod]
[DataRow("", FolderStatusProp, "Branch: main | +1 ~1 -0 | +0 ~7 -0")]
[DataRow(".gitmodules", StatusProp, "Staged, Modified")]
[DataRow("README.txt", StatusProp, "")]
[DataRow("sm_added_and_uncommitted", StatusProp, "Submodule Added")]
[DataRow("sm_changed_file", StatusProp, "Submodule Dirty")]
[DataRow("sm_changed_head", StatusProp, "Submodule Changed")]
[DataRow("sm_changed_index", StatusProp, "Submodule Dirty")]
[DataRow("sm_changed_untracked_file", StatusProp, "Submodule Dirty")]
[DataRow("sm_missing_commits", StatusProp, "Submodule Changed")]
[DataRow("sm_missing_commits_detached", StatusProp, "Submodule Changed")]
[DataRow("sm_unchanged", StatusProp, "")]
[DataRow("sm_unchanged_detached", StatusProp, "")]
public void RootFolderStatus(string path, string property, string value)
{
Assert.IsNotNull(_repo);
var result = _repo.GetProperties([property], path);
Assert.IsNotNull(result);
Assert.AreEqual(value, result[property]);
}

[TestMethod]
[DataRow("", ShaProp, "8a303a1d530d9d4e9f31002d4c9d1d8f1cd78940")]
[DataRow(".gitmodules", ShaProp, "d8ebdc0b3c1d5240d4fc1c4cd3728ff561e714ad")]
[DataRow("README.txt", ShaProp, "74b157c3bfd2f24323c3bc6e5e96639a424f157f")]
[DataRow("sm_added_and_uncommitted", ShaProp, "")]
[DataRow("sm_changed_file", ShaProp, "8a303a1d530d9d4e9f31002d4c9d1d8f1cd78940")]
[DataRow("sm_changed_head", ShaProp, "8a303a1d530d9d4e9f31002d4c9d1d8f1cd78940")]
[DataRow("sm_changed_index", ShaProp, "8a303a1d530d9d4e9f31002d4c9d1d8f1cd78940")]
[DataRow("sm_changed_untracked_file", ShaProp, "8a303a1d530d9d4e9f31002d4c9d1d8f1cd78940")]
[DataRow("sm_missing_commits", ShaProp, "8a303a1d530d9d4e9f31002d4c9d1d8f1cd78940")]
[DataRow("sm_missing_commits_detached", ShaProp, "8a303a1d530d9d4e9f31002d4c9d1d8f1cd78940")]
[DataRow("sm_unchanged", ShaProp, "8a303a1d530d9d4e9f31002d4c9d1d8f1cd78940")]
[DataRow("sm_unchanged_detached", ShaProp, "8a303a1d530d9d4e9f31002d4c9d1d8f1cd78940")]
public void RootFolderCommit(string path, string property, string value)
{
Assert.IsNotNull(_repo);
var result = _repo.GetProperties([property], path);
Assert.IsNotNull(result);
if (result.TryGetValue(property, out var actual))
{
Assert.AreEqual(value, actual);
}
else
{
Assert.AreEqual(value, string.Empty);
}
}

[TestMethod]
[DataRow("sm_added_and_uncommitted\\file_to_modify", ShaProp, "e9a899083a7e2b25d7a41e69463ce083bf9ef6ef")]
[DataRow("sm_changed_file\\file_to_modify", ShaProp, "e9a899083a7e2b25d7a41e69463ce083bf9ef6ef")]
[DataRow("sm_changed_head\\file_to_modify", ShaProp, "2ab664114c928551863c33d694965c79b6b75144")]
[DataRow("sm_changed_index\\file_to_modify", ShaProp, "e9a899083a7e2b25d7a41e69463ce083bf9ef6ef")]
[DataRow("sm_changed_untracked_file\\file_to_modify", ShaProp, "e9a899083a7e2b25d7a41e69463ce083bf9ef6ef")]
[DataRow("sm_missing_commits\\file_to_modify", ShaProp, "8e623bcf5aeceb8af7c0f0b22b82322f6c82fd4b")]
[DataRow("sm_missing_commits_detached\\file_to_modify", ShaProp, "8e623bcf5aeceb8af7c0f0b22b82322f6c82fd4b")]
[DataRow("sm_unchanged\\file_to_modify", ShaProp, "e9a899083a7e2b25d7a41e69463ce083bf9ef6ef")]
[DataRow("sm_unchanged_detached\\file_to_modify", ShaProp, "e9a899083a7e2b25d7a41e69463ce083bf9ef6ef")]
public void SubmoduleFilesCommit(string path, string property, string value)
{
Assert.IsNotNull(_repo);
var result = _repo.GetProperties([property], path);
Assert.IsNotNull(result);
if (result.TryGetValue(property, out var actual))
{
Assert.AreEqual(value, actual);
}
else
{
Assert.AreEqual(value, string.Empty);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using Serilog;

namespace FileExplorerGitIntegration.UnitTest;

internal sealed class SandboxHelper
{
private readonly Serilog.ILogger _log = Log.ForContext("SourceContext", nameof(SandboxHelper));

private readonly Dictionary<string, string> _renames = new()
{
{ "dot-git", ".git" },
{ "dot-gitmodules", ".gitmodules" },
};

public DirectoryInfo ResourcesDirectory { get; private set; }

public DirectoryInfo DeployedDirectory { get; private set; }

public SandboxHelper()
{
var parentDir = Directory.GetParent(typeof(SandboxHelper).Assembly.Location) ?? throw new InvalidOperationException("Could not obtain resources directory for sandbox repos");
ResourcesDirectory = new DirectoryInfo(Path.Combine(parentDir.FullName, "resources"));
DeployedDirectory = Directory.CreateTempSubdirectory("SandboxHelper.");
}

public void Cleanup()
{
try
{
Directory.Delete(DeployedDirectory.FullName, true);
}
catch (Exception ex)
{
_log.Warning(ex, $"Failed to delete temp directory {DeployedDirectory.FullName}");
throw;
}
}

public string CreateSandbox(string directory)
{
var source = new DirectoryInfo(Path.Combine(ResourcesDirectory.FullName, directory));
var target = new DirectoryInfo(Path.Combine(DeployedDirectory.FullName, directory));
CopyRecursive(source, target);

return target.FullName;
}

private void CopyRecursive(DirectoryInfo source, DirectoryInfo target)
{
foreach (var dir in source.GetDirectories())
{
CopyRecursive(dir, target.CreateSubdirectory(FixName(dir.Name)));
}

foreach (var file in source.GetFiles())
{
file.CopyTo(Path.Combine(target.FullName, FixName(file.Name)));
}
}

private string FixName(string name)
{
_renames.TryGetValue(name, out var newName);
return newName ?? name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
* binary
.gitattributes diff
.gitignore diff
config diff
resources_readme.txt diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
COMMIT_EDITMSG
exclude
logs/
description
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
The folders under "resources" are Git repositories that have had ".git" renamed to "dot-git" and ".gitmodules" renamed to "dot-gitmodules".

This makes Git treat them as normal files so they can be checked in. SandboxHelper will rename them back to ".git" and ".gitmodules" when it needs to "clone" the repos for testing.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
This is a submodule test repo.
It has various submodules in different states.
Inspired by unit tests in libgit2.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ref: refs/heads/main
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3e1e770f7c28e87cbb3ee0c1541e3417c84a0708
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[core]
repositoryformatversion = 0
filemode = false
bare = false
logallrefupdates = true
symlinks = false
ignorecase = true
[submodule "sm_changed_file"]
url = E:/Repos/GitHub/devhome/extensions/GitExtension/FileExplorerGitIntegration.UnitTest/resources/submodules_target
active = true
[submodule "sm_missing_commits"]
url = E:/Repos/GitHub/devhome/extensions/GitExtension/FileExplorerGitIntegration.UnitTest/resources/submodules_target
active = true
[submodule "sm_changed_head"]
url = E:/Repos/GitHub/devhome/extensions/GitExtension/FileExplorerGitIntegration.UnitTest/resources/submodules_target
active = true
[submodule "sm_changed_index"]
url = E:/Repos/GitHub/devhome/extensions/GitExtension/FileExplorerGitIntegration.UnitTest/resources/submodules_target
active = true
[submodule "sm_changed_untracked_file"]
url = E:/Repos/GitHub/devhome/extensions/GitExtension/FileExplorerGitIntegration.UnitTest/resources/submodules_target
active = true
[submodule "sm_unchanged"]
url = E:/Repos/GitHub/devhome/extensions/GitExtension/FileExplorerGitIntegration.UnitTest/resources/submodules_target
active = true
[submodule "sm_unchanged_detached"]
url = E:/Repos/GitHub/devhome/extensions/GitExtension/FileExplorerGitIntegration.UnitTest/resources/submodules_target
active = true
[submodule "sm_missing_commits_detached"]
url = E:/Repos/GitHub/devhome/extensions/GitExtension/FileExplorerGitIntegration.UnitTest/resources/submodules_target
active = true
[submodule "sm_added_and_uncommitted"]
url = E:/temp/resources/submodules_target
active = true
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Unnamed repository; edit this file 'description' to name the repository.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
8a303a1d530d9d4e9f31002d4c9d1d8f1cd78940 refs/heads/main
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ref: refs/heads/main
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[core]
repositoryformatversion = 0
filemode = false
bare = false
logallrefupdates = true
symlinks = false
ignorecase = true
worktree = ../../../sm_added_and_uncommitted
[remote "origin"]
url = E:/temp/resources/submodules_target
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
remote = origin
merge = refs/heads/main
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Unnamed repository; edit this file 'description' to name the repository.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
8bc132afeabc5cbf67bdaf4f92c3e391472a27dc refs/heads/main
8bc132afeabc5cbf67bdaf4f92c3e391472a27dc refs/remotes/origin/HEAD
8bc132afeabc5cbf67bdaf4f92c3e391472a27dc refs/remotes/origin/main
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
P pack-d3b1b7cf66ad317ab08fb781dba8d8ae68e1b200.pack
P pack-ffa30a089fdbfcfdaaea163fd2f9710ef01a00cf.pack

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# pack-refs with: peeled fully-peeled sorted
8bc132afeabc5cbf67bdaf4f92c3e391472a27dc refs/heads/main
8bc132afeabc5cbf67bdaf4f92c3e391472a27dc refs/remotes/origin/main
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ref: refs/remotes/origin/main
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
8bc132afeabc5cbf67bdaf4f92c3e391472a27dc not-for-merge branch 'main' of ../../submodules_target
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ref: refs/heads/main
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
e9a899083a7e2b25d7a41e69463ce083bf9ef6ef
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[core]
repositoryformatversion = 0
filemode = false
bare = false
logallrefupdates = true
symlinks = false
ignorecase = true
worktree = ../../../sm_changed_file
[remote "origin"]
url = ../../submodules_target
fetch = +refs/heads/*:refs/remotes/origin/*
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Unnamed repository; edit this file 'description' to name the repository.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
8bc132afeabc5cbf67bdaf4f92c3e391472a27dc refs/heads/main
8bc132afeabc5cbf67bdaf4f92c3e391472a27dc refs/remotes/origin/main
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
P pack-d3b1b7cf66ad317ab08fb781dba8d8ae68e1b200.pack
P pack-ffa30a089fdbfcfdaaea163fd2f9710ef01a00cf.pack

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# pack-refs with: peeled fully-peeled sorted
8bc132afeabc5cbf67bdaf4f92c3e391472a27dc refs/heads/main
8bc132afeabc5cbf67bdaf4f92c3e391472a27dc refs/remotes/origin/main
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Committing a change to submodule
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
8bc132afeabc5cbf67bdaf4f92c3e391472a27dc not-for-merge branch 'main' of ../../submodules_target
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ref: refs/heads/main
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
4bb90658751b1d839ee1277368998be69deacca5
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[core]
repositoryformatversion = 0
filemode = false
bare = false
logallrefupdates = true
symlinks = false
ignorecase = true
worktree = ../../../sm_changed_head
[remote "origin"]
url = ../../submodules_target
fetch = +refs/heads/*:refs/remotes/origin/*
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Unnamed repository; edit this file 'description' to name the repository.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
2ab664114c928551863c33d694965c79b6b75144 refs/heads/main
8bc132afeabc5cbf67bdaf4f92c3e391472a27dc refs/remotes/origin/main
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
P pack-d3b1b7cf66ad317ab08fb781dba8d8ae68e1b200.pack
P pack-9201333783142a88b5199747b1d4aa993fd8df68.pack

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# pack-refs with: peeled fully-peeled sorted
2ab664114c928551863c33d694965c79b6b75144 refs/heads/main
8bc132afeabc5cbf67bdaf4f92c3e391472a27dc refs/remotes/origin/main
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
8bc132afeabc5cbf67bdaf4f92c3e391472a27dc not-for-merge branch 'main' of ../../submodules_target
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ref: refs/heads/main
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
e9a899083a7e2b25d7a41e69463ce083bf9ef6ef
Loading

0 comments on commit 229084a

Please sign in to comment.