Skip to content

Commit 96dcc44

Browse files
authored
Log warnings and errors produced by Save-Module during managed dependency installation (#513)
1 parent 21ac547 commit 96dcc44

File tree

5 files changed

+59
-27
lines changed

5 files changed

+59
-27
lines changed

src/DependencyManagement/DependencyManager.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,13 @@ public DependencyManager(
4848
IInstalledDependenciesLocator installedDependenciesLocator = null,
4949
IDependencySnapshotInstaller installer = null,
5050
INewerDependencySnapshotDetector newerSnapshotDetector = null,
51-
IBackgroundDependencySnapshotMaintainer maintainer = null)
51+
IBackgroundDependencySnapshotMaintainer maintainer = null,
52+
ILogger logger = null)
5253
{
5354
_storage = storage ?? new DependencyManagerStorage(GetFunctionAppRootPath(requestMetadataDirectory));
5455
_installedDependenciesLocator = installedDependenciesLocator ?? new InstalledDependenciesLocator(_storage);
5556
_installer = installer ?? new DependencySnapshotInstaller(
56-
moduleProvider ?? new PowerShellGalleryModuleProvider(),
57+
moduleProvider ?? new PowerShellGalleryModuleProvider(logger),
5758
_storage,
5859
new PowerShellModuleSnapshotComparer(),
5960
new PowerShellModuleSnapshotLogger());

src/DependencyManagement/PowerShellGalleryModuleProvider.cs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,17 @@ namespace Microsoft.Azure.Functions.PowerShellWorker.DependencyManagement
1111

1212
using Microsoft.Azure.Functions.PowerShellWorker.PowerShell;
1313
using Microsoft.Azure.Functions.PowerShellWorker.Utility;
14+
using LogLevel = Microsoft.Azure.WebJobs.Script.Grpc.Messages.RpcLog.Types.Level;
1415

1516
internal class PowerShellGalleryModuleProvider : IModuleProvider
1617
{
18+
private readonly ILogger _logger;
19+
1720
private readonly IPowerShellGallerySearchInvoker _searchInvoker;
1821

19-
public PowerShellGalleryModuleProvider(IPowerShellGallerySearchInvoker searchInvoker = null)
22+
public PowerShellGalleryModuleProvider(ILogger logger, IPowerShellGallerySearchInvoker searchInvoker = null)
2023
{
24+
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
2125
_searchInvoker = searchInvoker ?? new PowerShellGallerySearchInvoker();
2226
}
2327

@@ -87,8 +91,18 @@ public void SaveModule(PowerShell pwsh, string moduleName, string version, strin
8791
.AddParameter("AllowPrerelease", Utils.BoxedTrue)
8892
.AddParameter("Path", path)
8993
.AddParameter("Force", Utils.BoxedTrue)
90-
.AddParameter("ErrorAction", "Stop")
91-
.InvokeAndClearCommands();
94+
.AddParameter("ErrorAction", "Stop");
95+
96+
try
97+
{
98+
pwsh.Invoke();
99+
}
100+
finally
101+
{
102+
LogSaveModuleErrorsAndWarnings(pwsh, moduleName, version);
103+
pwsh.Streams.ClearStreams();
104+
pwsh.Commands.Clear();
105+
}
92106
}
93107

94108
/// <summary>
@@ -104,6 +118,21 @@ public void Cleanup(PowerShell pwsh)
104118
.InvokeAndClearCommands();
105119
}
106120

121+
private void LogSaveModuleErrorsAndWarnings(PowerShell pwsh, string moduleName, string version)
122+
{
123+
var prefix = $"Save-Module('{moduleName}', '{version}'): ";
124+
125+
foreach (var item in pwsh.Streams.Error)
126+
{
127+
_logger.Log(isUserOnlyLog: false, LogLevel.Error, $"{prefix}{item.Exception.Message}");
128+
}
129+
130+
foreach (var item in pwsh.Streams.Warning)
131+
{
132+
_logger.Log(isUserOnlyLog: false, LogLevel.Warning, $"{prefix}{item.Message}");
133+
}
134+
}
135+
107136
private static Version GetLatestVersion(
108137
XmlNode root, XmlNamespaceManager namespaceManager, string expectedVersionStart, Version latestVersion)
109138
{

src/RequestProcessor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ internal StreamingMessage ProcessFunctionLoadRequest(StreamingMessage request)
190190
var rpcLogger = new RpcLogger(_msgStream);
191191
rpcLogger.SetContext(request.RequestId, null);
192192

193-
_dependencyManager = new DependencyManager(request.FunctionLoadRequest.Metadata.Directory);
193+
_dependencyManager = new DependencyManager(request.FunctionLoadRequest.Metadata.Directory, logger: rpcLogger);
194194
var managedDependenciesPath = _dependencyManager.Initialize(request, rpcLogger);
195195

196196
// Setup the FunctionApp root path and module path.

test/Unit/DependencyManagement/DependencyManagementTests.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public void TestManagedDependencyBasicRequirements()
102102
var functionLoadRequest = GetFuncLoadRequest(functionFolderPath, true);
103103

104104
// Create DependencyManager and process the requirements.psd1 file at the function app root.
105-
using (var dependencyManager = new DependencyManager(functionLoadRequest.Metadata.Directory))
105+
using (var dependencyManager = new DependencyManager(functionLoadRequest.Metadata.Directory, logger: _testLogger))
106106
{
107107
var currentDependenciesPath = dependencyManager.Initialize(_testLogger);
108108

@@ -132,7 +132,7 @@ public void TestManagedDependencyEmptyHashtableRequirement()
132132
var functionLoadRequest = GetFuncLoadRequest(functionFolderPath, true);
133133

134134
// Create DependencyManager and process the requirements.psd1 file at the function app root.
135-
using (var dependencyManager = new DependencyManager(functionLoadRequest.Metadata.Directory))
135+
using (var dependencyManager = new DependencyManager(functionLoadRequest.Metadata.Directory, logger: _testLogger))
136136
{
137137
var currentDependenciesPath = dependencyManager.Initialize(_testLogger);
138138

@@ -153,7 +153,7 @@ public void TestManagedDependencyNoHashtableRequirementShouldThrow()
153153
var functionFolderPath = Path.Combine(_dependencyManagementDirectory, requirementsDirectoryName, "FunctionDirectory");
154154
var functionLoadRequest = GetFuncLoadRequest(functionFolderPath, true);
155155

156-
using (var dependencyManager = new DependencyManager(functionLoadRequest.Metadata.Directory))
156+
using (var dependencyManager = new DependencyManager(functionLoadRequest.Metadata.Directory, logger: _testLogger))
157157
{
158158
// Trying to set the functionApp dependencies should throw since requirements.psd1 is not a hash table.
159159
var exception = Assert.Throws<DependencyInstallationException>(
@@ -172,7 +172,7 @@ public void TestManagedDependencyInvalidRequirementsFormatShouldThrow()
172172
var functionFolderPath = Path.Combine(_dependencyManagementDirectory, requirementsDirectoryName, "FunctionDirectory");
173173
var functionLoadRequest = GetFuncLoadRequest(functionFolderPath, true);
174174

175-
using (var dependencyManager = new DependencyManager(functionLoadRequest.Metadata.Directory))
175+
using (var dependencyManager = new DependencyManager(functionLoadRequest.Metadata.Directory, logger: _testLogger))
176176
{
177177
// Trying to set the functionApp dependencies should throw since the module version
178178
// in requirements.psd1 is not in a valid format.
@@ -193,7 +193,7 @@ public void TestManagedDependencyNoRequirementsFileShouldThrow()
193193
var functionFolderPath = Path.Combine(_dependencyManagementDirectory, requirementsDirectoryName, "FunctionDirectory");
194194
var functionLoadRequest = GetFuncLoadRequest(functionFolderPath, true);
195195

196-
using (var dependencyManager = new DependencyManager(functionLoadRequest.Metadata.Directory))
196+
using (var dependencyManager = new DependencyManager(functionLoadRequest.Metadata.Directory, logger: _testLogger))
197197
{
198198
// Trying to set the functionApp dependencies should throw since no
199199
// requirements.psd1 is found at the function app root.

test/Unit/DependencyManagement/PowerShellGalleryModuleProviderTests.cs

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,27 @@ namespace Microsoft.Azure.Functions.PowerShellWorker.Test.DependencyManagement
77
using Xunit;
88

99
using PowerShellWorker.DependencyManagement;
10+
using PowerShellWorker.Utility;
1011

1112
public class PowerShellGalleryModuleProviderTests
1213
{
14+
private readonly Mock<ILogger> _mockLogger = new Mock<ILogger>();
15+
1316
private readonly Mock<IPowerShellGallerySearchInvoker> _mockSearchInvoker =
1417
new Mock<IPowerShellGallerySearchInvoker>(MockBehavior.Strict);
1518

19+
private PowerShellGalleryModuleProvider _moduleProvider;
20+
21+
public PowerShellGalleryModuleProviderTests()
22+
{
23+
_moduleProvider = new PowerShellGalleryModuleProvider(_mockLogger.Object, _mockSearchInvoker.Object);
24+
}
25+
1626
[Fact]
1727
public void ReturnsNullIfSearchInvokerReturnsNull()
1828
{
1929
_mockSearchInvoker.Setup(_ => _.Invoke(It.IsAny<Uri>())).Returns(default(Stream));
20-
var moduleProvider = new PowerShellGalleryModuleProvider(_mockSearchInvoker.Object);
21-
var actualVersion = moduleProvider.GetLatestPublishedModuleVersion("ModuleName", "1");
30+
var actualVersion = _moduleProvider.GetLatestPublishedModuleVersion("ModuleName", "1");
2231
Assert.Null(actualVersion);
2332
}
2433

@@ -43,8 +52,7 @@ public void ReturnsSingleVersion()
4352
using (var responseStream = new MemoryStream(Encoding.UTF8.GetBytes(ResponseText)))
4453
{
4554
_mockSearchInvoker.Setup(_ => _.Invoke(It.IsAny<Uri>())).Returns(responseStream);
46-
var moduleProvider = new PowerShellGalleryModuleProvider(_mockSearchInvoker.Object);
47-
var actualVersion = moduleProvider.GetLatestPublishedModuleVersion("ModuleName", "1");
55+
var actualVersion = _moduleProvider.GetLatestPublishedModuleVersion("ModuleName", "1");
4856
Assert.Equal("1.2.3.4", actualVersion);
4957
}
5058
}
@@ -82,8 +90,7 @@ public void FindsLatestVersionRegardlessOfResponseOrder()
8290
using (var responseStream = new MemoryStream(Encoding.UTF8.GetBytes(ResponseText)))
8391
{
8492
_mockSearchInvoker.Setup(_ => _.Invoke(It.IsAny<Uri>())).Returns(responseStream);
85-
var moduleProvider = new PowerShellGalleryModuleProvider(_mockSearchInvoker.Object);
86-
var actualVersion = moduleProvider.GetLatestPublishedModuleVersion("ModuleName", "1");
93+
var actualVersion = _moduleProvider.GetLatestPublishedModuleVersion("ModuleName", "1");
8794
Assert.Equal("1.2.3.6", actualVersion);
8895
}
8996
}
@@ -121,8 +128,7 @@ public void IgnoresPrereleaseVersions()
121128
using (var responseStream = new MemoryStream(Encoding.UTF8.GetBytes(ResponseText)))
122129
{
123130
_mockSearchInvoker.Setup(_ => _.Invoke(It.IsAny<Uri>())).Returns(responseStream);
124-
var moduleProvider = new PowerShellGalleryModuleProvider(_mockSearchInvoker.Object);
125-
var actualVersion = moduleProvider.GetLatestPublishedModuleVersion("ModuleName", "1");
131+
var actualVersion = _moduleProvider.GetLatestPublishedModuleVersion("ModuleName", "1");
126132
Assert.Equal("1.2.3.5", actualVersion);
127133
}
128134
}
@@ -166,8 +172,7 @@ public void IgnoresNotMatchingMajorVersions()
166172
using (var responseStream = new MemoryStream(Encoding.UTF8.GetBytes(ResponseText)))
167173
{
168174
_mockSearchInvoker.Setup(_ => _.Invoke(It.IsAny<Uri>())).Returns(responseStream);
169-
var moduleProvider = new PowerShellGalleryModuleProvider(_mockSearchInvoker.Object);
170-
var actualVersion = moduleProvider.GetLatestPublishedModuleVersion("ModuleName", "1");
175+
var actualVersion = _moduleProvider.GetLatestPublishedModuleVersion("ModuleName", "1");
171176
Assert.Equal("1.2.3.6", actualVersion);
172177
}
173178
}
@@ -207,8 +212,7 @@ public void ComparesVersionsCorrectly(string lowerVersion, string higherVersion)
207212
using (var responseStream = new MemoryStream(Encoding.UTF8.GetBytes(responseText)))
208213
{
209214
_mockSearchInvoker.Setup(_ => _.Invoke(It.IsAny<Uri>())).Returns(responseStream);
210-
var moduleProvider = new PowerShellGalleryModuleProvider(_mockSearchInvoker.Object);
211-
var actualVersion = moduleProvider.GetLatestPublishedModuleVersion("ModuleName", "0");
215+
var actualVersion = _moduleProvider.GetLatestPublishedModuleVersion("ModuleName", "0");
212216
Assert.Equal(higherVersion, actualVersion);
213217
}
214218
}
@@ -228,8 +232,7 @@ public void ReturnsNullIfNoVersionFound()
228232
using (var responseStream = new MemoryStream(Encoding.UTF8.GetBytes(ResponseText)))
229233
{
230234
_mockSearchInvoker.Setup(_ => _.Invoke(It.IsAny<Uri>())).Returns(responseStream);
231-
var moduleProvider = new PowerShellGalleryModuleProvider(_mockSearchInvoker.Object);
232-
var actualVersion = moduleProvider.GetLatestPublishedModuleVersion("ModuleName", "1");
235+
var actualVersion = _moduleProvider.GetLatestPublishedModuleVersion("ModuleName", "1");
233236
Assert.Null(actualVersion);
234237
}
235238
}
@@ -315,8 +318,7 @@ public void FindsLatestVersionAcrossMultiplePages()
315318
_mockSearchInvoker.Setup(_ => _.Invoke(new Uri("https://NextLink2")))
316319
.Returns(responseStream3);
317320

318-
var moduleProvider = new PowerShellGalleryModuleProvider(_mockSearchInvoker.Object);
319-
var actualVersion = moduleProvider.GetLatestPublishedModuleVersion("ModuleName", "1");
321+
var actualVersion = _moduleProvider.GetLatestPublishedModuleVersion("ModuleName", "1");
320322
Assert.Equal("1.2.3.6", actualVersion);
321323
}
322324
}

0 commit comments

Comments
 (0)