Skip to content

Commit

Permalink
Merge internal/Az.Tools.Predictor (#13546)
Browse files Browse the repository at this point in the history
* psd1 & psm1 of Az.Installer with a demo cmdlet (#12698)

* Internal/az.installer (#12817)

* add util functions

* add install-azmodule

* add log to cmdlets

* move verbose messages to debug

* move under tools\

* polish warning message

* move install-azmodule to exports

* export install-azmodule

* rename to az.tools.installer

* Internal/az.installer (#12860)

* add util functions

* add install-azmodule

* add log to cmdlets

* move verbose messages to debug

* move under tools\

* polish warning message

* move install-azmodule to exports

* export install-azmodule

* rename to az.tools.installer

* add uninstall-AzModule

* Cmdlet Update-AzModule (#12832)

* Update-AzModule

* Address to PM requirements

1. Remove prefix Az. when input module name
2. update calculate from most recently installed respositories of
different modules
3. reorder the sequence of module udpate and uninstall
4. other bug fix

* Add telemetry

* Support telemetry

* Move Get-AzModuleUpdateList to internal (#12865)

* add telemetry to Uninstall-AzModule cmdlet

* bugfix: module name was not handled properly

* Add environment variable to disable telemetry

* parallel executing Install/Uninstall module

* update code after review

* improve performance

* Fix Update-AzModule issues

* bug fix

* remove unused util

* remove az.accounts when allow preview

* Fix issue when no module to udpate

* Add sign pipeline

* skip confirmation when remove-job

* remove debug info

* fix parameter reference

* Initial checking in AzPredictor (#12847)

- It contains an implementation of ICommandPredictor that provides
  predictions to PSReadLine.
- It also talks to the service endpoints to get the predictions.
- It reads from the profile settings about the service endpoint.
- There are some tests cases.

* filter installedmodules before uninstall

* bugfix for uninstall

* Add synopsis and example to exported cmdlets

* add default parameter set for uninstall-azmodule

* add input validatin

* remove unnecessary warning message

* Build and package module under artifacts folder

* Improve Az.Tool.Predictor (#12922)

* Set up the dependencies on the PSReadline 2.1.0

* Initialize the env when the module is imported.

- Add a script AzPredictor.ps1 to set the psreadline prediction view and
  source.
- The script is run when the module is imported.

* Fix a bug when loading settings from user profile.

- The settings from user profile may not exist. In this case we should
  just ignore it and use the default one.

* Fix issues in getting settings and send requests.

- Fix the way to get the Azure PowerShell settings regarding collecting
  telemetry.
- Avoid sending multiple requests while there is one running.

* Use the NuGet pacakges from nuget.org.

- Remove the local feed for those NuGet packages.

* Rename namespace/assemblies/module name

* Collect telemetry where we get the prediction.

* Make some classes internal.

* Add dependencies on Az module

- This avoid the issue that our module loads
  Microsoft.Azure.PowerShell.Common dlls and Az tries to load it too.

* Remove ps1 file that sets psreadline options.

- We should instruct the users to set the options by themselves.

* Remove psreadline module since it's not released.

* Fix the merge issue

* Add Az as external dependency

* Add pipeline 'sign-tool-predictor'

* Update sign-tool-predictor.yml for Azure Pipelines

* Update sign-tool-predictor.yml for Azure Pipelines

* net.webclient.downloadfile

* refine command

* clean build

* Update sign-tool-predictor.yml for Azure Pipelines

* Improve the build of Az.Tools.Predictor (#12974)

* Change the build for Az.Tools.Predictor

 - Do a 'dotnet publish' instead of 'dotnet build' when the
   configuration is release.
- When the configuration is release, replace the output folder with the
  ones from publish folder. The output folder is where the package
  retrieve the contents from. This will have the module and all the
  dependencies in the package.
- The package target only runs when the configuration is release.
- Add a target Test to run the unit tests.
- Update the build command in azure pipeline to build with configuration
  release.

* Specify the sub-folder artifact for each tool.

- The build process involves deleting the artifact folders. And each
  tool shares the same artifact folder. This may be an issue if we build
  them in parralel because the build process of a tool will delete the
  folder while another tool is being built.
- We'll use sub-folder for each tool in the artifact folder.

Co-authored-by: Beisi Zhou <[email protected]>

* Update sign-tool-predictor.yml for Azure Pipelines

* Update sign-tool-predictor.yml for Azure Pipelines

* Update sign-tool-predictor.yml for Azure Pipelines

* Update sign-tool-predictor.yml for Azure Pipelines

* Override powershellcorecommandPrefix

* join_path

* Update sign-tool-predictor.yml for Azure Pipelines

* Update sign-tool-predictor.yml for Azure Pipelines

* Update sign-tool-predictor.yml for Azure Pipelines

* Update sign-tool-predictor.yml for Azure Pipelines

* Install Az

* Update sign-tool-predictor.yml for Azure Pipelines

* Update sign-tool-predictor.yml for Azure Pipelines

* Sign dll

* Remove dll sign

* Predict parameter values in the suggestion (#12984)

* Get the parameter value from the history.

* Add a mock ps console for testing purpose.

- The mock ps console will echo back most of the commands. So that we
  don't need to really execute the Az command on Azure to test the
  prediction.

* improve telemetry (#13025)

* Correlate the telemetry event we send.

- We have these telemetry entry points when we provide suggestion, when
  a suggestion is accepted, and when the user executes some command. We
  add a SuggestionId to the telemetry events so that we can correlate
  those three events. Doing that we know what suggestions are provided,
  accepted, and executed.

* Collect and correlate our telemetry event.

- With this change, we have these telemetry events;
  * RequestPrediction
  * GetSuggestion
  * AcceptSuggestion
  * CommandHistory
- The events can be correlated by the session id and correlate id that
  are associate with the events.

* Fix the request body.

* Rename the prediction source.

* Collect telemetry when an error occurs.

* Remove some PII field

* Collect user input in GetSuggestion event.

* Use a common telemetry event prefix.

* Remove the .gitignore that shouldn't be added.

* Clean up the code.

* return multiple suggestion (#13098)

* Return multiple suggestions.

- Add a setting to configure at most how many suggestions to return.
- We'll go through the command/parameters one by one and to construct
  the suggestion. We may return multiple suggestions for the same
  command but with different parameter sets;

* Use camel casing in the setting fields.

- Looks like other json file in $HOME/.azure use camel case or
  PascalCase. None use snake case.

* Fix a logic error.

- We'll use the command list for suggestion while the prediction list
  isn't available.

* Stop finding suggestion when the count is met.

* Improve the MockPSConsole.

* Cache the last two commands from the history.

* Reduce the dependencies on Azure powershell common. (#13113)

- That assembly and its dependencies causes a conflict if we load this module
  and Az.Accounts module. Though we can work around by sepcifying Az as a
  dependencies on this module, that'll cause long loading time.
- The reason of loading that assembly is to get the setting about Azure
  PowerShell data collection. We can copy part of the code to load that
  file, so that we don't need that assembly as the dependency.

* Add a missing file. (#13234)

* Fix duplicate text (#13326)

* Improve the debugging experience.

- GetSuggestion gets cancelled during debugging because it times out. So
  we use an environment variable to control whether to allow
cancellation from psreadline.
- Use another macro to control if print message for telemetry.

* Fix a bug that the command line is repeated in the suggestion.

- When we parse the command line and there is an incomplete parameter
  list, we repeat the command line in the suggestion.
- The cause is that we parse the command line and get the wrong
  parameter set from the user input

* Update how we send request and collect telemetry (#13327)

* Fix the query

* Reduce the number of requests to the service.

- We request the prediction for the command history. When the command
  history isn't changed, we don't need to request the prediction again.

* Not to collect the parameter value in the telemetry.

* Bug fixes and performance improvement (#13410)

* Reduce extra cost to the perf issue.

* Remove the aggregation on the parameter set.

* Fix an issue

* Fix some comments.

* Improve the telemetry and http request (#13354)

* Collect user id and mac address.

- We hash the user account id and the mac address, and collect those in
  the telemetry. These are used to find how many users are using this
  mdoule.
- We also send the hashed user account id in the http request header.
  This is used to enable throttling by user account.

* Rename

* Collect more data for diagnostic purpose.

* Fix typo

* Remove getting Az modules versions.

* Update module infomation (#13328)

* Set the description and dependencies for the module.

* Update the project file and module manifest.

* Update manifest and csproj

* Fix typo

* Move PSReadLine to ExternalModuleDependencies.

- PSReadLine is in beta and there are issues in setting RequiredModules
  with a beta one. So move it as an ExternalModuleDependencies.

* Update package script to support requiredmodule (#13424)

* Add variety to Az.Predictor result list (#13420)

* add variety to predictions list

* add variety to predictions list

* Update description for release

* Add PublishLocation to build.proj of Az.Tools.Installer

Co-authored-by: Jin Lei <[email protected]>
Co-authored-by: Yabo Hu <[email protected]>
Co-authored-by: msJinLei <[email protected]>
Co-authored-by: msJinLei <[email protected]>
Co-authored-by: kceiw <[email protected]>
Co-authored-by: Beisi Zhou <[email protected]>
Co-authored-by: Beisi Zhou <[email protected]>
Co-authored-by: yemohyle <[email protected]>
  • Loading branch information
9 people authored Nov 19, 2020
1 parent 7a94d31 commit af7cf59
Show file tree
Hide file tree
Showing 38 changed files with 3,285 additions and 4 deletions.
93 changes: 93 additions & 0 deletions .azure-pipelines/sign-tool-predictor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
pr: none
trigger: none
pool:
vmImage: 'windows-2019'

steps:
- task: PowerShell@2
displayName: Install PS 7.1.0-preview.7
inputs:
targetType: 'inline'
script: |
$url = "https://github.com/PowerShell/PowerShell/releases/download/v7.1.0-preview.7/PowerShell-7.1.0-preview.7-win-x64.zip"
$output = Join-Path -Path $(Pipeline.Workspace) -ChildPath "./PowerShell-7.1.0-preview.7-win-x64.zip"
(New-Object System.Net.WebClient).DownloadFile($url, $output)
$pwshPath= Join-Path -Path $(Pipeline.Workspace) -ChildPath "./PowerShell-7.1.0-preview.7/"
Expand-Archive -Path $output -DestinationPath $pwshPath
$pwshFullPath = Convert-Path $pwshPath
Write-Host $pwshFullPath
- task: PowerShell@2
displayName: 'Install platyPS, PowerShellGet, Az 3.0.0'
inputs:
targetType: inline
script: |
$pwshPath= Join-Path -Path $(Pipeline.Workspace) -ChildPath "./PowerShell-7.1.0-preview.7/pwsh.exe"
$command = "`$PSVersionTable `
Install-Module platyPS -Force -Confirm:`$false -Scope CurrentUser `
Install-Module PowerShellGet -Force -Confirm:`$false -Scope CurrentUser -SkipPublisherCheck `
Install-Module Az -Repository PSGallery -RequiredVersion 3.0.0 -Confirm:`$false -Scope CurrentUser -AllowClobber -Force"
Invoke-Command -ScriptBlock { param ($pwshPath, $command) & $pwshPath -Command $command } -ArgumentList $pwshPath, $command
- task: UseDotNet@2
displayName: 'Use .NET Core sdk'
inputs:
packageType: sdk
version: 5.0.100-rc.1.20452.10

- task: DotNetCoreCLI@2
displayName: 'Build'
inputs:
command: custom
custom: msbuild
arguments: 'tools\Az.Tools.Predictor\build.proj /target:"Clean;Build" /p:Configuration=Release'

- task: EsrpCodeSigning@1
displayName: 'Signing'
inputs:
ConnectedServiceName: $(signServiceConnection)
FolderPath: artifacts
Pattern: |
Tools/**/*.ps1
Tools/**/*.psd1
Tools/**/*.psm1
Tools/**/*.ps1xml
UseMinimatch: true
signConfigType: inlineSignParams
inlineOperation: |
[
{
"KeyCode": "CP-230012",
"OperationCode": "SigntoolSign",
"Parameters": {
"OpusName": "Microsoft",
"OpusInfo": "http://www.microsoft.com",
"FileDigest": "/fd \"SHA256\"",
"PageHash": "/NPH",
"TimeStamp": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
},
"ToolName": "sign",
"ToolVersion": "1.0"
},
{
"KeyCode": "CP-230012",
"OperationCode": "SigntoolVerify",
"Parameters": {},
"ToolName": "sign",
"ToolVersion": "1.0"
}
]
- task: DotNetCoreCLI@2
displayName: Package
inputs:
command: custom
custom: msbuild
arguments: 'tools\Az.Tools.Predictor\build.proj /target:"Package" /p:Configuration=Release /p:PowerShellCoreCommandPrefix="$(Pipeline.Workspace)\\PowerShell-7.1.0-preview.7\\pwsh.exe -NonInteractive -NoLogo -NoProfile -Command" '

- task: PublishPipelineArtifact@0
displayName: 'Save artifacts'
inputs:
artifactName: artifacts
targetPath: artifacts
condition: succeededOrFailed()
4 changes: 2 additions & 2 deletions tools/Az.Tools.Installer/build.proj
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@

<Target Name="Package">
<Message Text="Package $(ModuleName)" />
<Exec Command="$(PowerShellCoreCommandPrefix) &quot;$(RepoTools)\PublishToolsModule.ps1 -RepositoryLocation $(ArtifactFolder) -ModuleName $(ModuleName)&quot;" />
<Exec Command="$(PowerShellCoreCommandPrefix) &quot;$(RepoTools)\PublishToolsModule.ps1 -RepositoryLocation $(ArtifactFolder) -PublishLocation $(ArtifactFolder) -ModuleName $(ModuleName)&quot;" />
</Target>
</Project>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<AssemblyName>Microsoft.Azure.PowerShell.Tools.AzPredictor.Test</AssemblyName>
<RootNamespace>Microsoft.Azure.PowerShell.Tools.AzPredictor.Test</RootNamespace>
<IsPackable>false</IsPackable>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<RepoArtifacts>$(MSBuildThisFileDirectory)</RepoArtifacts>
<OutputPath>$(RepoArtifacts)..\..\..\artifacts\Tools\Az.Tools.Predictor.Test\</OutputPath>
<DocumentationFile>$(OutputPath)\Microsoft.Azure.PowerShell.AzPredictor.Tools.Test.xml</DocumentationFile>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.Management.Automation" Version="7.1.0-preview.7" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="1.3.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<ProjectReference Include="..\Az.Tools.Predictor\Az.Tools.Predictor.csproj" />
</ItemGroup>

<ItemGroup>
<None Include="Data\CommandsModel.zip" CopyToOutputDirectory="PreserveNewest" />
<None Include="Data\PredictionsModel.zip" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// ----------------------------------------------------------------------------------
//
// 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 Microsoft.Azure.PowerShell.Tools.AzPredictor.Test.Mocks;
using System.Linq;
using System.Management.Automation.Subsystem;
using System.Threading;
using Xunit;

namespace Microsoft.Azure.PowerShell.Tools.AzPredictor.Test
{
/// <summary>
/// Tests for <see cref="AzPredictorService"/>
/// </summary>
[Collection("Model collection")]
public class AzPredictorServiceTests
{
private readonly ModelFixture _fixture;
private readonly AzPredictorService _service;
private readonly Predictor _suggestionsPredictor;
private readonly Predictor _commandsPredictor;

/// <summary>
/// Constructs a new instance of <see cref="AzPredictorServiceTests"/>
/// </summary>
/// <param name="fixture"></param>
public AzPredictorServiceTests(ModelFixture fixture)
{
this._fixture = fixture;
var startHistory = $"{AzPredictorConstants.CommandPlaceholder}{AzPredictorConstants.CommandConcatenator}{AzPredictorConstants.CommandPlaceholder}";
this._suggestionsPredictor = new Predictor(this._fixture.PredictionCollection[startHistory], null);
this._commandsPredictor = new Predictor(this._fixture.CommandCollection, null);

this._service = new MockAzPredictorService(startHistory, this._fixture.PredictionCollection[startHistory], this._fixture.CommandCollection);
}


/// <summary>
/// Verifies that the prediction comes from the suggestions list, not the command list.
/// </summary>
[Theory]
[InlineData("CONNECT-AZACCOUNT")]
[InlineData("set-azstorageaccount ")]
[InlineData("Get-AzResourceG")]
[InlineData("Get-AzStorageAcco")]
[InlineData("Get-AzKeyVault -VaultName")]
[InlineData("GET-AZSTORAGEACCOUNTKEY -NAME ")]
[InlineData("new-azresourcegroup -name hello")]
[InlineData("Get-AzContext -Name")]
[InlineData("Get-AzContext -ErrorAction")]
public void VerifyUsingSuggestion(string userInput)
{
var predictionContext = PredictionContext.Create(userInput);
var expected = this._suggestionsPredictor.Query(predictionContext.InputAst, 1, CancellationToken.None);
var actual = this._service.GetSuggestion(predictionContext.InputAst, 1, CancellationToken.None);
Assert.NotEmpty(actual);
Assert.NotNull(actual.First().Item1);
Assert.Equal(expected.First().Key, actual.First().Item1);
Assert.Equal(PredictionSource.CurrentCommand, actual.First().Item3);
}

/// <summary>
/// Verifies that when no prediction is in the suggestion list, we'll use the command list.
/// </summary>
[Theory]
[InlineData("Get-AzResource -Name hello -Pre")]
[InlineData("Get-AzADServicePrincipal -ApplicationObject")]
public void VerifyUsingCommand(string userInput)
{
var predictionContext = PredictionContext.Create(userInput);
var expected = this._commandsPredictor.Query(predictionContext.InputAst, 1, CancellationToken.None);
var actual = this._service.GetSuggestion(predictionContext.InputAst, 1, CancellationToken.None);
Assert.NotEmpty(actual);
Assert.NotNull(actual.First().Item1);
Assert.Equal(expected.First().Key, actual.First().Item1);
Assert.Equal(PredictionSource.StaticCommands, actual.First().Item3);
}

/// <summary>
/// Verify that no prediction for the user input, meaning it's not in the prediction list or the command list.
/// </summary>
[Theory]
[InlineData(AzPredictorConstants.CommandPlaceholder)]
[InlineData("git status")]
[InlineData("Get-ChildItem")]
[InlineData("new-azresourcegroup -NoExistingParam")]
[InlineData("get-azaccount ")]
[InlineData("Get-AzContext Name")]
[InlineData("NEW-AZCONTEXT")]
public void VerifyNoPrediction(string userInput)
{
var predictionContext = PredictionContext.Create(userInput);
var actual = this._service.GetSuggestion(predictionContext.InputAst, 1, CancellationToken.None);
Assert.Empty(actual);
}
}
}
Loading

0 comments on commit af7cf59

Please sign in to comment.