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); }
Task IConfigurableComponent.UnconfigureAsync( IEnvironment environment, EnvironmentVariableTarget environmentTarget, IGit git, GitConfigurationLevel configurationLevel) { string helperKey = $"{Constants.GitConfiguration.Credential.SectionName}.{Constants.GitConfiguration.Credential.Helper}"; string gitConfigAppName = GetGitConfigAppName(); IGitConfiguration targetConfig = git.GetConfiguration(configurationLevel); Context.Trace.WriteLine("Removing Git credential helper configuration..."); // Clear any blank 'reset' entries targetConfig.UnsetAll(helperKey, Constants.RegexPatterns.Empty); // Clear GCM executable entries targetConfig.UnsetAll(helperKey, Regex.Escape(gitConfigAppName)); // NOTE: We currently only update the PATH in Windows installations and leave removing the GCM executable // on the PATH on other platform to their installers. // Remove GCM executable from the PATH if (PlatformUtils.IsWindows()) { Context.Trace.WriteLine("Removing application from the PATH..."); string directoryPath = Path.GetDirectoryName(_appPath); environment.RemoveDirectoryFromPath(directoryPath, environmentTarget); } return(Task.CompletedTask); }
Task IConfigurableComponent.ConfigureAsync( IEnvironment environment, EnvironmentVariableTarget environmentTarget, IGit git, GitConfigurationLevel configurationLevel) { // NOTE: We currently only update the PATH in Windows installations and leave putting the GCM executable // on the PATH on other platform to their installers. if (PlatformUtils.IsWindows()) { string directoryPath = Path.GetDirectoryName(_appPath); if (!environment.IsDirectoryOnPath(directoryPath)) { Context.Trace.WriteLine("Adding application to PATH..."); environment.AddDirectoryToPath(directoryPath, environmentTarget); } else { Context.Trace.WriteLine("Application is already on the PATH."); } } string helperKey = $"{Constants.GitConfiguration.Credential.SectionName}.{Constants.GitConfiguration.Credential.Helper}"; string gitConfigAppName = GetGitConfigAppName(); IGitConfiguration targetConfig = git.GetConfiguration(configurationLevel); /* * We are looking for the following to be considered already set: * * [credential] * ... # any number of helper entries * helper = # an empty value to reset/clear any previous entries * helper = {gitConfigAppName} # the expected executable value in the last position & directly following the empty value * */ string[] currentValues = targetConfig.GetRegex(helperKey, Constants.RegexPatterns.Any).ToArray(); if (currentValues.Length < 2 || !string.IsNullOrWhiteSpace(currentValues[currentValues.Length - 2]) || // second to last entry is empty currentValues[currentValues.Length - 1] != gitConfigAppName) // last entry is the expected executable { Context.Trace.WriteLine("Updating Git credential helper configuration..."); // Clear any existing entries in the configuration. targetConfig.UnsetAll(helperKey, Constants.RegexPatterns.Any); // 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. targetConfig.SetValue(helperKey, string.Empty); targetConfig.ReplaceAll(helperKey, Constants.RegexPatterns.None, gitConfigAppName); } else { Context.Trace.WriteLine("Credential helper configuration is already set correctly."); } return(Task.CompletedTask); }
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 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 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 IGitConfiguration GetGitConfiguration() => _gitConfig ?? (_gitConfig = _git.GetConfiguration(RepositoryPath));
/// <summary> /// Get a snapshot of the configuration for the system and user. /// </summary> /// <param name="git">Git object.</param> /// <returns>Git configuration snapshot.</returns> public static IGitConfiguration GetConfiguration(this IGit git) => git.GetConfiguration(null);
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 = _git.GetConfiguration(); 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); } } }
public IEnumerable <string> GetSettingValues(string envarName, string section, string property, bool isPath) { string value; if (envarName != null) { if (_environment.Variables.TryGetValue(envarName, out value)) { yield return(value); } } if (section != null && property != null) { IGitConfiguration config = _git.GetConfiguration(); 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 * * It is also important to note that although the section and property names are NOT case * sensitive, the "scope" part IS case sensitive! We must be careful when searching to ensure * we follow Git's rules. * */ // 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>(GitConfigurationKeyComparer.Instance); config.Enumerate(section, property, entry => { configEntries[entry.Key] = entry.Value; // 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 `isPath` is true, then re-get the value from the // `GitConfiguration` with `isPath` specified. if (configEntries.TryGetValue(queryName, out value) && (!isPath || config.TryGet(queryName, isPath, out value))) { yield return(value); } // Now look for a scoped entry that omits the scheme "example.com" second as this is less // specific. As above, if `isPath` is true, get the configuration setting again with // `isPath` specified. string scopeWithoutScheme = scope.TrimUntilIndexOf(Uri.SchemeDelimiter); string queryWithSchemeName = $"{section}.{scopeWithoutScheme}.{property}"; if (configEntries.TryGetValue(queryWithSchemeName, out value) && (!isPath || config.TryGet(queryWithSchemeName, isPath, out value))) { yield return(value); } } } /* * Try to look for an un-scoped "section" property setting: * * [section] * property = value * */ if (config.TryGet($"{section}.{property}", isPath, out value)) { yield return(value); } // Check for an externally specified default value if (TryGetExternalDefault(section, property, out string defaultValue)) { yield return(defaultValue); } } }
/// <summary> /// Get the configuration. /// </summary> /// <param name="git">Git object.</param> /// <returns>Git configuration.</returns> public static IGitConfiguration GetConfiguration(this IGit git) => git.GetConfiguration(GitConfigurationLevel.All);
/// <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.TryGetValue(envarName, out value)) { yield return(value); } } if (section != null && property != null) { using (var config = _git.GetConfiguration(RepositoryPath)) { 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 * */ foreach (string scope in RemoteUri.GetGitConfigurationScopes()) { // Look for a scoped entry that includes the scheme "protocol://example.com" first as this is more specific if (config.TryGetValue(section, scope, property, 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); if (config.TryGetValue(section, scopeWithoutScheme, property, 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); } } } }