Skip to content

Commit 65ce0a9

Browse files
committed
Add pwsh agent capability detection
1 parent 6db3ee1 commit 65ce0a9

4 files changed

Lines changed: 101 additions & 1 deletion

File tree

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using Microsoft.VisualStudio.Services.Agent.Util;
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Threading;
8+
using System.Threading.Tasks;
9+
10+
namespace Microsoft.VisualStudio.Services.Agent.Capabilities
11+
{
12+
public sealed class PwshCapabilitiesProvider : AgentService, ICapabilitiesProvider
13+
{
14+
public Type ExtensionType => typeof(ICapabilitiesProvider);
15+
16+
public int Order => 2;
17+
18+
public Task<List<Capability>> GetCapabilitiesAsync(AgentSettings settings, CancellationToken cancellationToken)
19+
{
20+
Trace.Entering();
21+
var capabilities = new List<Capability>();
22+
23+
try
24+
{
25+
string pwsh = HostContext.GetService<IPwshExeUtil>().GetPath();
26+
capabilities.Add(new Capability("Pwsh", pwsh));
27+
}
28+
catch (Exception ex)
29+
{
30+
Trace.Info($"Pwsh capability not detected: {ex.Message}");
31+
}
32+
33+
return Task.FromResult(capabilities);
34+
}
35+
}
36+
}

src/Microsoft.VisualStudio.Services.Agent/ExtensionManager.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ private List<IExtension> LoadExtensions<T>() where T : class, IExtension
4646
case "Microsoft.VisualStudio.Services.Agent.Capabilities.ICapabilitiesProvider":
4747
Add<T>(extensions, "Microsoft.VisualStudio.Services.Agent.Capabilities.AgentCapabilitiesProvider, Microsoft.VisualStudio.Services.Agent");
4848
Add<T>(extensions, "Microsoft.VisualStudio.Services.Agent.Capabilities.EnvironmentCapabilitiesProvider, Microsoft.VisualStudio.Services.Agent");
49+
Add<T>(extensions, "Microsoft.VisualStudio.Services.Agent.Capabilities.PwshCapabilitiesProvider, Microsoft.VisualStudio.Services.Agent");
4950
if (PlatformUtil.RunningOnLinux || PlatformUtil.RunningOnMacOS)
5051
{
5152
Add<T>(extensions, "Microsoft.VisualStudio.Services.Agent.Capabilities.NixCapabilitiesProvider, Microsoft.VisualStudio.Services.Agent");
@@ -145,4 +146,4 @@ private void Add<T>(List<IExtension> extensions, string assemblyQualifiedName) w
145146
extensions.Add(extension);
146147
}
147148
}
148-
}
149+
}

src/Test/L0/ExtensionManagerL0.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ public void LoadsTypes()
4848
AssertContains<Microsoft.VisualStudio.Services.Agent.Capabilities.ICapabilitiesProvider>(
4949
manager,
5050
concreteType: typeof(Microsoft.VisualStudio.Services.Agent.Capabilities.AgentCapabilitiesProvider));
51+
AssertContains<Microsoft.VisualStudio.Services.Agent.Capabilities.ICapabilitiesProvider>(
52+
manager,
53+
concreteType: typeof(Microsoft.VisualStudio.Services.Agent.Capabilities.PwshCapabilitiesProvider));
5154
AssertContains<Microsoft.VisualStudio.Services.Agent.Worker.IJobExtension>(
5255
manager,
5356
concreteType: typeof(Microsoft.VisualStudio.Services.Agent.Worker.Build.BuildJobExtension));
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using Microsoft.VisualStudio.Services.Agent.Capabilities;
5+
using Microsoft.VisualStudio.Services.Agent.Util;
6+
using Moq;
7+
using System;
8+
using System.Collections.Generic;
9+
using System.Linq;
10+
using System.Threading;
11+
using System.Threading.Tasks;
12+
using Xunit;
13+
14+
namespace Microsoft.VisualStudio.Services.Agent.Tests.Listener
15+
{
16+
public sealed class PwshCapabilitiesProviderTestL0
17+
{
18+
[Fact]
19+
[Trait("Level", "L0")]
20+
[Trait("Category", "Agent")]
21+
public async Task AddsPwshCapabilityWhenPwshExists()
22+
{
23+
using var hc = new TestHostContext(this);
24+
using var tokenSource = new CancellationTokenSource();
25+
26+
var pwshUtil = new Mock<IPwshExeUtil>();
27+
pwshUtil.Setup(x => x.GetPath()).Returns("/usr/bin/pwsh");
28+
hc.SetSingleton<IPwshExeUtil>(pwshUtil.Object);
29+
30+
var provider = new PwshCapabilitiesProvider();
31+
provider.Initialize(hc);
32+
33+
List<Capability> capabilities = await provider.GetCapabilitiesAsync(new AgentSettings(), tokenSource.Token);
34+
35+
Capability pwshCapability = capabilities.SingleOrDefault(x => string.Equals(x.Name, "Pwsh", StringComparison.Ordinal));
36+
Assert.NotNull(pwshCapability);
37+
Assert.Equal("/usr/bin/pwsh", pwshCapability.Value);
38+
}
39+
40+
[Fact]
41+
[Trait("Level", "L0")]
42+
[Trait("Category", "Agent")]
43+
public async Task ReturnsNoPwshCapabilityWhenPwshIsUnavailable()
44+
{
45+
using var hc = new TestHostContext(this);
46+
using var tokenSource = new CancellationTokenSource();
47+
48+
var pwshUtil = new Mock<IPwshExeUtil>();
49+
pwshUtil.Setup(x => x.GetPath()).Throws(new InvalidOperationException("pwsh missing"));
50+
hc.SetSingleton<IPwshExeUtil>(pwshUtil.Object);
51+
52+
var provider = new PwshCapabilitiesProvider();
53+
provider.Initialize(hc);
54+
55+
List<Capability> capabilities = await provider.GetCapabilitiesAsync(new AgentSettings(), tokenSource.Token);
56+
57+
Assert.DoesNotContain(capabilities, x => string.Equals(x.Name, "Pwsh", StringComparison.Ordinal));
58+
}
59+
}
60+
}

0 commit comments

Comments
 (0)