diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/AzPredictorServiceTests.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/AzPredictorServiceTests.cs index 262279c87903..377f5d2836dc 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/AzPredictorServiceTests.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/AzPredictorServiceTests.cs @@ -107,8 +107,6 @@ public void VerifyParameterValues() [InlineData("Get-AzKeyVault -VaultName")] [InlineData("GET-AZSTORAGEACCOUNTKEY -NAME ")] [InlineData("new-azresourcegroup -name hello")] - [InlineData("Get-AzContext -Name")] - [InlineData("Get-AzContext -ErrorAction")] public void VerifyUsingCommandBasedPredictor(string userInput) { var predictionContext = PredictionContext.Create(userInput); @@ -150,8 +148,8 @@ public void VerifyUsingCommandBasedPredictor(string userInput) /// Verifies that when no prediction is in the command based list, we'll use the fallback list. /// [Theory] - [InlineData("Get-AzResource -Name hello -Pre")] - [InlineData("Get-AzADServicePrincipal -ApplicationObject")] + [InlineData("New-AzApiManagementContext -ResourceGroupName hello -Serv")] + [InlineData("Get-AzAlert -TimeRange '1h' -Incl")] public void VerifyUsingFallbackPredictor(string userInput) { var predictionContext = PredictionContext.Create(userInput); diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/AzPredictorTests.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/AzPredictorTests.cs index 4032b733f235..df52a44ba337 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/AzPredictorTests.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/AzPredictorTests.cs @@ -137,8 +137,6 @@ public void VerifySupportedCommandMasked() [Theory] [InlineData("new-azresourcegroup -name hello")] [InlineData("Get-AzContext -Name")] - [InlineData("Get-AzContext -ErrorAction")] - [InlineData("Get-AzADServicePrincipal -ApplicationObject")] public void VerifySuggestion(string userInput) { var predictionContext = PredictionContext.Create(userInput); @@ -164,7 +162,7 @@ public void VerifySuggestionOnIncompleteCommand() null); var userInput = "New-AzResourceGroup -Name 'ResourceGroup01' -Location 'Central US' -WhatIf -"; - var expected = "New-AzResourceGroup -Name 'ResourceGroup01' -Location 'Central US' -WhatIf -Verbose ***"; + var expected = "New-AzResourceGroup -Name 'ResourceGroup01' -Location 'Central US' -WhatIf -Tag value1"; var predictionContext = PredictionContext.Create(userInput); var actual = localAzPredictor.GetSuggestion(predictionContext, CancellationToken.None); diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/CommandLinePredictorTests.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/CommandLinePredictorTests.cs index dd2bd9a6c32d..0aa9898dcee3 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/CommandLinePredictorTests.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/CommandLinePredictorTests.cs @@ -169,7 +169,6 @@ public void GetPredictionWithCommandName(string userInput) [InlineData("Get-AzKeyVault -VaultName")] [InlineData("GET-AZSTORAGEACCOUNTKEY -NAME ")] [InlineData("new-azresourcegroup -name hello")] - [InlineData("Get-AzContext -Name")] public void GetPredictionWithCommandNameParameters(string userInput) { var predictionContext = PredictionContext.Create(userInput); @@ -237,7 +236,7 @@ public void VerifyPredictionForCommand() 1, CancellationToken.None); - Assert.Equal("Connect-AzAccount -Credential -ServicePrincipal -Tenant <>", result.PredictiveSuggestions.First().SuggestionText); + Assert.Equal("Connect-AzAccount -Identity", result.PredictiveSuggestions.First().SuggestionText); } /// @@ -260,7 +259,7 @@ public void VerifyPredictionForCommandAndParameters() 1, CancellationToken.None); - Assert.Equal("Get-AzStorageAccountKey -Name 'ContosoStorage' -ResourceGroupName 'ContosoGroup02'", result.PredictiveSuggestions.First().SuggestionText); + Assert.Equal("Get-AzStorageAccountKey -Name 'myStorageAccount' -ResourceGroupName 'ContosoGroup02'", result.PredictiveSuggestions.First().SuggestionText); } } } diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Data/CommandsModel.zip b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Data/CommandsModel.zip index f7e44297f3db..d9427c192f47 100644 Binary files a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Data/CommandsModel.zip and b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Data/CommandsModel.zip differ diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Data/PredictionsModel.zip b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Data/PredictionsModel.zip index e05ade2247e5..81e5bbe97abe 100644 Binary files a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Data/PredictionsModel.zip and b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Data/PredictionsModel.zip differ diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Data/SuggestionsModel.zip b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Data/SuggestionsModel.zip deleted file mode 100644 index cd95d18a2ad1..000000000000 Binary files a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Data/SuggestionsModel.zip and /dev/null differ diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Mocks/MockAzPredictorService.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Mocks/MockAzPredictorService.cs index 334aa5d01ed6..0d0d3d74d724 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Mocks/MockAzPredictorService.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/Mocks/MockAzPredictorService.cs @@ -12,6 +12,7 @@ // limitations under the License. // ---------------------------------------------------------------------------------- +using System; using System.Collections.Generic; namespace Microsoft.Azure.PowerShell.Tools.AzPredictor.Test.Mocks @@ -32,7 +33,7 @@ sealed class MockAzPredictorService : AzPredictorService /// The history that the suggestion is for /// The suggestions collection /// The commands collection - public MockAzPredictorService(string history, IList suggestions, IList commands) + public MockAzPredictorService(string history, IList suggestions, IList commands) { if (history != null) { diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/ModelEntry.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/ModelEntry.cs new file mode 100644 index 000000000000..8a263ab66b1c --- /dev/null +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/ModelEntry.cs @@ -0,0 +1,63 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; + +namespace Microsoft.Azure.PowerShell.Tools.AzPredictor.Test +{ + /// + /// Represents a command entry in the model files. + /// + [JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy))] + public class ModelEntry + { + /// + /// The command in the model. + /// + [JsonProperty("suggestion", Required = Required.Always)] + public string Command { get; set; } + + /// + /// The description of the command in the model. + /// + [JsonProperty(Required = Required.Always)] + public string Description { get; set; } + + /// + /// The prediction count in the model. + /// + [JsonProperty("suggestion count", Required = Required.Always)] + public int PredictionCount { get; set; } + + /// + /// The history count in the model. + /// + [JsonProperty("history count", Required = Required.Always)] + public int HistoryCount { get; set; } + + /// + /// Transforms the model entry into the client PredictiveCommand object. + /// + /// The PredictiveCommand object used on the client. + public PredictiveCommand TransformEntry() + { + return new PredictiveCommand() + { + Command = this.Command, + Description = this.Description + }; + } + } +} diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/ModelFixture.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/ModelFixture.cs index 74538f27a8f6..8f0e8460d4a2 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/ModelFixture.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/ModelFixture.cs @@ -12,12 +12,12 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using Microsoft.Azure.PowerShell.Tools.AzPredictor.Utilities; +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; -using System.Text.Json; +using System.Linq; using Xunit; namespace Microsoft.Azure.PowerShell.Tools.AzPredictor.Test @@ -32,16 +32,18 @@ public sealed class ModelFixture : IDisposable private const string PredictionsModelZip = "PredictionsModel.zip"; private const string PredictionsModelJson = "PredictionsModel.json"; private const string DataDirectoryName = "Data"; + private static readonly Version CommandsVersionToUse = new Version("5.1.0"); + private static readonly Version PredictionsVersionToUse = new Version("5.1.0"); /// /// Gets a list of string for the commands. /// - public IList CommandCollection { get; private set; } + public IList CommandCollection { get; private set; } /// /// Gets a dictionary for the predictions. /// - public IDictionary> PredictionCollection { get; private set; } + public IDictionary> PredictionCollection { get; private set; } /// /// Constructs a new instance of @@ -52,11 +54,24 @@ public ModelFixture() var fileInfo = new FileInfo(currentLocation); var directory = fileInfo.DirectoryName; var dataDirectory = Path.Join(directory, ModelFixture.DataDirectoryName); - var commandsModel = ModelFixture.ReadZipEntry(Path.Join(dataDirectory, ModelFixture.CommandsModelZip), ModelFixture.CommandsModelJson); - var predictionsModel = ModelFixture.ReadZipEntry(Path.Join(dataDirectory, ModelFixture.PredictionsModelZip), ModelFixture.PredictionsModelJson); + var commandsModelVersions= JsonConvert.DeserializeObject>>(ModelFixture.ReadZipEntry(Path.Join(dataDirectory, ModelFixture.CommandsModelZip), ModelFixture.CommandsModelJson)); + var predictionsModelVersions = JsonConvert.DeserializeObject>>>(ModelFixture.ReadZipEntry(Path.Join(dataDirectory, ModelFixture.PredictionsModelZip), ModelFixture.PredictionsModelJson)); - this.CommandCollection = JsonSerializer.Deserialize>(commandsModel, JsonUtilities.DefaultSerializerOptions); - this.PredictionCollection = JsonSerializer.Deserialize>>(predictionsModel, JsonUtilities.DefaultSerializerOptions); + var commandsModel = commandsModelVersions[CommandsVersionToUse]; + var predictionsModel = predictionsModelVersions[PredictionsVersionToUse]; + + this.CommandCollection = commandsModel.Select(x => x.TransformEntry()).ToList(); + var predictiveCollection = new Dictionary>(); + foreach (var command in predictionsModel) + { + var predictiveCommandEntries = new List(); + foreach (var modelEntry in command.Value) + { + predictiveCommandEntries.Add(modelEntry.TransformEntry()); + } + predictiveCollection.Add(command.Key, predictiveCommandEntries); + } + this.PredictionCollection = predictiveCollection; } /// diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor/AzContext.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor/AzContext.cs index a363280c66be..91e6dbc5cb87 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor/AzContext.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor/AzContext.cs @@ -32,6 +32,9 @@ internal sealed class AzContext : IAzContext { private static readonly Version DefaultVersion = new Version("0.0.0.0"); + /// + public Version AzVersion { get; private set; } = DefaultVersion; + /// public string UserId { get; private set; } = string.Empty; @@ -100,6 +103,7 @@ public Version ModuleVersion /// public void UpdateContext() { + AzVersion = GetAzVersion(); UserId = GenerateSha256HashString(GetUserAccountId()); } @@ -120,6 +124,34 @@ private string GetUserAccountId() return string.Empty; } + /// + /// Gets the latest version from the loaded Az modules. + /// + private Version GetAzVersion() + { + Version latestAz = DefaultVersion; + + try + { + var outputs = AzContext.ExecuteScript("Get-Module -Name Az -ListAvailable"); + foreach (PSObject obj in outputs) + { + string psVersion = obj.Properties["Version"].Value.ToString(); + int pos = psVersion.IndexOf('-'); + Version currentAz = (pos == -1) ? new Version(psVersion) : new Version(psVersion.Substring(0, pos)); + if (currentAz > latestAz) + { + latestAz = currentAz; + } + } + } + catch (Exception) + { + } + + return latestAz; + } + /// /// Executes the PowerShell cmdlet in the current powershell session. /// diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor/AzPredictorService.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor/AzPredictorService.cs index 59605d701768..cbe0f2c3786f 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor/AzPredictorService.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor/AzPredictorService.cs @@ -44,11 +44,11 @@ public sealed class RequestContext public Version VersionNumber{ get; set; } = new Version(0, 0); } - public string History { get; set; } + public IEnumerable History { get; set; } public string ClientType { get; set; } = AzPredictorService.ClientType; public RequestContext Context { get; set; } = new RequestContext(); - public PredictionRequestBody(string command) => History = command; + public PredictionRequestBody(IEnumerable commands) => History = commands; }; private sealed class CommandRequestContext @@ -98,7 +98,7 @@ public AzPredictorService(string serviceUri, ITelemetryClient telemetryClient, I Validation.CheckArgument(telemetryClient, $"{nameof(telemetryClient)} cannot be null."); Validation.CheckArgument(azContext, $"{nameof(azContext)} cannot be null."); - _commandsEndpoint = $"{serviceUri}{AzPredictorConstants.CommandsEndpoint}?clientType={AzPredictorService.ClientType}&context={JsonSerializer.Serialize(new CommandRequestContext(), JsonUtilities.DefaultSerializerOptions)}"; + _commandsEndpoint = $"{serviceUri}{AzPredictorConstants.CommandsEndpoint}?clientType={AzPredictorService.ClientType}&context.versionNumber={azContext.AzVersion}"; _predictionsEndpoint = serviceUri + AzPredictorConstants.PredictionsEndpoint; _telemetryClient = telemetryClient; _azContext = azContext; @@ -264,9 +264,10 @@ public virtual void RequestPredictions(IEnumerable commands) { SessionId = _telemetryClient.SessionId, CorrelationId = _telemetryClient.CorrelationId, + VersionNumber = this._azContext.AzVersion }; - var requestBody = new PredictionRequestBody(localCommands) + var requestBody = new PredictionRequestBody(commands) { Context = requestContext, }; @@ -277,7 +278,7 @@ public virtual void RequestPredictions(IEnumerable commands) httpResponseMessage.EnsureSuccessStatusCode(); var reply = await httpResponseMessage.Content.ReadAsStreamAsync(cancellationToken); - var suggestionsList = await JsonSerializer.DeserializeAsync>(reply, JsonUtilities.DefaultSerializerOptions); + var suggestionsList = await JsonSerializer.DeserializeAsync>(reply, JsonUtilities.DefaultSerializerOptions); SetCommandBasedPreditor(localCommands, suggestionsList); } @@ -336,7 +337,7 @@ protected virtual void RequestAllPredictiveCommands() httpResponseMessage.EnsureSuccessStatusCode(); var reply = await httpResponseMessage.Content.ReadAsStringAsync(); - var commandsReply = JsonSerializer.Deserialize>(reply, JsonUtilities.DefaultSerializerOptions); + var commandsReply = JsonSerializer.Deserialize>(reply, JsonUtilities.DefaultSerializerOptions); SetFallbackPredictor(commandsReply); } catch (Exception e) @@ -359,12 +360,12 @@ protected virtual void RequestAllPredictiveCommands() /// Sets the fallback predictor. /// /// The command collection to set the predictor - protected void SetFallbackPredictor(IList commands) + protected void SetFallbackPredictor(IList commands) { Validation.CheckArgument(commands, $"{nameof(commands)} cannot be null."); _fallbackPredictor = new CommandLinePredictor(commands, _parameterValuePredictor); - _allPredictiveCommands = commands.Select(x => AzPredictorService.GetCommandName(x)).ToHashSet(StringComparer.OrdinalIgnoreCase); // this could be slow + _allPredictiveCommands = commands.Select(x => AzPredictorService.GetCommandName(x.Command)).ToHashSet(StringComparer.OrdinalIgnoreCase); // this could be slow } /// @@ -372,7 +373,7 @@ protected void SetFallbackPredictor(IList commands) /// /// The commands that the suggestions are for /// The suggestion collection to set the predictor - protected void SetCommandBasedPreditor(string commands, IList suggestions) + protected void SetCommandBasedPreditor(string commands, IList suggestions) { Validation.CheckArgument(!string.IsNullOrWhiteSpace(commands), $"{nameof(commands)} cannot be null or whitespace."); Validation.CheckArgument(suggestions, $"{nameof(suggestions)} cannot be null."); diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor/AzPredictorSettings.json b/tools/Az.Tools.Predictor/Az.Tools.Predictor/AzPredictorSettings.json index 60545bdbb0bb..50e37963ef68 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor/AzPredictorSettings.json +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor/AzPredictorSettings.json @@ -1,5 +1,5 @@ { "maxAllowedCommandDuplicate": 1, - "serviceUri": "https://app.aladdin.microsoft.com/api/v1", + "serviceUri": "https://app.aladdin.microsoft.com/api/v2.0", "suggestionCount": 7 } diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor/CommandLine.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor/CommandLine.cs index 991249765eb0..f58422547e21 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor/CommandLine.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor/CommandLine.cs @@ -27,6 +27,11 @@ sealed class CommandLine /// public string Name { get; } + /// + /// Gets the description text for the command. + /// + public string Description { get; } + /// /// Gets the . /// @@ -36,12 +41,14 @@ sealed class CommandLine /// Create a new instance of with the command name and parameter set. /// /// The command name. + /// The command's description /// The parameter set. - public CommandLine(string name, ParameterSet parameterSet) + public CommandLine(string name, string description, ParameterSet parameterSet) { Validation.CheckArgument(!string.IsNullOrWhiteSpace(name), $"{nameof(name)} must not be null or whitespace."); Name = name; + Description = description; ParameterSet = parameterSet; } } diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor/CommandLinePredictor.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor/CommandLinePredictor.cs index 2a193f134ada..f0bdebcaf252 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor/CommandLinePredictor.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor/CommandLinePredictor.cs @@ -33,6 +33,19 @@ namespace Microsoft.Azure.PowerShell.Tools.AzPredictor /// internal sealed class CommandLinePredictor { + private class DuplicateResult + { + public string Source { get; set; } + + public string Description { get; set; } + + public DuplicateResult(string source, string description) + { + this.Source = source; + this.Description = description; + } + } + private readonly IList _commandLinePredictions = new List(); private readonly ParameterValuePredictor _parameterValuePredictor; @@ -41,23 +54,23 @@ internal sealed class CommandLinePredictor /// /// List of suggestions from the model, sorted by frequency (most to least). /// Provide the prediction to the parameter values. - public CommandLinePredictor(IList modelPredictions, ParameterValuePredictor parameterValuePredictor) + public CommandLinePredictor(IList modelPredictions, ParameterValuePredictor parameterValuePredictor) { Validation.CheckArgument(modelPredictions, $"{nameof(modelPredictions)} cannot be null."); _parameterValuePredictor = parameterValuePredictor; var commnadLines = new List(); - foreach (var predictionTextRaw in modelPredictions ?? Enumerable.Empty()) + foreach (var predictiveCommand in modelPredictions ?? Enumerable.Empty()) { - var predictionText = CommandLineUtilities.EscapePredictionText(predictionTextRaw); + var predictionText = CommandLineUtilities.EscapePredictionText(predictiveCommand.Command); Ast ast = Parser.ParseInput(predictionText, out Token[] tokens, out _); var commandAst = (ast.Find((ast) => ast is CommandAst, searchNestedScriptBlocks: false) as CommandAst); if (commandAst?.CommandElements[0] is StringConstantExpressionAst commandName) { var parameterSet = new ParameterSet(commandAst); - this._commandLinePredictions.Add(new CommandLine(commandName.Value, parameterSet)); + this._commandLinePredictions.Add(new CommandLine(commandName.Value, predictiveCommand.Description, parameterSet)); } } } @@ -90,7 +103,7 @@ public CommandLineSuggestion GetSuggestion(string inputCommandName, const int commandCollectionCapacity = 10; CommandLineSuggestion result = new(); - var resultsTemp = new Dictionary(commandCollectionCapacity, StringComparer.OrdinalIgnoreCase); + var duplicateResults = new Dictionary(commandCollectionCapacity, StringComparer.OrdinalIgnoreCase); var isCommandNameComplete = inputParameterSet.Parameters.Any() || rawUserInput.EndsWith(' '); @@ -144,17 +157,17 @@ public CommandLineSuggestion GetSuggestion(string inputCommandName, if (!presentCommands.ContainsKey(_commandLinePredictions[i].Name)) { - result.AddSuggestion(new PredictiveSuggestion(prediction), sourceBuilder.ToString()); + result.AddSuggestion(new PredictiveSuggestion(prediction, _commandLinePredictions[i].Description), sourceBuilder.ToString()); presentCommands.Add(_commandLinePredictions[i].Name, 1); } else if (presentCommands[_commandLinePredictions[i].Name] < maxAllowedCommandDuplicate) { - result.AddSuggestion(new PredictiveSuggestion(prediction), sourceBuilder.ToString()); + result.AddSuggestion(new PredictiveSuggestion(prediction, _commandLinePredictions[i].Description), sourceBuilder.ToString()); presentCommands[_commandLinePredictions[i].Name] += 1; } else { - _ = resultsTemp.TryAdd(prediction, sourceBuilder.ToString()); + _ = duplicateResults.TryAdd(prediction, new DuplicateResult(sourceBuilder.ToString(), _commandLinePredictions[i].Description)); } } } @@ -162,11 +175,11 @@ public CommandLineSuggestion GetSuggestion(string inputCommandName, var resultCount = result.Count; - if ((resultCount < suggestionCount) && (resultsTemp.Count > 0)) + if ((resultCount < suggestionCount) && (duplicateResults.Count > 0)) { - foreach (var temp in resultsTemp.Take(suggestionCount - resultCount)) + foreach (var temp in duplicateResults.Take(suggestionCount - resultCount)) { - result.AddSuggestion(new PredictiveSuggestion(temp.Key), temp.Value); + result.AddSuggestion(new PredictiveSuggestion(temp.Key, temp.Value.Description), temp.Value.Source); } } diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor/IAzContext.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor/IAzContext.cs index 7c19d92de0f8..657ea8369f3c 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor/IAzContext.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor/IAzContext.cs @@ -46,6 +46,11 @@ internal interface IAzContext /// public Version ModuleVersion { get; } + /// + /// Gets the current Az module version. + /// + public Version AzVersion { get; } + /// /// Updates the Az context. /// diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor/IAzPredictorService.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor/IAzPredictorService.cs index 038935825aa0..80825fd43fc7 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor/IAzPredictorService.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor/IAzPredictorService.cs @@ -12,6 +12,7 @@ // limitations under the License. // ---------------------------------------------------------------------------------- +using System; using System.Collections.Generic; using System.Management.Automation.Language; using System.Threading; diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor/PredictiveCommand.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor/PredictiveCommand.cs new file mode 100644 index 000000000000..b5657aa7da95 --- /dev/null +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor/PredictiveCommand.cs @@ -0,0 +1,32 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +namespace Microsoft.Azure.PowerShell.Tools.AzPredictor +{ + /// + /// A command predicted by the predictor service. + /// + public class PredictiveCommand + { + /// + /// The command name. + /// + public string Command { get; set; } + + /// + /// The description of the command. + /// + public string Description { get; set; } + } +}