Skip to content

Commit 0bd90a0

Browse files
committed
Add Azure Repos host provider configuration component
Add the required configuration/unconfiguration to the Azure Repos host provider. The required config is to set `useHttpPath` to true for dev.azure.com hosts.
1 parent c763ca0 commit 0bd90a0

File tree

3 files changed

+137
-7
lines changed

3 files changed

+137
-7
lines changed

src/shared/Microsoft.AzureRepos.Tests/AzureReposHostProviderTests.cs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ namespace Microsoft.AzureRepos.Tests
1313
{
1414
public class AzureReposHostProviderTests
1515
{
16+
private static readonly string AzDevUseHttpPathKey =
17+
$"{Constants.GitConfiguration.Credential.SectionName}.https://dev.azure.com.{Constants.GitConfiguration.Credential.UseHttpPath}";
18+
1619
[Fact]
1720
public void AzureReposProvider_IsSupported_AzureHost_UnencryptedHttp_ReturnsTrue()
1821
{
@@ -171,5 +174,84 @@ public async Task AzureReposProvider_GetCredentialAsync_ReturnsCredential()
171174
Assert.Equal(personalAccessToken, credential.Password);
172175
// We don't care about the username value
173176
}
177+
178+
[Fact]
179+
public async Task AzureReposHostProvider_ConfigureAsync_UseHttpPathSetTrue_DoesNothing()
180+
{
181+
var provider = new AzureReposHostProvider(new TestCommandContext());
182+
183+
var environment = new TestEnvironment();
184+
var config = new TestGitConfiguration(new Dictionary<string, IList<string>>
185+
{
186+
[AzDevUseHttpPathKey] = new List<string> {"true"}
187+
});
188+
189+
await provider.ConfigureAsync(
190+
environment, EnvironmentVariableTarget.User,
191+
config, GitConfigurationLevel.Global);
192+
193+
Assert.Single(config.Dictionary);
194+
Assert.True(config.Dictionary.TryGetValue(AzDevUseHttpPathKey, out IList<string> actualValues));
195+
Assert.Single(actualValues);
196+
Assert.Equal("true", actualValues[0]);
197+
}
198+
199+
[Fact]
200+
public async Task AzureReposHostProvider_ConfigureAsync_UseHttpPathSetFalse_SetsUseHttpPathTrue()
201+
{
202+
var provider = new AzureReposHostProvider(new TestCommandContext());
203+
204+
var environment = new TestEnvironment();
205+
var config = new TestGitConfiguration(new Dictionary<string, IList<string>>
206+
{
207+
[AzDevUseHttpPathKey] = new List<string> {"false"}
208+
});
209+
210+
await provider.ConfigureAsync(
211+
environment, EnvironmentVariableTarget.User,
212+
config, GitConfigurationLevel.Global);
213+
214+
Assert.Single(config.Dictionary);
215+
Assert.True(config.Dictionary.TryGetValue(AzDevUseHttpPathKey, out IList<string> actualValues));
216+
Assert.Single(actualValues);
217+
Assert.Equal("true", actualValues[0]);
218+
}
219+
220+
[Fact]
221+
public async Task AzureReposHostProvider_ConfigureAsync_UseHttpPathUnset_SetsUseHttpPathTrue()
222+
{
223+
var provider = new AzureReposHostProvider(new TestCommandContext());
224+
225+
var environment = new TestEnvironment();
226+
var config = new TestGitConfiguration();
227+
228+
await provider.ConfigureAsync(
229+
environment, EnvironmentVariableTarget.User,
230+
config, GitConfigurationLevel.Global);
231+
232+
Assert.Single(config.Dictionary);
233+
Assert.True(config.Dictionary.TryGetValue(AzDevUseHttpPathKey, out IList<string> actualValues));
234+
Assert.Single(actualValues);
235+
Assert.Equal("true", actualValues[0]);
236+
}
237+
238+
239+
[Fact]
240+
public async Task AzureReposHostProvider_UnconfigureAsync_UseHttpPathSet_RemovesEntry()
241+
{
242+
var provider = new AzureReposHostProvider(new TestCommandContext());
243+
244+
var environment = new TestEnvironment();
245+
var config = new TestGitConfiguration(new Dictionary<string, IList<string>>
246+
{
247+
[AzDevUseHttpPathKey] = new List<string> {"true"}
248+
});
249+
250+
await provider.UnconfigureAsync(
251+
environment, EnvironmentVariableTarget.User,
252+
config, GitConfigurationLevel.Global);
253+
254+
Assert.Empty(config.Dictionary);
255+
}
174256
}
175257
}

src/shared/Microsoft.AzureRepos/AzureReposHostProvider.cs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55
using System.Threading.Tasks;
66
using Microsoft.Git.CredentialManager;
77
using Microsoft.Git.CredentialManager.Authentication;
8+
using KnownGitCfg = Microsoft.Git.CredentialManager.Constants.GitConfiguration;
89

