public void GitConfiguration_GetString_Name_DoesNotExists_ThrowsException() { string repoPath = CreateRepository(); string gitPath = GetGitPath(); var trace = new NullTrace(); var git = new GitProcess(trace, gitPath, repoPath); IGitConfiguration config = git.GetConfiguration(); string randomName = $"{Guid.NewGuid():N}.{Guid.NewGuid():N}"; Assert.Throws <KeyNotFoundException>(() => config.Get(randomName)); }
public Task UnconfigureAsync( IEnvironment environment, EnvironmentVariableTarget environmentTarget, IGit git, GitConfigurationLevel configurationLevel) { string useHttpPathKey = $"{KnownGitCfg.Credential.SectionName}.https://dev.azure.com.{KnownGitCfg.Credential.UseHttpPath}"; Context.Trace.WriteLine("Clearing Git configuration 'credential.useHttpPath' for https://dev.azure.com..."); IGitConfiguration targetConfig = git.GetConfiguration(configurationLevel); targetConfig.Unset(useHttpPathKey); return(Task.CompletedTask); }
public void GitConfiguration_GetString_SectionProperty_DoesNotExists_ThrowsException() { string repoPath = CreateRepository(); string gitPath = GetGitPath(); var trace = new NullTrace(); var git = new GitProcess(trace, gitPath, repoPath); IGitConfiguration config = git.GetConfiguration(); string randomSection = Guid.NewGuid().ToString("N"); string randomProperty = Guid.NewGuid().ToString("N"); Assert.Throws <KeyNotFoundException>(() => config.Get(randomSection, randomProperty)); }
public IEnumerable <AzureReposBinding> GetBindings(string orgName = null) { var globalUsers = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); var localUsers = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); IGitConfiguration config = _git.GetConfiguration(); string orgPrefix = $"{AzureDevOpsConstants.UrnOrgPrefix}/"; bool ExtractUserBinding(GitConfigurationEntry entry, IDictionary <string, string> dict) { if (GitConfigurationKeyComparer.TrySplit(entry.Key, out _, out string scope, out _) && Uri.TryCreate(scope, UriKind.Absolute, out Uri uri) && uri.Scheme == AzureDevOpsConstants.UrnScheme && uri.AbsolutePath.StartsWith(orgPrefix)) { string entryOrgName = uri.AbsolutePath.Substring(orgPrefix.Length); if (string.IsNullOrWhiteSpace(orgName) || StringComparer.OrdinalIgnoreCase.Equals(entryOrgName, orgName)) { dict[entryOrgName] = entry.Value; } } return(true); } // Only enumerate local configuration if we are inside a repository if (_git.IsInsideRepository()) { config.Enumerate( GitConfigurationLevel.Local, Constants.GitConfiguration.Credential.SectionName, Constants.GitConfiguration.Credential.UserName, entry => ExtractUserBinding(entry, localUsers)); } config.Enumerate( GitConfigurationLevel.Global, Constants.GitConfiguration.Credential.SectionName, Constants.GitConfiguration.Credential.UserName, entry => ExtractUserBinding(entry, globalUsers)); foreach (string org in globalUsers.Keys.Union(localUsers.Keys)) { // NOT using the short-circuiting OR operator here on purpose - we need both branches to be evaluated if (globalUsers.TryGetValue(org, out string globalUser) | localUsers.TryGetValue(org, out string localUser)) { yield return(new AzureReposBinding(org, globalUser, localUser)); } } }
public string GetAuthority(string orgName) { EnsureArgument.NotNullOrWhiteSpace(orgName, nameof(orgName)); _trace.WriteLine($"Looking up cached authority for organization '{orgName}'..."); IGitConfiguration config = _git.GetConfiguration(); if (config.TryGet(GitConfigurationLevel.Global, GetAuthorityKey(orgName), out string authority)) { return(authority); } return(null); }
public void GitConfiguration_Set_Local_SetsLocalConfig() { string repoPath = CreateRepository(out string workDirPath); string gitPath = GetGitPath(); var trace = new NullTrace(); var git = new GitProcess(trace, gitPath, repoPath); IGitConfiguration config = git.GetConfiguration(GitConfigurationLevel.Local); config.Set("core.foobar", "foo123"); GitResult localResult = Git(repoPath, workDirPath, "config --local core.foobar"); Assert.Equal("foo123", localResult.StandardOutput.Trim()); }
public Task UnconfigureAsync( IEnvironment environment, EnvironmentVariableTarget environmentTarget, IGitConfiguration configuration, GitConfigurationLevel configurationLevel) { string useHttpPathKey = $"{KnownGitCfg.Credential.SectionName}.https://dev.azure.com.{KnownGitCfg.Credential.UseHttpPath}"; Context.Trace.WriteLine("Clearing Git configuration 'credential.useHttpPath' for https://dev.azure.com..."); using (IGitConfiguration targetConfig = configuration.GetFilteredConfiguration(configurationLevel)) { targetConfig.DeleteEntry(useHttpPathKey); } return(Task.CompletedTask); }
public void GitConfiguration_TryGet_Name_DoesNotExists_ReturnsFalse() { string repoPath = CreateRepository(); string gitPath = GetGitPath(); var trace = new NullTrace(); var git = new GitProcess(trace, gitPath, repoPath); IGitConfiguration config = git.GetConfiguration(); string randomName = $"{Guid.NewGuid():N}.{Guid.NewGuid():N}"; bool result = config.TryGet(randomName, out string value); Assert.False(result); Assert.Null(value); }
public Task UnconfigureAsync(ConfigurationTarget target) { string useHttpPathKey = $"{KnownGitCfg.Credential.SectionName}.https://dev.azure.com.{KnownGitCfg.Credential.UseHttpPath}"; _context.Trace.WriteLine("Clearing Git configuration 'credential.useHttpPath' for https://dev.azure.com..."); GitConfigurationLevel configurationLevel = target == ConfigurationTarget.System ? GitConfigurationLevel.System : GitConfigurationLevel.Global; IGitConfiguration targetConfig = _context.Git.GetConfiguration(configurationLevel); targetConfig.Unset(useHttpPathKey); return(Task.CompletedTask); }
public void GitConfiguration_Get_Name_Exists_ReturnsString() { string repoPath = CreateRepository(out string workDirPath); ExecGit(repoPath, workDirPath, "config --local user.name john.doe").AssertSuccess(); string gitPath = GetGitPath(); var trace = new NullTrace(); var git = new GitProcess(trace, gitPath, repoPath); IGitConfiguration config = git.GetConfiguration(); string value = config.Get("user.name"); Assert.NotNull(value); Assert.Equal("john.doe", value); }
public void GitConfiguration_GetString_SectionScopeProperty_NullScope_ReturnsUnscopedString() { string repoPath = CreateRepository(out string workDirPath); Git(repoPath, workDirPath, "config --local user.name john.doe").AssertSuccess(); string gitPath = GetGitPath(); var trace = new NullTrace(); var git = new GitProcess(trace, gitPath, repoPath); IGitConfiguration config = git.GetConfiguration(); string value = config.Get("user", null, "name"); Assert.NotNull(value); Assert.Equal("john.doe", value); }
public void GitConfiguration_TryGet_SectionProperty_DoesNotExists_ReturnsFalse() { string repoPath = CreateRepository(); string gitPath = GetGitPath(); var trace = new NullTrace(); var git = new GitProcess(trace, gitPath, repoPath); IGitConfiguration config = git.GetConfiguration(); string randomSection = Guid.NewGuid().ToString("N"); string randomProperty = Guid.NewGuid().ToString("N"); bool result = config.TryGet(randomSection, randomProperty, out string value); Assert.False(result); Assert.Null(value); }
Task IConfigurableComponent.ConfigureAsync(ConfigurationTarget target) { string helperKey = $"{Constants.GitConfiguration.Credential.SectionName}.{Constants.GitConfiguration.Credential.Helper}"; string appPath = GetGitConfigAppPath(); GitConfigurationLevel configLevel = target == ConfigurationTarget.System ? GitConfigurationLevel.System : GitConfigurationLevel.Global; Context.Trace.WriteLine($"Configuring for config level '{configLevel}'."); IGitConfiguration config = Context.Git.GetConfiguration(configLevel); // We are looking for the following to be set in the config: // // [credential] // ... # any number of helper entries (possibly none) // helper = # an empty value to reset/clear any previous entries (if applicable) // helper = {appPath} # the expected executable value & directly following the empty value // ... # any number of helper entries (possibly none, but not the empty value '') // string[] currentValues = config.GetAll(helperKey).ToArray(); // Try to locate an existing app entry with a blank reset/clear entry immediately preceding, // and no other blank empty/clear entries following (which effectively disable us). int appIndex = Array.FindIndex(currentValues, x => Context.FileSystem.IsSamePath(x, appPath)); int lastEmptyIndex = Array.FindLastIndex(currentValues, string.IsNullOrWhiteSpace); if (appIndex > 0 && string.IsNullOrWhiteSpace(currentValues[appIndex - 1]) && lastEmptyIndex < appIndex) { Context.Trace.WriteLine("Credential helper configuration is already set correctly."); } else { Context.Trace.WriteLine("Updating Git credential helper configuration..."); // Clear any existing app entries in the configuration config.UnsetAll(helperKey, Regex.Escape(appPath)); // Add an empty value for `credential.helper`, which has the effect of clearing any helper value // from any lower-level Git configuration, then add a second value which is the actual executable path. config.Add(helperKey, string.Empty); config.Add(helperKey, appPath); } return(Task.CompletedTask); }
public void GitConfiguration_TryGet_SectionScopeProperty_Exists_ReturnsTrueOutString() { string repoPath = CreateRepository(out string workDirPath); Git(repoPath, workDirPath, "config --local user.example.com.name john.doe").AssertSuccess(); string gitPath = GetGitPath(); var trace = new NullTrace(); var git = new GitProcess(trace, gitPath, repoPath); IGitConfiguration config = git.GetConfiguration(); bool result = config.TryGet("user", "example.com", "name", out string value); Assert.True(result); Assert.NotNull(value); Assert.Equal("john.doe", value); }
Task IConfigurableComponent.UnconfigureAsync(ConfigurationTarget target) { string helperKey = $"{Constants.GitConfiguration.Credential.SectionName}.{Constants.GitConfiguration.Credential.Helper}"; string appPath = GetGitConfigAppPath(); GitConfigurationLevel configLevel = target == ConfigurationTarget.System ? GitConfigurationLevel.System : GitConfigurationLevel.Global; Context.Trace.WriteLine($"Unconfiguring for config level '{configLevel}'."); IGitConfiguration config = Context.Git.GetConfiguration(configLevel); // We are looking for the following to be set in the config: // // [credential] // ... # any number of helper entries (possibly none) // helper = # an empty value to reset/clear any previous entries (if applicable) // helper = {appPath} # the expected executable value & directly following the empty value // ... # any number of helper entries (possibly none) // // We should remove the {appPath} entry, and any blank entries immediately preceding IFF there are no more entries following. // Context.Trace.WriteLine("Removing Git credential helper configuration..."); string[] currentValues = config.GetAll(helperKey).ToArray(); int appIndex = Array.FindIndex(currentValues, x => Context.FileSystem.IsSamePath(x, appPath)); if (appIndex > -1) { // Check for the presence of a blank entry immediately preceding an app entry in the last position if (appIndex > 0 && appIndex == currentValues.Length - 1 && string.IsNullOrWhiteSpace(currentValues[appIndex - 1])) { // Clear the blank entry config.UnsetAll(helperKey, Constants.RegexPatterns.Empty); } // Clear app entry config.UnsetAll(helperKey, Regex.Escape(appPath)); } return(Task.CompletedTask); }
public void GitConfiguration_TryGet_IsPath_False_ReturnsRawConfig() { string repoPath = CreateRepository(out string workDirPath); ExecGit(repoPath, workDirPath, "config --local example.path ~/test").AssertSuccess(); string gitPath = GetGitPath(); var trace = new NullTrace(); var env = new TestEnvironment(); var git = new GitProcess(trace, env, gitPath, repoPath); IGitConfiguration config = git.GetConfiguration(); bool result = config.TryGet("example.path", false, out string value); Assert.True(result); Assert.NotNull(value); Assert.Equal($"~/test", value); }
public void GitConfiguration_TryGet_Name_Exists_ReturnsTrueOutString() { string repoPath = CreateRepository(out string workDirPath); ExecGit(repoPath, workDirPath, "config --local user.name john.doe").AssertSuccess(); string gitPath = GetGitPath(); var trace = new NullTrace(); var env = new TestEnvironment(); var git = new GitProcess(trace, env, gitPath, repoPath); IGitConfiguration config = git.GetConfiguration(); bool result = config.TryGet("user.name", false, out string value); Assert.True(result); Assert.NotNull(value); Assert.Equal("john.doe", value); }
public void GitConfiguration_TryGet_BoolWithoutType_ReturnsRawConfig() { string repoPath = CreateRepository(out string workDirPath); ExecGit(repoPath, workDirPath, "config --local example.bool fAlSe").AssertSuccess(); string gitPath = GetGitPath(); var trace = new NullTrace(); var env = new TestEnvironment(); var git = new GitProcess(trace, env, gitPath, repoPath); IGitConfiguration config = git.GetConfiguration(); bool result = config.TryGet(GitConfigurationLevel.Local, GitConfigurationType.Raw, "example.bool", out string value); Assert.True(result); Assert.NotNull(value); Assert.Equal("fAlSe", value); }
public void GitConfiguration_UnsetAll_UnsetsAllConfig() { string repoPath = CreateRepository(out string workDirPath); Git(repoPath, workDirPath, "config --local --add core.foobar foo1").AssertSuccess(); Git(repoPath, workDirPath, "config --local --add core.foobar foo2").AssertSuccess(); Git(repoPath, workDirPath, "config --local --add core.foobar bar1").AssertSuccess(); string gitPath = GetGitPath(); var trace = new NullTrace(); var git = new GitProcess(trace, gitPath, repoPath); IGitConfiguration config = git.GetConfiguration(GitConfigurationLevel.Local); config.UnsetAll("core.foobar", "foo*"); GitResult result = Git(repoPath, workDirPath, "config --local --get-all core.foobar"); Assert.Equal("bar1", result.StandardOutput.Trim()); }
public void GitConfiguration_TryGet_IsPath_True_ReturnsCanonicalPath() { string repoPath = CreateRepository(out string workDirPath); ExecGit(repoPath, workDirPath, "config --local example.path ~/test").AssertSuccess(); string homeDirectory = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); string gitPath = GetGitPath(); var trace = new NullTrace(); var env = new TestEnvironment(); var git = new GitProcess(trace, env, gitPath, repoPath); IGitConfiguration config = git.GetConfiguration(); bool result = config.TryGet("example.path", true, out string value); Assert.True(result); Assert.NotNull(value); Assert.Equal(Path.GetFullPath($"{homeDirectory}/test").Replace("\\", "/"), value); }
public AzureReposBinding GetBinding(string orgName) { EnsureArgument.NotNullOrWhiteSpace(orgName, nameof(orgName)); string orgKey = GetOrgUserKey(orgName); IGitConfiguration config = _git.GetConfiguration(); _trace.WriteLine($"Looking up organization binding for '{orgName}'..."); // NOT using the short-circuiting OR operator here on purpose - we need both branches to be evaluated if (config.TryGet(GitConfigurationLevel.Local, orgKey, out string localUser) | config.TryGet(GitConfigurationLevel.Global, orgKey, out string globalUser)) { return(new AzureReposBinding(orgName, globalUser, localUser)); } // No bound user return(null); }
public Task ConfigureAsync( IEnvironment environment, EnvironmentVariableTarget environmentTarget, IGit git, GitConfigurationLevel configurationLevel) { string useHttpPathKey = $"{KnownGitCfg.Credential.SectionName}.https://dev.azure.com.{KnownGitCfg.Credential.UseHttpPath}"; IGitConfiguration targetConfig = git.GetConfiguration(configurationLevel); if (targetConfig.TryGetValue(useHttpPathKey, out string currentValue) && currentValue.IsTruthy()) { Context.Trace.WriteLine("Git configuration 'credential.useHttpPath' is already set to 'true' for https://dev.azure.com."); } else { Context.Trace.WriteLine("Setting Git configuration 'credential.useHttpPath' to 'true' for https://dev.azure.com..."); targetConfig.SetValue(useHttpPathKey, "true"); } return(Task.CompletedTask); }
private async Task RunAsync(ConfigurationTarget target, bool configure) { GitConfigurationLevel configLevel; EnvironmentVariableTarget envTarget; switch (target) { case ConfigurationTarget.User: configLevel = GitConfigurationLevel.Global; envTarget = EnvironmentVariableTarget.User; break; case ConfigurationTarget.System: configLevel = GitConfigurationLevel.System; envTarget = EnvironmentVariableTarget.Machine; break; default: throw new ArgumentOutOfRangeException(nameof(target)); } using (IGitConfiguration config = _context.Git.GetConfiguration()) { foreach (IConfigurableComponent component in _components) { if (configure) { _context.Trace.WriteLine($"Configuring component '{component.Name}'..."); _context.Streams.Error.WriteLine($"Configuring component '{component.Name}'..."); await component.ConfigureAsync(_context.Environment, envTarget, config, configLevel); } else { _context.Trace.WriteLine($"Unconfiguring component '{component.Name}'..."); _context.Streams.Error.WriteLine($"Unconfiguring component '{component.Name}'..."); await component.UnconfigureAsync(_context.Environment, envTarget, config, configLevel); } } } }
public Task ConfigureAsync(ConfigurationTarget target) { string useHttpPathKey = $"{KnownGitCfg.Credential.SectionName}.https://dev.azure.com.{KnownGitCfg.Credential.UseHttpPath}"; GitConfigurationLevel configurationLevel = target == ConfigurationTarget.System ? GitConfigurationLevel.System : GitConfigurationLevel.Global; IGitConfiguration targetConfig = _context.Git.GetConfiguration(); if (targetConfig.TryGet(useHttpPathKey, false, out string currentValue) && currentValue.IsTruthy()) { _context.Trace.WriteLine("Git configuration 'credential.useHttpPath' is already set to 'true' for https://dev.azure.com."); } else { _context.Trace.WriteLine("Setting Git configuration 'credential.useHttpPath' to 'true' for https://dev.azure.com..."); targetConfig.Set(configurationLevel, useHttpPathKey, "true"); } return(Task.CompletedTask); }
public void GitConfiguration_Enumerate_CallbackReturnsTrue_InvokesCallbackForEachEntry() { string repoPath = CreateRepository(out string workDirPath); ExecGit(repoPath, workDirPath, "config --local foo.name lancelot").AssertSuccess(); ExecGit(repoPath, workDirPath, "config --local foo.quest seek-holy-grail").AssertSuccess(); ExecGit(repoPath, workDirPath, "config --local foo.favcolor blue").AssertSuccess(); var expectedVisitedEntries = new List <(string name, string value)> { ("foo.name", "lancelot"), ("foo.quest", "seek-holy-grail"), ("foo.favcolor", "blue") }; string gitPath = GetGitPath(); var trace = new NullTrace(); var env = new TestEnvironment(); var git = new GitProcess(trace, env, gitPath, repoPath); IGitConfiguration config = git.GetConfiguration(); var actualVisitedEntries = new List <(string name, string value)>(); bool cb(GitConfigurationEntry entry) { if (entry.Key.StartsWith("foo.")) { actualVisitedEntries.Add((entry.Key, entry.Value)); } // Continue enumeration return(true); } config.Enumerate(cb); Assert.Equal(expectedVisitedEntries, actualVisitedEntries); }
public Task UnconfigureAsync(ConfigurationTarget target) { string helperKey = $"{Constants.GitConfiguration.Credential.SectionName}.{Constants.GitConfiguration.Credential.Helper}"; string useHttpPathKey = $"{KnownGitCfg.Credential.SectionName}.https://dev.azure.com.{KnownGitCfg.Credential.UseHttpPath}"; _context.Trace.WriteLine("Clearing Git configuration 'credential.useHttpPath' for https://dev.azure.com..."); GitConfigurationLevel configurationLevel = target == ConfigurationTarget.System ? GitConfigurationLevel.System : GitConfigurationLevel.Global; IGitConfiguration targetConfig = _context.Git.GetConfiguration(); // On Windows, if there is a "manager-core" entry remaining in the system config then we must not clear // the useHttpPath option otherwise this would break the bundled version of GCM in Git for Windows. if (!PlatformUtils.IsWindows() || target != ConfigurationTarget.System || targetConfig.GetAll(helperKey).All(x => !string.Equals(x, "manager-core"))) { targetConfig.Unset(configurationLevel, useHttpPathKey); } return(Task.CompletedTask); }
public void Clear() { _trace.WriteLine("Clearing all cached authorities..."); IGitConfiguration config = _git.GetConfiguration(); var orgKeys = new HashSet <string>(GitConfigurationKeyComparer.Instance); config.Enumerate( GitConfigurationLevel.Global, Constants.GitConfiguration.Credential.SectionName, AzureDevOpsConstants.GitConfiguration.Credential.AzureAuthority, entry => { if (GitConfigurationKeyComparer.TrySplit(entry.Key, out _, out string scope, out _) && Uri.TryCreate(scope, UriKind.Absolute, out Uri orgUrn) && orgUrn.Scheme == AzureDevOpsConstants.UrnScheme) { orgKeys.Add(entry.Key); } return(true); });
public void GitConfiguration_Enumerate_CallbackReturnsFalse_InvokesCallbackForEachEntryUntilReturnsFalse() { string repoPath = CreateRepository(out string workDirPath); Git(repoPath, workDirPath, "config --local foo.name lancelot").AssertSuccess(); Git(repoPath, workDirPath, "config --local foo.quest seek-holy-grail").AssertSuccess(); Git(repoPath, workDirPath, "config --local foo.favcolor blue").AssertSuccess(); var expectedVisitedEntries = new List <(string name, string value)> { ("foo.name", "lancelot"), ("foo.quest", "seek-holy-grail") }; string gitPath = GetGitPath(); var trace = new NullTrace(); var git = new GitProcess(trace, gitPath, repoPath); IGitConfiguration config = git.GetConfiguration(); var actualVisitedEntries = new List <(string name, string value)>(); bool cb(string name, string value) { if (name.StartsWith("foo.")) { actualVisitedEntries.Add((name, value)); } // Stop enumeration after 2 'foo' entries return(actualVisitedEntries.Count < 2); } config.Enumerate(cb); Assert.Equal(expectedVisitedEntries, actualVisitedEntries); }
private IGitConfiguration GetGitConfiguration() => _gitConfig ?? (_gitConfig = _git.GetConfiguration(RepositoryPath));
/// <summary> /// Try and get the all values of a specified setting as specified in the environment and Git configuration, /// in the correct order or precedence. /// </summary> /// <param name="envarName">Optional environment variable name.</param> /// <param name="section">Optional Git configuration section name.</param> /// <param name="property">Git configuration property name. Required if <paramref name="section"/> is set, optional otherwise.</param> /// <returns>All values for the specified setting, in order of precedence, or an empty collection if no such values are set.</returns> public IEnumerable <string> GetSettingValues(string envarName, string section, string property) { string value; if (envarName != null) { if (_environment.Variables.TryGetValue(envarName, out value)) { yield return(value); } } if (section != null && property != null) { IGitConfiguration config = GetGitConfiguration(); if (RemoteUri != null) { /* * Look for URL scoped "section" configuration entries, starting from the most specific * down to the least specific (stopping before the TLD). * * In a divergence from standard Git configuration rules, we also consider matching URL scopes * without a scheme ("protocol://"). * * For each level of scope, we look for an entry with the scheme included (the default), and then * also one without it specified. This allows you to have one configuration scope for both "http" and * "https" without needing to repeat yourself, for example. * * For example, starting with "https://foo.example.com/bar/buzz" we have: * * 1a. [section "https://foo.example.com/bar/buzz"] * property = value * * 1b. [section "foo.example.com/bar/buzz"] * property = value * * 2a. [section "https://foo.example.com/bar"] * property = value * * 2b. [section "foo.example.com/bar"] * property = value * * 3a. [section "https://foo.example.com"] * property = value * * 3b. [section "foo.example.com"] * property = value * * 4a. [section "https://example.com"] * property = value * * 4b. [section "example.com"] * property = value * */ // Enumerate all configuration entries with the correct section and property name // and make a local copy of them here to avoid needing to call `TryGetValue` on the // IGitConfiguration object multiple times in a loop below. var configEntries = new Dictionary <string, string>(); config.Enumerate((entryName, entryValue) => { string entrySection = entryName.TruncateFromIndexOf('.'); string entryProperty = entryName.TrimUntilLastIndexOf('.'); if (StringComparer.OrdinalIgnoreCase.Equals(entrySection, section) && StringComparer.OrdinalIgnoreCase.Equals(entryProperty, property)) { configEntries[entryName] = entryValue; } // Continue the enumeration return(true); }); foreach (string scope in RemoteUri.GetGitConfigurationScopes()) { string queryName = $"{section}.{scope}.{property}"; // Look for a scoped entry that includes the scheme "protocol://example.com" first as this is more specific if (configEntries.TryGetValue(queryName, out value)) { yield return(value); } // Now look for a scoped entry that omits the scheme "example.com" second as this is less specific string scopeWithoutScheme = scope.TrimUntilIndexOf(Uri.SchemeDelimiter); string queryWithSchemeName = $"{section}.{scopeWithoutScheme}.{property}"; if (configEntries.TryGetValue(queryWithSchemeName, out value)) { yield return(value); } } } /* * Try to look for an un-scoped "section" property setting: * * [section] * property = value * */ if (config.TryGetValue($"{section}.{property}", out value)) { yield return(value); } } }