Merge pull request #14438 from dotnet-maestro-bot/merge/release/3.1-to-master
[automated] Merge branch 'release/3.1' => 'master'
This commit is contained in:
commit
cd2983bf41
|
|
@ -55,6 +55,7 @@ parameters:
|
|||
artifacts: []
|
||||
buildDirectory: ''
|
||||
buildScript: ''
|
||||
installTar: true
|
||||
installNodeJs: true
|
||||
installJdk: true
|
||||
timeoutInMinutes: 180
|
||||
|
|
@ -151,6 +152,9 @@ jobs:
|
|||
Write-Host "##vso[task.setvariable variable=SeleniumProcessTrackingFolder]$(BuildDirectory)\artifacts\tmp\selenium\"
|
||||
./eng/scripts/InstallGoogleChrome.ps1
|
||||
displayName: Install Chrome
|
||||
- ${{ if and(eq(parameters.installTar, 'true'), eq(parameters.agentOs, 'Windows')) }}:
|
||||
- powershell: ./eng/scripts/InstallTar.ps1
|
||||
displayName: Find or install Tar
|
||||
|
||||
- ${{ parameters.beforeBuild }}
|
||||
|
||||
|
|
|
|||
18
build.ps1
18
build.ps1
|
|
@ -307,6 +307,8 @@ if (-not $foundJdk -and $RunBuild -and ($All -or $BuildJava) -and -not $NoBuildJ
|
|||
# Initialize global variables need to be set before the import of Arcade is imported
|
||||
$restore = $RunRestore
|
||||
|
||||
# Though VS Code may indicate $nodeReuse, $warnAsError and $msbuildEngine are unused, tools.ps1 uses them.
|
||||
|
||||
# Disable node reuse - Workaround perpetual issues in node reuse and custom task assemblies
|
||||
$nodeReuse = $false
|
||||
$env:MSBUILDDISABLENODEREUSE=1
|
||||
|
|
@ -328,10 +330,10 @@ if ($CI) {
|
|||
}
|
||||
|
||||
# tools.ps1 corrupts global state, so reset these values in case they carried over from a previous build
|
||||
rm variable:global:_BuildTool -ea Ignore
|
||||
rm variable:global:_DotNetInstallDir -ea Ignore
|
||||
rm variable:global:_ToolsetBuildProj -ea Ignore
|
||||
rm variable:global:_MSBuildExe -ea Ignore
|
||||
Remove-Item variable:global:_BuildTool -ea Ignore
|
||||
Remove-Item variable:global:_DotNetInstallDir -ea Ignore
|
||||
Remove-Item variable:global:_ToolsetBuildProj -ea Ignore
|
||||
Remove-Item variable:global:_MSBuildExe -ea Ignore
|
||||
|
||||
# Import Arcade
|
||||
. "$PSScriptRoot/eng/common/tools.ps1"
|
||||
|
|
@ -391,10 +393,10 @@ finally {
|
|||
}
|
||||
|
||||
# tools.ps1 corrupts global state, so reset these values so they don't carry between invocations of build.ps1
|
||||
rm variable:global:_BuildTool -ea Ignore
|
||||
rm variable:global:_DotNetInstallDir -ea Ignore
|
||||
rm variable:global:_ToolsetBuildProj -ea Ignore
|
||||
rm variable:global:_MSBuildExe -ea Ignore
|
||||
Remove-Item variable:global:_BuildTool -ea Ignore
|
||||
Remove-Item variable:global:_DotNetInstallDir -ea Ignore
|
||||
Remove-Item variable:global:_ToolsetBuildProj -ea Ignore
|
||||
Remove-Item variable:global:_MSBuildExe -ea Ignore
|
||||
|
||||
if ($DumpProcesses -or $ci) {
|
||||
Stop-Job -Name DumpProcesses
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ Building ASP.NET Core on Windows requires:
|
|||
```ps1
|
||||
PS> ./eng/scripts/InstallJdk.ps1
|
||||
```
|
||||
* Chrome - Selenium-based tests require a version of Chrome to be installed. Download and install it from [https://www.google.com/chrome]
|
||||
|
||||
### macOS/Linux
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<Project>
|
||||
<PropertyGroup>
|
||||
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
|
||||
<AspNetCoreBaselineVersion>2.2.6</AspNetCoreBaselineVersion>
|
||||
<AspNetCoreBaselineVersion>2.2.7</AspNetCoreBaselineVersion>
|
||||
</PropertyGroup>
|
||||
<!-- Package: dotnet-dev-certs-->
|
||||
<PropertyGroup Condition=" '$(PackageId)' == 'dotnet-dev-certs' ">
|
||||
|
|
@ -77,12 +77,12 @@
|
|||
</ItemGroup>
|
||||
<!-- Package: Microsoft.AspNetCore.AspNetCoreModule-->
|
||||
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.AspNetCoreModule' ">
|
||||
<BaselinePackageVersion>2.2.6</BaselinePackageVersion>
|
||||
<BaselinePackageVersion>2.2.7</BaselinePackageVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.AspNetCoreModule' AND '$(TargetFramework)' == 'netcoreapp2.2' " />
|
||||
<!-- Package: Microsoft.AspNetCore.AspNetCoreModuleV2-->
|
||||
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.AspNetCoreModuleV2' ">
|
||||
<BaselinePackageVersion>2.2.6</BaselinePackageVersion>
|
||||
<BaselinePackageVersion>2.2.7</BaselinePackageVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.AspNetCoreModuleV2' AND '$(TargetFramework)' == 'netcoreapp2.2' " />
|
||||
<!-- Package: Microsoft.AspNetCore.Authentication.Abstractions-->
|
||||
|
|
@ -303,10 +303,11 @@
|
|||
</ItemGroup>
|
||||
<!-- Package: Microsoft.AspNetCore.DataProtection.AzureStorage-->
|
||||
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.DataProtection.AzureStorage' ">
|
||||
<BaselinePackageVersion>2.2.0</BaselinePackageVersion>
|
||||
<BaselinePackageVersion>2.2.7</BaselinePackageVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.DataProtection.AzureStorage' AND '$(TargetFramework)' == 'netstandard2.0' ">
|
||||
<BaselinePackageReference Include="Microsoft.AspNetCore.DataProtection" Version="[2.2.0, )" />
|
||||
<BaselinePackageReference Include="Microsoft.Data.OData" Version="[5.8.4, )" />
|
||||
<BaselinePackageReference Include="WindowsAzure.Storage" Version="[8.1.4, )" />
|
||||
</ItemGroup>
|
||||
<!-- Package: Microsoft.AspNetCore.DataProtection.EntityFrameworkCore-->
|
||||
|
|
@ -434,21 +435,21 @@
|
|||
</ItemGroup>
|
||||
<!-- Package: Microsoft.AspNetCore.Hosting-->
|
||||
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Hosting' ">
|
||||
<BaselinePackageVersion>2.2.0</BaselinePackageVersion>
|
||||
<BaselinePackageVersion>2.2.7</BaselinePackageVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Hosting' AND '$(TargetFramework)' == 'netstandard2.0' ">
|
||||
<BaselinePackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="[2.2.0, )" />
|
||||
<BaselinePackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="[2.2.0, )" />
|
||||
<BaselinePackageReference Include="Microsoft.AspNetCore.Http" Version="[2.2.0, )" />
|
||||
<BaselinePackageReference Include="Microsoft.AspNetCore.Http.Extensions" Version="[2.2.0, )" />
|
||||
<BaselinePackageReference Include="Microsoft.Extensions.Configuration" Version="[2.2.0, )" />
|
||||
<BaselinePackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="[2.2.0, )" />
|
||||
<BaselinePackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="[2.2.4, )" />
|
||||
<BaselinePackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="[2.2.0, )" />
|
||||
<BaselinePackageReference Include="Microsoft.Extensions.DependencyInjection" Version="[2.2.0, )" />
|
||||
<BaselinePackageReference Include="Microsoft.Extensions.FileProviders.Physical" Version="[2.2.0, )" />
|
||||
<BaselinePackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="[2.2.0, )" />
|
||||
<BaselinePackageReference Include="Microsoft.Extensions.Logging" Version="[2.2.0, )" />
|
||||
<BaselinePackageReference Include="Microsoft.Extensions.Options" Version="[2.2.0, )" />
|
||||
<BaselinePackageReference Include="System.Diagnostics.DiagnosticSource" Version="[4.5.0, )" />
|
||||
<BaselinePackageReference Include="System.Diagnostics.DiagnosticSource" Version="[4.5.1, )" />
|
||||
<BaselinePackageReference Include="System.Reflection.Metadata" Version="[1.6.0, )" />
|
||||
</ItemGroup>
|
||||
<!-- Package: Microsoft.AspNetCore.Html.Abstractions-->
|
||||
|
|
@ -1197,12 +1198,12 @@
|
|||
</ItemGroup>
|
||||
<!-- Package: Microsoft.AspNetCore.SpaServices-->
|
||||
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.SpaServices' ">
|
||||
<BaselinePackageVersion>2.2.0</BaselinePackageVersion>
|
||||
<BaselinePackageVersion>2.2.7</BaselinePackageVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.SpaServices' AND '$(TargetFramework)' == 'netstandard2.0' ">
|
||||
<BaselinePackageReference Include="Microsoft.AspNetCore.NodeServices" Version="[2.2.0, )" />
|
||||
<BaselinePackageReference Include="Microsoft.AspNetCore.Mvc.TagHelpers" Version="[2.2.0, )" />
|
||||
<BaselinePackageReference Include="Microsoft.AspNetCore.Mvc.ViewFeatures" Version="[2.2.0, )" />
|
||||
<BaselinePackageReference Include="Microsoft.AspNetCore.NodeServices" Version="[2.2.0, )" />
|
||||
</ItemGroup>
|
||||
<!-- Package: Microsoft.AspNetCore.StaticFiles-->
|
||||
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.StaticFiles' ">
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ This file contains a list of all the packages and their versions which were rele
|
|||
build of ASP.NET Core 2.2.x. Update this list when preparing for a new patch.
|
||||
|
||||
-->
|
||||
<Baseline Version="2.2.6">
|
||||
<Baseline Version="2.2.7">
|
||||
<Package Id="dotnet-dev-certs" Version="2.2.0" />
|
||||
<Package Id="dotnet-sql-cache" Version="2.2.0" />
|
||||
<Package Id="dotnet-user-secrets" Version="2.2.0" />
|
||||
|
|
@ -12,8 +12,8 @@ build of ASP.NET Core 2.2.x. Update this list when preparing for a new patch.
|
|||
<Package Id="Microsoft.AspNetCore.Antiforgery" Version="2.2.0" />
|
||||
<Package Id="Microsoft.AspNetCore.ApiAuthorization.IdentityServer" Version="2.2.0-preview-35687" />
|
||||
<Package Id="Microsoft.AspNetCore.ApplicationInsights.HostingStartup" Version="2.2.0" />
|
||||
<Package Id="Microsoft.AspNetCore.AspNetCoreModule" Version="2.2.6" />
|
||||
<Package Id="Microsoft.AspNetCore.AspNetCoreModuleV2" Version="2.2.6" />
|
||||
<Package Id="Microsoft.AspNetCore.AspNetCoreModule" Version="2.2.7" />
|
||||
<Package Id="Microsoft.AspNetCore.AspNetCoreModuleV2" Version="2.2.7" />
|
||||
<Package Id="Microsoft.AspNetCore.Authentication.Abstractions" Version="2.2.0" />
|
||||
<Package Id="Microsoft.AspNetCore.Authentication.AzureAD.UI" Version="2.2.0" />
|
||||
<Package Id="Microsoft.AspNetCore.Authentication.AzureADB2C.UI" Version="2.2.0" />
|
||||
|
|
@ -39,7 +39,7 @@ build of ASP.NET Core 2.2.x. Update this list when preparing for a new patch.
|
|||
<Package Id="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="2.2.0" />
|
||||
<Package Id="Microsoft.AspNetCore.DataProtection.Abstractions" Version="2.2.0" />
|
||||
<Package Id="Microsoft.AspNetCore.DataProtection.AzureKeyVault" Version="2.2.0" />
|
||||
<Package Id="Microsoft.AspNetCore.DataProtection.AzureStorage" Version="2.2.0" />
|
||||
<Package Id="Microsoft.AspNetCore.DataProtection.AzureStorage" Version="2.2.7" />
|
||||
<Package Id="Microsoft.AspNetCore.DataProtection.EntityFrameworkCore" Version="2.2.0" />
|
||||
<Package Id="Microsoft.AspNetCore.DataProtection.Extensions" Version="2.2.0" />
|
||||
<Package Id="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="2.2.5" />
|
||||
|
|
@ -53,7 +53,7 @@ build of ASP.NET Core 2.2.x. Update this list when preparing for a new patch.
|
|||
<Package Id="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" />
|
||||
<Package Id="Microsoft.AspNetCore.Hosting.Server.Abstractions" Version="2.2.0" />
|
||||
<Package Id="Microsoft.AspNetCore.Hosting.WindowsServices" Version="2.2.0" />
|
||||
<Package Id="Microsoft.AspNetCore.Hosting" Version="2.2.0" />
|
||||
<Package Id="Microsoft.AspNetCore.Hosting" Version="2.2.7" />
|
||||
<Package Id="Microsoft.AspNetCore.Html.Abstractions" Version="2.2.0" />
|
||||
<Package Id="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
|
||||
<Package Id="Microsoft.AspNetCore.Http.Connections.Client" Version="1.1.0" />
|
||||
|
|
@ -122,7 +122,7 @@ build of ASP.NET Core 2.2.x. Update this list when preparing for a new patch.
|
|||
<Package Id="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="1.1.5" />
|
||||
<Package Id="Microsoft.AspNetCore.SignalR" Version="1.1.0" />
|
||||
<Package Id="Microsoft.AspNetCore.SpaServices.Extensions" Version="2.2.0" />
|
||||
<Package Id="Microsoft.AspNetCore.SpaServices" Version="2.2.0" />
|
||||
<Package Id="Microsoft.AspNetCore.SpaServices" Version="2.2.7" />
|
||||
<Package Id="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" />
|
||||
<Package Id="Microsoft.AspNetCore.TestHost" Version="2.2.0" />
|
||||
<Package Id="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />
|
||||
|
|
|
|||
|
|
@ -29,10 +29,6 @@ Later on, this will be checked using this condition:
|
|||
java:signalr;
|
||||
</PackagesInPatch>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(VersionPrefix)' == '2.2.3' ">
|
||||
<PackagesInPatch>
|
||||
</PackagesInPatch>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(VersionPrefix)' == '2.2.4' ">
|
||||
<PackagesInPatch>
|
||||
@aspnet/signalr;
|
||||
|
|
@ -70,4 +66,8 @@ Later on, this will be checked using this condition:
|
|||
Microsoft.AspNetCore.SpaServices;
|
||||
</PackagesInPatch>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(VersionPrefix)' == '2.2.8' ">
|
||||
<PackagesInPatch>
|
||||
</PackagesInPatch>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,74 @@
|
|||
<#
|
||||
.SYNOPSIS
|
||||
Finds or installs the Tar command on this system.
|
||||
.DESCRIPTION
|
||||
This script searches for Tar on this system. If not found, downloads and extracts Git to use its tar.exe. Prefers
|
||||
global installation locations even if Git has been downloaded into this repo.
|
||||
.PARAMETER GitVersion
|
||||
The version of the Git to install. If not set, the default value is read from global.json.
|
||||
.PARAMETER Force
|
||||
Overwrite the existing installation if one exists in this repo and Tar isn't installed globally.
|
||||
#>
|
||||
param(
|
||||
[string]$GitVersion,
|
||||
[switch]$Force
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$ProgressPreference = 'SilentlyContinue' # Workaround PowerShell/PowerShell#2138
|
||||
|
||||
Set-StrictMode -Version 1
|
||||
|
||||
# Find tar. If not found, install Git to get it.
|
||||
$repoRoot = (Join-Path $PSScriptRoot "..\.." -Resolve)
|
||||
$installDir = "$repoRoot\.tools\Git\win-x64"
|
||||
$tarCommand = "$installDir\usr\bin\tar.exe"
|
||||
$finalCommand = "$repoRoot\.tools\tar.exe"
|
||||
|
||||
Write-Host "Windows version and other information..."
|
||||
cmd.exe /c ver
|
||||
systeminfo.exe
|
||||
Write-Host "Processor Architecture: $env:PROCESSOR_ARCHITECTURE"
|
||||
|
||||
Write-Host "Checking $env:SystemRoot\System32\tar.exe"
|
||||
Get-ChildItem "$env:SystemRoot\System32\ta*.exe"
|
||||
if (Test-Path "$env:SystemRoot\System32\tar.exe") {
|
||||
Write-Host "Found $env:SystemRoot\System32\tar.exe"
|
||||
$tarCommand = "$env:SystemRoot\System32\tar.exe"
|
||||
}
|
||||
elseif (Test-Path "$env:ProgramFiles\Git\usr\bin\tar.exe") {
|
||||
$tarCommand = "$env:ProgramFiles\Git\usr\bin\tar.exe"
|
||||
}
|
||||
elseif (Test-Path "${env:ProgramFiles(x86)}\Git\usr\bin\tar.exe") {
|
||||
$tarCommand = "${env:ProgramFiles(x86)}\Git\usr\bin\tar.exe"
|
||||
}
|
||||
elseif (Test-Path "$env:AGENT_HOMEDIRECTORY\externals\git\usr\bin\tar.exe") {
|
||||
$tarCommand = "$env:AGENT_HOMEDIRECTORY\externals\git\usr\bin\tar.exe"
|
||||
}
|
||||
elseif ((Test-Path $tarCommand) -And (-Not $Force)) {
|
||||
Write-Verbose "Repo-local Git installation and $tarCommand already exist, skipping Git install."
|
||||
}
|
||||
else {
|
||||
if (-not $GitVersion) {
|
||||
$globalJson = Get-Content "$repoRoot\global.json" | ConvertFrom-Json
|
||||
$GitVersion = $globalJson.tools.Git
|
||||
}
|
||||
|
||||
$Uri = "https://netcorenativeassets.blob.core.windows.net/resource-packages/external/windows/git/Git-${GitVersion}-64-bit.zip"
|
||||
|
||||
Import-Module -Name (Join-Path $PSScriptRoot "..\common\native\CommonLibrary.psm1" -Resolve)
|
||||
$InstallStatus = CommonLibrary\DownloadAndExtract -Uri $Uri -InstallDirectory "$installDir\" -Force:$Force -Verbose
|
||||
|
||||
if ($InstallStatus -Eq $False) {
|
||||
Write-Error "Installation failed"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
New-Item "$repoRoot\.tools\" -ErrorAction SilentlyContinue -ItemType Directory
|
||||
Copy-Item "$tarCommand" "$finalCommand" -Verbose
|
||||
Write-Host "Tar now available at '$finalCommand'"
|
||||
|
||||
if ($tarCommand -like '*\Git\*') {
|
||||
$null >.\.tools\tar.fromGit
|
||||
}
|
||||
|
|
@ -61,15 +61,21 @@
|
|||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<_GenApiFile>$([MSBuild]::NormalizePath('$(ArtifactsDir)', 'log', 'GenAPI.rsp'))</_GenApiFile>
|
||||
<_GenAPICommand Condition="'$(MSBuildRuntimeType)' == 'core'">"$(DotNetTool)" --roll-forward-on-no-candidate-fx 2 "$(_GenAPIPath)"</_GenAPICommand>
|
||||
<_GenAPICmd>$(_GenAPICommand)</_GenAPICmd>
|
||||
<_GenAPICmd>$(_GenAPICmd) "$(TargetPath)"</_GenAPICmd>
|
||||
<_GenAPICmd>$(_GenAPICmd) --lib-path "@(_ReferencePathDirectories)"</_GenAPICmd>
|
||||
<_GenAPICmd>$(_GenAPICmd) --out "$(_RefSourceFileOutputPath)"</_GenAPICmd>
|
||||
<_GenAPICmd>$(_GenAPICmd) --header-file "$(RepoRoot)/eng/LicenseHeader.txt"</_GenAPICmd>
|
||||
<_GenAPICmd>$(_GenAPICmd) --exclude-api-list "$(RepoRoot)/eng/GenAPI.exclusions.txt"</_GenAPICmd>
|
||||
<_GenAPICmd>$(_GenAPICommand) @"$(_GenApiFile)"</_GenAPICmd>
|
||||
<_GenApiArguments><![CDATA[
|
||||
"$(TargetPath)"
|
||||
--lib-path "@(_ReferencePathDirectories, '%3B')"
|
||||
--out "$(_RefSourceFileOutputPath)"
|
||||
--header-file "$(RepoRoot)/eng/LicenseHeader.txt"
|
||||
--exclude-api-list "$(RepoRoot)/eng/GenAPI.exclusions.txt"
|
||||
]]>
|
||||
</_GenApiArguments>
|
||||
</PropertyGroup>
|
||||
|
||||
<WriteLinesToFile File="$(_GenApiFile)" Lines="$(_GenApiArguments)" Overwrite="true" />
|
||||
|
||||
<MakeDir Directories="$(_RefSourceOutputPath)" />
|
||||
<Message Importance="High" Text="Generating $(_RefSourceFileOutputPath)" />
|
||||
<Exec Command="$(_GenAPICmd)" />
|
||||
|
|
@ -96,4 +102,4 @@
|
|||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
"$(MicrosoftNETCoreAppRuntimeVersion)"
|
||||
]
|
||||
},
|
||||
"Git": "2.22.0",
|
||||
"jdk": "11.0.3",
|
||||
"vs": {
|
||||
"version": "16.0",
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ namespace Ignitor
|
|||
|
||||
public Task<CapturedRenderBatch> PrepareForNextBatch(TimeSpan? timeout)
|
||||
{
|
||||
if (NextBatchReceived?.Completion != null)
|
||||
if (NextBatchReceived != null && !NextBatchReceived.Disposed)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid state previous task not completed");
|
||||
}
|
||||
|
|
@ -100,7 +100,7 @@ namespace Ignitor
|
|||
|
||||
public Task<CapturedJSInteropCall> PrepareForNextJSInterop(TimeSpan? timeout)
|
||||
{
|
||||
if (NextJSInteropReceived?.Completion != null)
|
||||
if (NextJSInteropReceived != null && !NextJSInteropReceived.Disposed)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid state previous task not completed");
|
||||
}
|
||||
|
|
@ -112,7 +112,7 @@ namespace Ignitor
|
|||
|
||||
public Task<string> PrepareForNextDotNetInterop(TimeSpan? timeout)
|
||||
{
|
||||
if (NextDotNetInteropCompletionReceived?.Completion != null)
|
||||
if (NextDotNetInteropCompletionReceived != null && !NextDotNetInteropCompletionReceived.Disposed)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid state previous task not completed");
|
||||
}
|
||||
|
|
@ -124,7 +124,7 @@ namespace Ignitor
|
|||
|
||||
public Task<string> PrepareForNextCircuitError(TimeSpan? timeout)
|
||||
{
|
||||
if (NextErrorReceived?.Completion != null)
|
||||
if (NextErrorReceived != null && !NextErrorReceived.Disposed)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid state previous task not completed");
|
||||
}
|
||||
|
|
@ -136,7 +136,7 @@ namespace Ignitor
|
|||
|
||||
public Task<Exception> PrepareForNextDisconnect(TimeSpan? timeout)
|
||||
{
|
||||
if (NextDisconnect?.Completion != null)
|
||||
if (NextDisconnect != null && !NextDisconnect.Disposed)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid state previous task not completed");
|
||||
}
|
||||
|
|
@ -499,56 +499,6 @@ namespace Ignitor
|
|||
return element;
|
||||
}
|
||||
|
||||
private class CancellableOperation<TResult>
|
||||
{
|
||||
public CancellableOperation(TimeSpan? timeout)
|
||||
{
|
||||
Timeout = timeout;
|
||||
Initialize();
|
||||
}
|
||||
|
||||
public TimeSpan? Timeout { get; }
|
||||
|
||||
public TaskCompletionSource<TResult> Completion { get; set; }
|
||||
|
||||
public CancellationTokenSource Cancellation { get; set; }
|
||||
|
||||
public CancellationTokenRegistration CancellationRegistration { get; set; }
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
Completion = new TaskCompletionSource<TResult>(TaskContinuationOptions.RunContinuationsAsynchronously);
|
||||
Completion.Task.ContinueWith(
|
||||
(task, state) =>
|
||||
{
|
||||
var operation = (CancellableOperation<TResult>)state;
|
||||
operation.Dispose();
|
||||
},
|
||||
this,
|
||||
TaskContinuationOptions.ExecuteSynchronously); // We need to execute synchronously to clean-up before anything else continues
|
||||
if (Timeout != null && Timeout != System.Threading.Timeout.InfiniteTimeSpan && Timeout != TimeSpan.MaxValue)
|
||||
{
|
||||
Cancellation = new CancellationTokenSource(Timeout.Value);
|
||||
CancellationRegistration = Cancellation.Token.Register(
|
||||
(self) =>
|
||||
{
|
||||
var operation = (CancellableOperation<TResult>)self;
|
||||
operation.Completion.TrySetCanceled(operation.Cancellation.Token);
|
||||
operation.Cancellation.Dispose();
|
||||
operation.CancellationRegistration.Dispose();
|
||||
},
|
||||
this);
|
||||
}
|
||||
}
|
||||
|
||||
private void Dispose()
|
||||
{
|
||||
Completion = null;
|
||||
Cancellation.Dispose();
|
||||
CancellationRegistration.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private string[] ReadMarkers(string content)
|
||||
{
|
||||
content = content.Replace("\r\n", "").Replace("\n", "");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ignitor
|
||||
{
|
||||
internal class CancellableOperation<TResult>
|
||||
{
|
||||
public CancellableOperation(TimeSpan? timeout)
|
||||
{
|
||||
Timeout = timeout;
|
||||
|
||||
Completion = new TaskCompletionSource<TResult>(TaskContinuationOptions.RunContinuationsAsynchronously);
|
||||
Completion.Task.ContinueWith(
|
||||
(task, state) =>
|
||||
{
|
||||
var operation = (CancellableOperation<TResult>)state;
|
||||
operation.Dispose();
|
||||
},
|
||||
this,
|
||||
TaskContinuationOptions.ExecuteSynchronously); // We need to execute synchronously to clean-up before anything else continues
|
||||
|
||||
if (Timeout != null && Timeout != System.Threading.Timeout.InfiniteTimeSpan && Timeout != TimeSpan.MaxValue)
|
||||
{
|
||||
Cancellation = new CancellationTokenSource(Timeout.Value);
|
||||
CancellationRegistration = Cancellation.Token.Register(
|
||||
(self) =>
|
||||
{
|
||||
var operation = (CancellableOperation<TResult>)self;
|
||||
operation.Completion.TrySetCanceled(operation.Cancellation.Token);
|
||||
operation.Cancellation.Dispose();
|
||||
operation.CancellationRegistration.Dispose();
|
||||
},
|
||||
this);
|
||||
}
|
||||
}
|
||||
|
||||
public TimeSpan? Timeout { get; }
|
||||
|
||||
public TaskCompletionSource<TResult> Completion { get; }
|
||||
|
||||
public CancellationTokenSource Cancellation { get; }
|
||||
|
||||
public CancellationTokenRegistration CancellationRegistration { get; }
|
||||
|
||||
public bool Disposed { get; private set; }
|
||||
|
||||
private void Dispose()
|
||||
{
|
||||
if (Disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Disposed = true;
|
||||
Completion.TrySetCanceled(Cancellation.Token);
|
||||
Cancellation.Dispose();
|
||||
CancellationRegistration.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -171,14 +171,26 @@ This package is an internal implementation of the .NET Core SDK and is not meant
|
|||
Inputs="@(RefPackContent)"
|
||||
Outputs="$(ZipArchiveOutputPath);$(TarArchiveOutputPath)"
|
||||
Condition="'$(IsPackable)' == 'true'">
|
||||
<PropertyGroup>
|
||||
<_TarCommand>tar</_TarCommand>
|
||||
<_TarCommand Condition="Exists('$(RepoRoot).tools\tar.exe')">$(RepoRoot).tools\tar.exe</_TarCommand>
|
||||
|
||||
<!-- For the tar packed with git, transform e.g. "C:\root\AspNetCore\File.tar.gz" to "/C/root/AspNetCore/File.tar.gz". -->
|
||||
<_TarArchiveOutputPath>$(TarArchiveOutputPath)</_TarArchiveOutputPath>
|
||||
<_TarArchiveOutputPath
|
||||
Condition="Exists('$(repoRoot)\.tools\tar.fromGit')">/$(TarArchiveOutputPath.Replace('\','/').Replace(':',''))</_TarArchiveOutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ZipDirectory
|
||||
SourceDirectory="$(TargetingPackLayoutRoot)"
|
||||
DestinationFile="$(ZipArchiveOutputPath)"
|
||||
Overwrite="true" />
|
||||
|
||||
<!-- Requires Windows 10 version 1803 or newer -->
|
||||
<Exec
|
||||
Command="tar -czf $(TarArchiveOutputPath) ."
|
||||
WorkingDirectory="$(TargetingPackLayoutRoot)" />
|
||||
<Message Importance="High" Text="Executing: $(_TarCommand) -czf $(_TarArchiveOutputPath) ." />
|
||||
<Exec Command="$(_TarCommand) -czf $(_TarArchiveOutputPath) ."
|
||||
WorkingDirectory="$(TargetingPackLayoutRoot)" />
|
||||
|
||||
<Message Importance="High" Text="$(MSBuildProjectName) -> $(TarArchiveOutputPath)" />
|
||||
</Target>
|
||||
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ namespace Microsoft.AspNetCore.E2ETesting
|
|||
var instance = await SeleniumStandaloneServer.GetInstanceAsync(output);
|
||||
|
||||
var attempt = 0;
|
||||
var maxAttempts = 3;
|
||||
const int maxAttempts = 3;
|
||||
do
|
||||
{
|
||||
try
|
||||
|
|
@ -132,18 +132,16 @@ namespace Microsoft.AspNetCore.E2ETesting
|
|||
|
||||
return (driver, logs);
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (attempt >= maxAttempts)
|
||||
{
|
||||
throw new InvalidOperationException("Couldn't create a Selenium remote driver client. The server is irresponsive");
|
||||
}
|
||||
output.WriteLine($"Error initializing RemoteWebDriver: {ex.Message}");
|
||||
}
|
||||
|
||||
attempt++;
|
||||
|
||||
} while (attempt < maxAttempts);
|
||||
|
||||
// We will never get here. Keeping the compiler happy.
|
||||
throw new InvalidOperationException("Couldn't create a Selenium remote driver client. The server is unresponsive");
|
||||
throw new InvalidOperationException("Couldn't create a Selenium remote driver client. The server is irresponsive");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ namespace Microsoft.Extensions.ApiDescription.Client
|
|||
public void Execute_ReturnsExpectedItem()
|
||||
{
|
||||
// Arrange
|
||||
string input = "Identity=../files/azureMonitor.json|ClassName=azureMonitorClient|" +
|
||||
var input = "Identity=../files/azureMonitor.json|ClassName=azureMonitorClient|" +
|
||||
"CodeGenerator=NSwagCSharp|Namespace=ConsoleClient|Options=|OutputPath=" +
|
||||
"C:\\dd\\dnx\\AspNetCore\\artifacts\\obj\\ConsoleClient\\azureMonitorClient.cs|" +
|
||||
"OriginalItemSpec=../files/azureMonitor.json|FirstForGenerator=true";
|
||||
|
|
@ -22,8 +22,8 @@ namespace Microsoft.Extensions.ApiDescription.Client
|
|||
Input = input,
|
||||
};
|
||||
|
||||
string expectedIdentity = "../files/azureMonitor.json";
|
||||
IDictionary<string, string> expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
var expectedIdentity = "../files/azureMonitor.json";
|
||||
var expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
{ "ClassName", "azureMonitorClient" },
|
||||
{ "CodeGenerator", "NSwagCSharp" },
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ namespace Microsoft.Extensions.ApiDescription.Client
|
|||
OutputDirectory = "obj",
|
||||
};
|
||||
|
||||
IDictionary<string, string> expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
var expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
{ "ClassName", "NSwagClient" },
|
||||
{ "CodeGenerator", "NSwagCSharp" },
|
||||
|
|
@ -85,7 +85,7 @@ namespace Microsoft.Extensions.ApiDescription.Client
|
|||
OutputDirectory = "obj",
|
||||
};
|
||||
|
||||
IDictionary<string, string> expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
var expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
{ "ClassName", className },
|
||||
{ "CodeGenerator", "NSwagCSharp" },
|
||||
|
|
@ -143,7 +143,7 @@ namespace Microsoft.Extensions.ApiDescription.Client
|
|||
OutputDirectory = "obj",
|
||||
};
|
||||
|
||||
IDictionary<string, string> expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
var expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
{ "ClassName", "NSwagClient" },
|
||||
{ "CodeGenerator", "NSwagCSharp" },
|
||||
|
|
@ -201,7 +201,7 @@ namespace Microsoft.Extensions.ApiDescription.Client
|
|||
OutputDirectory = "bin",
|
||||
};
|
||||
|
||||
IDictionary<string, string> expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
var expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
{ "ClassName", className },
|
||||
{ "CodeGenerator", "NSwagCSharp" },
|
||||
|
|
@ -351,7 +351,7 @@ namespace Microsoft.Extensions.ApiDescription.Client
|
|||
OutputDirectory = "bin",
|
||||
};
|
||||
|
||||
IDictionary<string, string> expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
var expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
{ "ClassName", className },
|
||||
{ "CodeGenerator", "NSwagCSharp" },
|
||||
|
|
@ -414,7 +414,7 @@ namespace Microsoft.Extensions.ApiDescription.Client
|
|||
OutputDirectory = "bin",
|
||||
};
|
||||
|
||||
IDictionary<string, string> expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
var expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
{ "ClassName", className },
|
||||
{ "CodeGenerator", "NSwagCSharp" },
|
||||
|
|
@ -481,7 +481,7 @@ namespace Microsoft.Extensions.ApiDescription.Client
|
|||
OutputDirectory = "obj",
|
||||
};
|
||||
|
||||
IDictionary<string, string> expectedMetadata1 = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
var expectedMetadata1 = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
{ "ClassName", className12 },
|
||||
{ "CodeGenerator", codeGenerator13 },
|
||||
|
|
@ -496,7 +496,7 @@ namespace Microsoft.Extensions.ApiDescription.Client
|
|||
$"OutputPath={outputPath1}|ClassName={className12}|Namespace={@namespace}"
|
||||
},
|
||||
};
|
||||
IDictionary<string, string> expectedMetadata2 = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
var expectedMetadata2 = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
{ "ClassName", className12 },
|
||||
{ "CodeGenerator", codeGenerator2 },
|
||||
|
|
@ -511,7 +511,7 @@ namespace Microsoft.Extensions.ApiDescription.Client
|
|||
$"OutputPath={outputPath2}|ClassName={className12}|Namespace={@namespace}"
|
||||
},
|
||||
};
|
||||
IDictionary<string, string> expectedMetadata3 = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
var expectedMetadata3 = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
{ "ClassName", className3 },
|
||||
{ "CodeGenerator", codeGenerator13 },
|
||||
|
|
|
|||
|
|
@ -0,0 +1,314 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Extensions.ApiDescription.Client
|
||||
{
|
||||
// ItemSpec values always have '\\' converted to '/' on input when running on non-Windows. It is not possible to
|
||||
// retrieve the original (unconverted) item spec value. In other respects, item spec values are treated identically
|
||||
// to custom metadata values.
|
||||
//
|
||||
// ITaskItem members aka the implicitly-implemented methods and properties in TaskItem expect _escaped_ values on
|
||||
// input and return _literal_ values. This includes TaskItem constructors and CloneCustomMetadata() (which returns
|
||||
// a new dictionary containing literal values). TaskItem stores all values in their escaped form.
|
||||
//
|
||||
// Added ITaskItem2 members e.g. CloneCustomMetadataEscaped(), GetMetadataValueEscaped(...) and
|
||||
// EvaluatedIncludeEscaped return escaped values. Of all TaskItem methods, only SetMetadataValueLiteral(...)
|
||||
// accepts a literal input value.
|
||||
//
|
||||
// Metadata names are never escaped.
|
||||
//
|
||||
// MetadataSerializer expects literal values on input.
|
||||
public class MetadataSerializerTest
|
||||
{
|
||||
// Maps literal to escaped values.
|
||||
public static TheoryData<string, string> EscapedValuesMapping { get; } = new TheoryData<string, string>
|
||||
{
|
||||
{ "No escaping necessary for =.", "No escaping necessary for =." },
|
||||
{ "Value needs escaping? (yes)", "Value needs escaping%3f %28yes%29" },
|
||||
{ "$ comes earlier; @ comes later.", "%24 comes earlier%3b %40 comes later." },
|
||||
{
|
||||
"A '%' *character* needs escaping %-escaping.",
|
||||
"A %27%25%27 %2acharacter%2a needs escaping %25-escaping."
|
||||
},
|
||||
};
|
||||
|
||||
public static TheoryData<string> EscapedValues
|
||||
{
|
||||
get
|
||||
{
|
||||
var result = new TheoryData<string>();
|
||||
foreach (var entry in EscapedValuesMapping)
|
||||
{
|
||||
result.Add((string)entry[1]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static TheoryData<string> LiteralValues
|
||||
{
|
||||
get
|
||||
{
|
||||
var result = new TheoryData<string>();
|
||||
foreach (var entry in EscapedValuesMapping)
|
||||
{
|
||||
result.Add((string)entry[0]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(LiteralValues))]
|
||||
public void SetMetadata_UpdatesTaskAsExpected(string value)
|
||||
{
|
||||
// Arrange
|
||||
var item = new TaskItem("My Identity");
|
||||
var key = "My key";
|
||||
|
||||
// Act
|
||||
MetadataSerializer.SetMetadata(item, key, value);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(value, item.GetMetadata(key));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(EscapedValuesMapping))]
|
||||
public void SetMetadata_UpdatesTaskAsExpected_WithLegacyItem(string value, string escapedValue)
|
||||
{
|
||||
// Arrange
|
||||
var item = new Mock<ITaskItem>(MockBehavior.Strict);
|
||||
var key = "My key";
|
||||
item.Setup(i => i.SetMetadata(key, escapedValue)).Verifiable();
|
||||
|
||||
// Act
|
||||
MetadataSerializer.SetMetadata(item.Object, key, value);
|
||||
|
||||
// Assert
|
||||
item.Verify(i => i.SetMetadata(key, escapedValue), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DeserializeMetadata_ReturnsExpectedTask()
|
||||
{
|
||||
// Arrange
|
||||
var identity = "../files/azureMonitor.json";
|
||||
var input = $"Identity={identity}|ClassName=azureMonitorClient|" +
|
||||
"CodeGenerator=NSwagCSharp|FirstForGenerator=true|Namespace=ConsoleClient|" +
|
||||
"Options=|OriginalItemSpec=../files/azureMonitor.json|" +
|
||||
"OutputPath=C:\\dd\\dnx\\AspNetCore\\artifacts\\obj\\ConsoleClient\\azureMonitorClient.cs";
|
||||
|
||||
var expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
{ "ClassName", "azureMonitorClient" },
|
||||
{ "CodeGenerator", "NSwagCSharp" },
|
||||
{ "FirstForGenerator", "true" },
|
||||
{ "Namespace", "ConsoleClient" },
|
||||
{ "Options", "" },
|
||||
{ "OriginalItemSpec", identity },
|
||||
{ "OutputPath", "C:\\dd\\dnx\\AspNetCore\\artifacts\\obj\\ConsoleClient\\azureMonitorClient.cs" },
|
||||
};
|
||||
|
||||
// Act
|
||||
var item = MetadataSerializer.DeserializeMetadata(input);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(identity, item.ItemSpec);
|
||||
var metadata = Assert.IsAssignableFrom<IDictionary<string, string>>(item.CloneCustomMetadata());
|
||||
|
||||
// The dictionary CloneCustomMetadata returns doesn't provide a useful KeyValuePair enumerator.
|
||||
var orderedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal);
|
||||
foreach (var key in metadata.Keys)
|
||||
{
|
||||
orderedMetadata.Add(key, metadata[key]);
|
||||
}
|
||||
|
||||
Assert.Equal(expectedMetadata, orderedMetadata);
|
||||
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(EscapedValuesMapping))]
|
||||
public void DeserializeMetadata_ReturnsExpectedTask_WhenEscaping(string value, string escapedValue)
|
||||
{
|
||||
// Arrange
|
||||
var identity = "../files/azureMonitor.json";
|
||||
var input = $"Identity={identity}|Value={escapedValue}";
|
||||
|
||||
// Act
|
||||
var item = MetadataSerializer.DeserializeMetadata(input);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(identity, item.ItemSpec);
|
||||
Assert.Equal(value, item.GetMetadata("Value"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(EscapedValuesMapping))]
|
||||
public void DeserializeMetadata_ReturnsExpectedTask_WhenEscapingIdentity(string value, string escapedValue)
|
||||
{
|
||||
// Arrange
|
||||
var input = $"Identity={escapedValue}|Value=a value";
|
||||
|
||||
// Act
|
||||
var item = MetadataSerializer.DeserializeMetadata(input);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(value, item.ItemSpec);
|
||||
Assert.Equal("a value", item.GetMetadata("Value"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SerializeMetadata_ReturnsExpectedString()
|
||||
{
|
||||
// Arrange
|
||||
var identity = "../files/azureMonitor.json";
|
||||
var metadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
{ "ClassName", "azureMonitorClient" },
|
||||
{ "CodeGenerator", "NSwagCSharp" },
|
||||
{ "FirstForGenerator", "true" },
|
||||
{ "Namespace", "ConsoleClient" },
|
||||
{ "Options", "" },
|
||||
{ "OriginalItemSpec", identity },
|
||||
{ "OutputPath", "C:\\dd\\dnx\\AspNetCore\\artifacts\\obj\\ConsoleClient\\azureMonitorClient.cs" },
|
||||
};
|
||||
|
||||
var input = new TaskItem(identity, metadata);
|
||||
var expectedResult = $"Identity={identity}|ClassName=azureMonitorClient|" +
|
||||
"CodeGenerator=NSwagCSharp|FirstForGenerator=true|Namespace=ConsoleClient|" +
|
||||
"Options=|OriginalItemSpec=../files/azureMonitor.json|" +
|
||||
"OutputPath=C:\\dd\\dnx\\AspNetCore\\artifacts\\obj\\ConsoleClient\\azureMonitorClient.cs";
|
||||
|
||||
// Act
|
||||
var result = MetadataSerializer.SerializeMetadata(input);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedResult, result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(EscapedValues))]
|
||||
public void SerializeMetadata_ReturnsExpectedString_WhenEscaping(string escapedValue)
|
||||
{
|
||||
// Arrange
|
||||
var identity = "../files/azureMonitor.json";
|
||||
var expectedResult = $"Identity={identity}|Value={escapedValue}";
|
||||
var metadata = new SortedDictionary<string, string>(StringComparer.Ordinal) { { "Value", escapedValue } };
|
||||
var input = new TaskItem(identity, metadata);
|
||||
|
||||
// Act
|
||||
var result = MetadataSerializer.SerializeMetadata(input);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedResult, result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(EscapedValues))]
|
||||
public void SerializeMetadata_ReturnsExpectedString_WhenEscapingIdentity(string escapedValue)
|
||||
{
|
||||
// Arrange
|
||||
var metadata = new SortedDictionary<string, string>(StringComparer.Ordinal) { { "Value", "a value" } };
|
||||
var expectedResult = $"Identity={escapedValue}|Value=a value";
|
||||
var input = new TaskItem(escapedValue, metadata);
|
||||
|
||||
// Act
|
||||
var result = MetadataSerializer.SerializeMetadata(input);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedResult, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SerializeMetadata_ReturnsExpectedString_WithLegacyItem()
|
||||
{
|
||||
// Arrange
|
||||
var identity = "../files/azureMonitor.json";
|
||||
var metadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
{ "ClassName", "azureMonitorClient" },
|
||||
{ "CodeGenerator", "NSwagCSharp" },
|
||||
{ "FirstForGenerator", "true" },
|
||||
{ "Namespace", "ConsoleClient" },
|
||||
{ "Options", "" },
|
||||
{ "OriginalItemSpec", identity },
|
||||
{ "OutputPath", "C:\\dd\\dnx\\AspNetCore\\artifacts\\obj\\ConsoleClient\\azureMonitorClient.cs" },
|
||||
};
|
||||
|
||||
var input = new Mock<ITaskItem>(MockBehavior.Strict);
|
||||
input.SetupGet(i => i.ItemSpec).Returns(identity).Verifiable();
|
||||
input.Setup(i => i.CloneCustomMetadata()).Returns(metadata).Verifiable();
|
||||
|
||||
var expectedResult = $"Identity={identity}|ClassName=azureMonitorClient|" +
|
||||
"CodeGenerator=NSwagCSharp|FirstForGenerator=true|Namespace=ConsoleClient|" +
|
||||
"Options=|OriginalItemSpec=../files/azureMonitor.json|" +
|
||||
"OutputPath=C:\\dd\\dnx\\AspNetCore\\artifacts\\obj\\ConsoleClient\\azureMonitorClient.cs";
|
||||
|
||||
// Act
|
||||
var result = MetadataSerializer.SerializeMetadata(input.Object);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedResult, result);
|
||||
input.VerifyGet(i => i.ItemSpec, Times.Once);
|
||||
input.Verify(i => i.CloneCustomMetadata(), Times.Once);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(EscapedValuesMapping))]
|
||||
public void SerializeMetadata_ReturnsExpectedString_WithLegacyItem_WhenEscaping(
|
||||
string value,
|
||||
string escapedValue)
|
||||
{
|
||||
// Arrange
|
||||
var identity = "../files/azureMonitor.json";
|
||||
var metadata = new SortedDictionary<string, string>(StringComparer.Ordinal) { { "Value", value } };
|
||||
var input = new Mock<ITaskItem>(MockBehavior.Strict);
|
||||
input.SetupGet(i => i.ItemSpec).Returns(identity).Verifiable();
|
||||
input.Setup(i => i.CloneCustomMetadata()).Returns(metadata).Verifiable();
|
||||
|
||||
var expectedResult = $"Identity={identity}|Value={escapedValue}";
|
||||
|
||||
// Act
|
||||
var result = MetadataSerializer.SerializeMetadata(input.Object);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedResult, result);
|
||||
input.VerifyGet(i => i.ItemSpec, Times.Once);
|
||||
input.Verify(i => i.CloneCustomMetadata(), Times.Once);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(EscapedValuesMapping))]
|
||||
public void SerializeMetadata_ReturnsExpectedString_WithLegacyItem_WhenEscapingIdentity(
|
||||
string value,
|
||||
string escapedValue)
|
||||
{
|
||||
// Arrange
|
||||
var metadata = new SortedDictionary<string, string>(StringComparer.Ordinal) { { "Value", "a value" } };
|
||||
var input = new Mock<ITaskItem>(MockBehavior.Strict);
|
||||
input.SetupGet(i => i.ItemSpec).Returns(value).Verifiable();
|
||||
input.Setup(i => i.CloneCustomMetadata()).Returns(metadata).Verifiable();
|
||||
|
||||
var expectedResult = $"Identity={escapedValue}|Value=a value";
|
||||
|
||||
// Act
|
||||
var result = MetadataSerializer.SerializeMetadata(input.Object);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedResult, result);
|
||||
input.VerifyGet(i => i.ItemSpec, Times.Once);
|
||||
input.Verify(i => i.CloneCustomMetadata(), Times.Once);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,9 +6,12 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Build.Evaluation;
|
||||
using Microsoft.DotNet.Openapi.Tools;
|
||||
|
|
@ -240,13 +243,13 @@ namespace Microsoft.DotNet.OpenApi.Commands
|
|||
|
||||
internal async Task DownloadToFileAsync(string url, string destinationPath, bool overwrite)
|
||||
{
|
||||
using var response = await _httpClient.GetResponseAsync(url);
|
||||
using var response = await RetryRequest(() => _httpClient.GetResponseAsync(url));
|
||||
await WriteToFileAsync(await response.Stream, destinationPath, overwrite);
|
||||
}
|
||||
|
||||
internal async Task<string> DownloadGivenOption(string url, CommandOption fileOption)
|
||||
{
|
||||
using var response = await _httpClient.GetResponseAsync(url);
|
||||
using var response = await RetryRequest(() => _httpClient.GetResponseAsync(url));
|
||||
|
||||
if (response.IsSuccessCode())
|
||||
{
|
||||
|
|
@ -272,6 +275,56 @@ namespace Microsoft.DotNet.OpenApi.Commands
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retries every 1 sec for 60 times by default.
|
||||
/// </summary>
|
||||
/// <param name="retryBlock"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <param name="retryCount"></param>
|
||||
private static async Task<IHttpResponseMessageWrapper> RetryRequest(
|
||||
Func<Task<IHttpResponseMessageWrapper>> retryBlock,
|
||||
CancellationToken cancellationToken = default,
|
||||
int retryCount = 60)
|
||||
{
|
||||
for (var retry = 0; retry < retryCount; retry++)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
throw new OperationCanceledException("Failed to connect, retry canceled.", cancellationToken);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var response = await retryBlock().ConfigureAwait(false);
|
||||
|
||||
if (response.StatusCode == HttpStatusCode.ServiceUnavailable)
|
||||
{
|
||||
// Automatically retry on 503. May be application is still booting.
|
||||
continue;
|
||||
}
|
||||
|
||||
return response; // Went through successfully
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (retry == retryCount - 1)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (exception is HttpRequestException || exception is WebException)
|
||||
{
|
||||
await Task.Delay(1 * 1000); //Wait for a while before retry.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new OperationCanceledException("Failed to connect, retry limit exceeded.");
|
||||
}
|
||||
|
||||
private string GetUniqueFileName(string directory, string fileName, string extension)
|
||||
{
|
||||
var uniqueName = fileName;
|
||||
|
|
|
|||
|
|
@ -440,8 +440,8 @@ namespace Microsoft.DotNet.OpenApi.Add.Tests
|
|||
var url = BrokenUrl;
|
||||
var run = app.Execute(new[] { "add", "url", url });
|
||||
|
||||
Assert.Equal(_error.ToString(), $"The given url returned 'NotFound', " +
|
||||
"indicating failure. The url might be wrong, or there might be a networking issue."+Environment.NewLine);
|
||||
Assert.Equal($"The given url returned 'NotFound', " +
|
||||
"indicating failure. The url might be wrong, or there might be a networking issue."+Environment.NewLine, _error.ToString());
|
||||
Assert.Equal(1, run);
|
||||
|
||||
var expectedJsonName = "dingos.json";
|
||||
|
|
|
|||
Loading…
Reference in New Issue