910
namespace Microsoft.AzureRepos
1011
{
11-
public class AzureReposHostProvider : HostProvider
12+
public class AzureReposHostProvider : HostProvider, IConfigurableComponent
1213
{
1314
private readonly IAzureDevOpsRestApi _azDevOps;
1415
private readonly IMicrosoftAuthentication _msAuth;
@@ -103,5 +104,49 @@ protected override void ReleaseManagedResources()
103104
}
104105

105106
#endregion
107+
108+
#region IConfigurationComponent
109+
110+
string IConfigurableComponent.Name => "Azure Repos provider";
111+
112+
public Task ConfigureAsync(
113+
IEnvironment environment, EnvironmentVariableTarget environmentTarget,
114+
IGitConfiguration configuration, GitConfigurationLevel configurationLevel)
115+
{
116+
string useHttpPathKey = $"{KnownGitCfg.Credential.SectionName}.https://dev.azure.com.{KnownGitCfg.Credential.UseHttpPath}";
117+
118+
using (IGitConfiguration targetConfig = configuration.GetFilteredConfiguration(configurationLevel))
119+
{
120+
if (targetConfig.TryGetValue(useHttpPathKey, out string currentValue) && currentValue.IsTruthy())
121+
{
122+
Context.Trace.WriteLine("Git configuration 'credential.useHttpPath' is already set to 'true' for https://dev.azure.com.");
123+
}
124+
else
125+
{
126+
Context.Trace.WriteLine("Setting Git configuration 'credential.useHttpPath' to 'true' for https://dev.azure.com...");
127+
targetConfig.SetValue(useHttpPathKey, "true");
128+
}
129+
}
130+
131+
return Task.CompletedTask;
132+
}
133+
134+
public Task UnconfigureAsync(
135+
IEnvironment environment, EnvironmentVariableTarget environmentTarget,
136+
IGitConfiguration configuration, GitConfigurationLevel configurationLevel)
137+
{
138+
string useHttpPathKey = $"{KnownGitCfg.Credential.SectionName}.https://dev.azure.com.{KnownGitCfg.Credential.UseHttpPath}";
139+
140+
Context.Trace.WriteLine("Clearing Git configuration 'credential.useHttpPath' for https://dev.azure.com...");
141+
142+
using (IGitConfiguration targetConfig = configuration.GetFilteredConfiguration(configurationLevel))
143+
{
144+
targetConfig.DeleteEntry(useHttpPathKey);
145+
}
146+
147+
return Task.CompletedTask;
148+
}
149+
150+
#endregion
106151
}
107152
}

src/shared/Microsoft.Git.CredentialManager.Tests/ApplicationTests.cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,12 +157,13 @@ await application.UnconfigureAsync(
157157
[PlatformFact(Platform.Windows)]
158158
public async Task Application_ConfigureAsync_User_PathSet_DoesNothing()
159159
{
160-
const string executablePath = "/usr/local/share/gcm-core/git-credential-manager-core";
160+
const string directoryPath = @"X:\Install Location";
161+
const string executablePath = @"X:\Install Location\git-credential-manager-core.exe";
161162

162163
IConfigurableComponent application = new Application(new TestCommandContext(), executablePath);
163164

164165
var environment = new Mock<IEnvironment>();
165-
environment.Setup(x => x.IsDirectoryOnPath("/usr/local/share/gcm-core")).Returns(true);
166+
environment.Setup(x => x.IsDirectoryOnPath(directoryPath)).Returns(true);
166167

167168
var config = new TestGitConfiguration();
168169

@@ -176,12 +177,13 @@ await application.ConfigureAsync(
176177
[PlatformFact(Platform.Windows)]
177178
public async Task Application_ConfigureAsync_User_PathNotSet_SetsUserPath()
178179
{
179-
const string executablePath = "/usr/local/share/gcm-core/git-credential-manager-core";
180+
const string directoryPath = @"X:\Install Location";
181+
const string executablePath = @"X:\Install Location\git-credential-manager-core.exe";
180182

181183
IConfigurableComponent application = new Application(new TestCommandContext(), executablePath);
182184

183185
var environment = new Mock<IEnvironment>();
184-
environment.Setup(x => x.IsDirectoryOnPath("/usr/local/share/gcm-core")).Returns(false);
186+
environment.Setup(x => x.IsDirectoryOnPath(directoryPath)).Returns(false);
185187

186188
var config = new TestGitConfiguration();
187189

@@ -195,12 +197,13 @@ await application.ConfigureAsync(
195197
[PlatformFact(Platform.Windows)]
196198
public async Task Application_UnconfigureAsync_User_PathSet_RemovesFromUserPath()
197199
{
198-
const string executablePath = "/usr/local/share/gcm-core/git-credential-manager-core";
200+
const string directoryPath = @"X:\Install Location";
201+
const string executablePath = @"X:\Install Location\git-credential-manager-core.exe";
199202

200203
IConfigurableComponent application = new Application(new TestCommandContext(), executablePath);
201204

202205
var environment = new Mock<IEnvironment>();
203-
environment.Setup(x => x.IsDirectoryOnPath("/usr/local/share/gcm-core")).Returns(true);
206+
environment.Setup(x => x.IsDirectoryOnPath(directoryPath)).Returns(true);
204207

205208
var config = new TestGitConfiguration();
206209

0 commit comments

Comments
 (0)